Commit 39f4dbe2 authored by Matthieu Dorier's avatar Matthieu Dorier

separated linking to client and server libraries

parent 001374c0
......@@ -47,6 +47,8 @@ src_libiochain_la_SOURCES = src/io-chain/prepare-read-op.c \
src_libmobject_store_la_SOURCES = \
src/client/io-context.c \
src/aio/completion.c \
src/client/read-op.c \
src/client/write-op.c \
src/client/libmobject-store.c
src_libmobject_store_la_LIBADD = src/libomap-iter.la\
......
/*
* (C) 2017 The University of Chicago
*
* See COPYRIGHT in top-level directory.
*/
#include <stdlib.h>
#include <string.h>
#include "mobject-store-config.h"
#include "libmobject-store.h"
#include "src/io-chain/read-op-impl.h"
#include "src/util/utlist.h"
#include "src/util/log.h"
mobject_store_read_op_t mobject_store_create_read_op(void)
{
return create_read_op();
}
void mobject_store_release_read_op(mobject_store_read_op_t read_op)
{
release_read_op(read_op);
}
void mobject_store_read_op_stat(mobject_store_read_op_t read_op,
uint64_t *psize,
time_t *pmtime,
int *prval)
{
MOBJECT_ASSERT(read_op != MOBJECT_READ_OP_NULL, "invalid mobject_store_read_op_t obect");
MOBJECT_ASSERT(!(read_op->ready), "can't modify a read_op that is ready to be processed");
rd_action_stat_t action = (rd_action_stat_t)calloc(1, sizeof(*action));
action->base.type = READ_OPCODE_STAT;
action->psize = psize;
action->pmtime = pmtime;
action->prval = prval;
READ_ACTION_UPCAST(base, action);
DL_APPEND(read_op->actions, base);
read_op->num_actions += 1;
}
void mobject_store_read_op_read(mobject_store_read_op_t read_op,
uint64_t offset,
size_t len,
char *buffer,
size_t *bytes_read,
int *prval)
{
MOBJECT_ASSERT(read_op != MOBJECT_READ_OP_NULL, "invalid mobject_store_read_op_t obect");
MOBJECT_ASSERT(!(read_op->ready), "can't modify a read_op that is ready to be processed");
rd_action_read_t action = (rd_action_read_t)calloc(1, sizeof(*action));
action->base.type = READ_OPCODE_READ;
action->offset = offset;
action->len = len;
action->buffer.as_pointer = buffer;
action->bytes_read = bytes_read;
action->prval = prval;
READ_ACTION_UPCAST(base, action);
DL_APPEND(read_op->actions, base);
read_op->num_actions += 1;
}
void mobject_store_read_op_omap_get_keys(mobject_store_read_op_t read_op,
const char *start_after,
uint64_t max_return,
mobject_store_omap_iter_t *iter,
int *prval)
{
MOBJECT_ASSERT(read_op != MOBJECT_READ_OP_NULL, "invalid mobject_store_read_op_t obect");
MOBJECT_ASSERT(!(read_op->ready), "can't modify a read_op that is ready to be processed");
size_t strl = strlen(start_after);
rd_action_omap_get_keys_t action = (rd_action_omap_get_keys_t)calloc(1, sizeof(*action)+strl);
action->base.type = READ_OPCODE_OMAP_GET_KEYS;
action->start_after = action->data;
action->max_return = max_return;
action->iter = iter;
action->prval = prval;
action->data_size = strl+1;
strcpy(action->data, start_after);
READ_ACTION_UPCAST(base, action);
DL_APPEND(read_op->actions, base);
read_op->num_actions += 1;
}
void mobject_store_read_op_omap_get_vals(mobject_store_read_op_t read_op,
const char *start_after,
const char *filter_prefix,
uint64_t max_return,
mobject_store_omap_iter_t *iter,
int *prval)
{
MOBJECT_ASSERT(read_op != MOBJECT_READ_OP_NULL, "invalid mobject_store_read_op_t obect");
MOBJECT_ASSERT(!(read_op->ready), "can't modify a read_op that is ready to be processed");
// compute required size for embedded data
size_t strl1 = strlen(start_after)+1;
size_t strl2 = strlen(filter_prefix)+1;
size_t extra_mem = strl1+strl2;
rd_action_omap_get_vals_t action = (rd_action_omap_get_vals_t)calloc(1, sizeof(*action)-1+extra_mem);
action->base.type = READ_OPCODE_OMAP_GET_VALS;
action->start_after = action->data;
action->filter_prefix = action->data + strl1;
action->max_return = max_return;
action->iter = iter;
action->prval = prval;
action->data_size = extra_mem;
strcpy(action->data, start_after);
strcpy(action->data + strl1, filter_prefix);
READ_ACTION_UPCAST(base, action);
DL_APPEND(read_op->actions, base);
read_op->num_actions += 1;
}
void mobject_store_read_op_omap_get_vals_by_keys(mobject_store_read_op_t read_op,
char const* const* keys,
size_t keys_len,
mobject_store_omap_iter_t *iter,
int *prval)
{
MOBJECT_ASSERT(read_op != MOBJECT_READ_OP_NULL, "invalid mobject_store_read_op_t obect");
MOBJECT_ASSERT(!(read_op->ready), "can't modify a read_op that is ready to be processed");
// computing extra memory required to hold keys
size_t extra_mem = 0;
size_t i;
for(i = 0; i < keys_len; i++) {
extra_mem += strlen(keys[i]) + 1;
}
rd_action_omap_get_vals_by_keys_t action =
(rd_action_omap_get_vals_by_keys_t)calloc(1, sizeof(*action) - 1 + extra_mem);
action->base.type = READ_OPCODE_OMAP_GET_VALS_BY_KEYS;
action->num_keys = keys_len;
action->iter = iter;
action->prval = prval;
action->data_size = extra_mem;
char* s = action->data;
for(i = 0; i < keys_len; i++) {
strcpy(s, keys[i]);
s += strlen(keys[i]) + 1;
}
READ_ACTION_UPCAST(base, action);
DL_APPEND(read_op->actions, base);
read_op->num_actions += 1;
}
/*
typedef struct read_op_ult_args {
mobject_store_read_op_t read_op;
mobject_store_ioctx_t ioctx;
mobject_store_completion_t completion
char* oid;
int flags;
} read_op_ult_args;
static void aio_read_op_operate_ult(read_op_ult_args* args) {
read_op_in_t in;
in.object_name = args->oid;
in.pool_name = args->ioctx->pool_name;
in.read_op = args->read_op;
prepare_read_op(io->mid, read_op);
// TODO: svr_addr should be computed based on the pool name, object name,
// and SSG structures accessible via the io context
hg_handle_t h;
margo_create(io->mid, io->svr_addr, mobject_read_op_rpc_id, &h);
margo_forward(h, &in);
read_op_out_t resp;
margo_get_output(h, &resp);
feed_read_op_pointers_from_response(read_op, resp.responses);
margo_free_output(h,&resp);
margo_destroy(h);
free(args->oid);
ABT_rwlock_wrlock(args->completion->lock);
int ret = 0; // TODO change that depending on results of the read_op
ABT_eventual_set (args->completion->eventual, &ret, sizeof(int));
mobject_store_callback_t cb_complete = args->completion->cb_complete;
void* cb_arg = args->completion->cb_arg;
ABT_rwlock_unlock(args->completion->lock);
if(complete_cb)
complete_cb(args->completion, cb_arg);
free(args);
return 0;
}
*/
int mobject_store_aio_read_op_operate(mobject_store_read_op_t read_op,
mobject_store_ioctx_t io,
mobject_store_completion_t completion,
const char *oid,
int flags)
{
/* MOBJECT_ASSERT(read_op != MOBJECT_READ_OP_NULL, "invalid mobject_store_read_op_t object");
// TODO this is not great, we should use the margo non-blocking API instead
ABT_xstream self_es;
ABT_xstream_self(&self_es);
ABT_pool pool;
ABT_xstream_get_main_pools(self_es, 1, &pool);
ABT_thread ult;
read_op_ult_args* args = (read_op_ult_args*)calloc(1, sizeof(*args);
args->read_op = read_op;
args->ioctx = io;
args->completion = completion;
args->oid = strdup(oid);
args->flags = flags;
ABT_thread_create(pool, aio_read_op_operate_ult, args, ABT_THREAD_ATTR_NULL, &ult);
completion->ult = ult;
*/
}
/*
* (C) 2017 The University of Chicago
*
* See COPYRIGHT in top-level directory.
*/
#include <stdlib.h>
#include <string.h>
#include "mobject-store-config.h"
#include "libmobject-store.h"
#include "src/io-chain/write-op-impl.h"
#include "src/aio/completion.h"
#include "src/util/utlist.h"
#include "src/util/log.h"
mobject_store_write_op_t mobject_store_create_write_op(void)
{
return create_write_op();
}
void mobject_store_release_write_op(mobject_store_write_op_t write_op)
{
release_write_op(write_op);
}
void mobject_store_write_op_create(mobject_store_write_op_t write_op,
int exclusive,
const char* category)
{
MOBJECT_ASSERT(write_op != MOBJECT_WRITE_OP_NULL, "invalid mobject_store_write_op_t obect");
MOBJECT_ASSERT(!(write_op->ready), "can't modify a write_op that is ready to be processed");
wr_action_create_t action = (wr_action_create_t)calloc(1, sizeof(*action));
action->base.type = WRITE_OPCODE_CREATE;
action->exclusive = exclusive;
WRITE_ACTION_UPCAST(base, action);
DL_APPEND(write_op->actions, base);
write_op->num_actions += 1;
}
void mobject_store_write_op_write(mobject_store_write_op_t write_op,
const char *buffer,
size_t len,
uint64_t offset)
{
MOBJECT_ASSERT(write_op != MOBJECT_WRITE_OP_NULL, "invalid mobject_store_write_op_t obect");
MOBJECT_ASSERT(!(write_op->ready), "can't modify a write_op that is ready to be processed");
wr_action_write_t action = (wr_action_write_t)calloc(1, sizeof(*action));
action->base.type = WRITE_OPCODE_WRITE;
action->buffer.as_pointer = buffer;
action->len = len;
action->offset = offset;
WRITE_ACTION_UPCAST(base, action);
DL_APPEND(write_op->actions, base);
write_op->num_actions += 1;
}
void mobject_store_write_op_write_full(mobject_store_write_op_t write_op,
const char *buffer,
size_t len)
{
MOBJECT_ASSERT(write_op != MOBJECT_WRITE_OP_NULL, "invalid mobject_store_write_op_t obect");
MOBJECT_ASSERT(!(write_op->ready), "can't modify a write_op that is ready to be processed");
wr_action_write_full_t action = (wr_action_write_full_t)calloc(1, sizeof(*action));
action->base.type = WRITE_OPCODE_WRITE_FULL;
action->buffer.as_pointer = buffer;
action->len = len;
/* POTENTIAL OPTIMIZATION (INCOMPLETE)
// a write_full will replace the entire content of the object
// so we can try and optimize by removing some operations that will
// be overwritten anyway
wr_action_base_t current, temp;
DL_FOREACH_SAFE(write_op->actions, current, temp) {
if(current->type == WRITE_OPCODE_WRITE
|| current->type == WRITE_OPCODE_WRITE_FULL
|| current->type == WRITE_OPCODE_WRITE_SAME
|| current->type == WRITE_OPCODE_APPEND
|| current->type == WRITE_OPCODE_TRUNCATE
|| current->type == WRITE_OPCODE_ZERO) {
DL_DELETE(write_op->actions, current);
free(current);
}
}
*/
WRITE_ACTION_UPCAST(base, action);
DL_APPEND(write_op->actions, base);
write_op->num_actions += 1;
}
void mobject_store_write_op_writesame(mobject_store_write_op_t write_op,
const char *buffer,
size_t data_len,
size_t write_len,
uint64_t offset)
{
MOBJECT_ASSERT(write_op != MOBJECT_WRITE_OP_NULL, "invalid mobject_store_write_op_t obect");
MOBJECT_ASSERT(!(write_op->ready), "can't modify a write_op that is ready to be processed");
wr_action_write_same_t action = (wr_action_write_same_t)calloc(1, sizeof(*action));
action->base.type = WRITE_OPCODE_WRITE_SAME;
action->buffer.as_pointer = buffer;
action->data_len = data_len;
action->write_len = write_len;
action->offset = offset;
WRITE_ACTION_UPCAST(base, action);
DL_APPEND(write_op->actions, base);
write_op->num_actions += 1;
}
void mobject_store_write_op_append(mobject_store_write_op_t write_op,
const char *buffer,
size_t len)
{
MOBJECT_ASSERT(write_op != MOBJECT_WRITE_OP_NULL, "invalid mobject_store_write_op_t obect");
MOBJECT_ASSERT(!(write_op->ready), "can't modify a write_op that is ready to be processed");
wr_action_append_t action = (wr_action_append_t)calloc(1, sizeof(*action));
action->base.type = WRITE_OPCODE_APPEND;
action->buffer.as_pointer = buffer;
action->len = len;
WRITE_ACTION_UPCAST(base, action);
DL_APPEND(write_op->actions, base);
write_op->num_actions += 1;
}
void mobject_store_write_op_remove(mobject_store_write_op_t write_op)
{
MOBJECT_ASSERT(write_op != MOBJECT_WRITE_OP_NULL, "invalid mobject_store_write_op_t obect");
MOBJECT_ASSERT(!(write_op->ready), "can't modify a write_op that is ready to be processed");
wr_action_remove_t action = (wr_action_remove_t)calloc(1, sizeof(*action));
action->base.type = WRITE_OPCODE_REMOVE;
/* THE FOLLOWING IS A POTENTIAL (INCOMPLETE) OPTIMIZATION
// a remove operation will make all previous operations unecessary
// so we can delete all previously posted operations (and potentially
// not even post the remove)
wr_action_base_t current, temp;
int do_not_even_post = 0;
DL_FOREACH_SAFE(write_op->actions, current, temp) {
if(current->type == WRITE_OPCODE_CREATE)
do_not_even_post = 1;
DL_DELETE(write_op->actions, current);
free(current);
}
if(!do_not_even_post) {
WRITE_ACTION_UPCAST(base, action);
DL_APPEND(write_op->actions, base);
}
*/
WRITE_ACTION_UPCAST(base, action);
DL_APPEND(write_op->actions, base);
write_op->num_actions += 1;
}
void mobject_store_write_op_truncate(mobject_store_write_op_t write_op,
uint64_t offset)
{
MOBJECT_ASSERT(write_op != MOBJECT_WRITE_OP_NULL, "invalid mobject_store_write_op_t obect");
MOBJECT_ASSERT(!(write_op->ready), "can't modify a write_op that is ready to be processed");
wr_action_truncate_t action = (wr_action_truncate_t)calloc(1, sizeof(*action));
action->base.type = WRITE_OPCODE_TRUNCATE;
action->offset = offset;
WRITE_ACTION_UPCAST(base, action);
DL_APPEND(write_op->actions, base);
write_op->num_actions += 1;
}
void mobject_store_write_op_zero(mobject_store_write_op_t write_op,
uint64_t offset,
uint64_t len)
{
MOBJECT_ASSERT(write_op != MOBJECT_WRITE_OP_NULL, "invalid mobject_store_write_op_t obect");
MOBJECT_ASSERT(!(write_op->ready), "can't modify a write_op that is ready to be processed");
wr_action_zero_t action = (wr_action_zero_t)calloc(1, sizeof(*action));
action->base.type = WRITE_OPCODE_ZERO;
action->offset = offset;
action->len = len;
WRITE_ACTION_UPCAST(base, action);
DL_APPEND(write_op->actions, base);
write_op->num_actions += 1;
}
void mobject_store_write_op_omap_set(mobject_store_write_op_t write_op,
char const* const* keys,
char const* const* vals,
const size_t *lens,
size_t num)
{
MOBJECT_ASSERT(write_op != MOBJECT_WRITE_OP_NULL, "invalid mobject_store_write_op_t obect");
MOBJECT_ASSERT(!(write_op->ready), "can't modify a write_op that is ready to be processed");
// compute the size required to embed the keys and values
size_t i;
size_t extra_size = sizeof(lens[0])*num;
for(i = 0; i < num; i++) {
extra_size += strlen(keys[i])+1;
extra_size += lens[i];
}
wr_action_omap_set_t action = (wr_action_omap_set_t)calloc(1, sizeof(*action)-1+extra_size);
action->base.type = WRITE_OPCODE_OMAP_SET;
action->num = num;
action->data_size = extra_size;
char* data = action->data;
for(i = 0; i < num; i++) {
// serialize key
strcpy(data, keys[i]);
data += strlen(keys[i])+1;
// serialize size of value
memcpy(data, &lens[i], sizeof(lens[i]));
data += sizeof(lens[i]);
// serialize value
memcpy(data, vals[i], lens[i]);
data += lens[i];
}
WRITE_ACTION_UPCAST(base, action);
DL_APPEND(write_op->actions, base);
write_op->num_actions += 1;
}
void mobject_store_write_op_omap_rm_keys(mobject_store_write_op_t write_op,
char const* const* keys,
size_t keys_len)
{
MOBJECT_ASSERT(write_op != MOBJECT_WRITE_OP_NULL, "invalid mobject_store_write_op_t obect");
MOBJECT_ASSERT(!(write_op->ready), "can't modify a write_op that is ready to be processed");
// find out the extra memory to allocate
size_t i;
size_t extra_mem = 0;
for(i = 0; i < keys_len; i++) {
extra_mem += strlen(keys[i])+1;
}
wr_action_omap_rm_keys_t action = (wr_action_omap_rm_keys_t)calloc(1, sizeof(*action)-1+extra_mem);
action->base.type = WRITE_OPCODE_OMAP_RM_KEYS;
action->num_keys = keys_len;
action->data_size = extra_mem;
char* data = action->data;
// serialize the keys
for(i = 0; i < keys_len; i++) {
strcpy(data, keys[i]);
data += strlen(keys[i])+1;
}
WRITE_ACTION_UPCAST(base, action);
DL_APPEND(write_op->actions, base);
write_op->num_actions += 1;
}
/*
int mobject_store_write_op_operate(mobject_store_write_op_t write_op,
mobject_store_ioctx_t io,
const char *oid,
time_t *mtime,
int flags)
{
int r;
MOBJECT_ASSERT(write_op != MOBJECT_WRITE_OP_NULL, "invalid mobject_store_write_op_t obect");
mobject_store_completion_t completion = MOBJECT_COMPLETION_NULL;
r = mobject_store_aio_create_completion(NULL, NULL, NULL, &completion);
MOBJECT_ASSERT(0 == r, "Could not create completion object");
r = mobject_store_aio_write_op_operate(write_op, io, completion, oid, mtime, flags);
MOBJECT_ASSERT(0 == r, "Call to mobject_store_aio_write_op_operate failed");
r = mobject_store_aio_wait_for_complete(completion);
MOBJECT_ASSERT(0 == r, "Could not wait for completion");
int ret = mobject_store_aio_get_return_value(completion);
mobject_store_aio_release(completion);
return ret;
}
int mobject_store_aio_write_op_operate(mobject_store_write_op_t write_op,
mobject_store_ioctx_t io,
mobject_store_completion_t completion,
const char *oid,
time_t *mtime,
int flags)
{
MOBJECT_ASSERT(write_op != MOBJECT_WRITE_OP_NULL, "invalid mobject_store_write_op_t obect");
// TODO
}
*/
......@@ -126,7 +126,7 @@ hg_return_t hg_proc_mobject_store_read_op_t(hg_proc_t proc, mobject_store_read_o
case HG_DECODE:
*read_op = mobject_store_create_read_op();
*read_op = create_read_op();
(*read_op)->ready = 1;
// decode the bulk handle
ret = hg_proc_hg_bulk_t(proc, &((*read_op)->bulk_handle));
......@@ -156,7 +156,7 @@ hg_return_t hg_proc_mobject_store_read_op_t(hg_proc_t proc, mobject_store_read_o
case HG_FREE:
mobject_store_release_read_op(*read_op);
release_read_op(*read_op);
return HG_SUCCESS;
}
......
......@@ -176,7 +176,7 @@ hg_return_t hg_proc_mobject_store_write_op_t(hg_proc_t proc, mobject_store_write
case HG_DECODE:
*write_op = mobject_store_create_write_op();
*write_op = create_write_op();
(*write_op)->ready = 1;
// decode the bulk handle
......@@ -206,7 +206,7 @@ hg_return_t hg_proc_mobject_store_write_op_t(hg_proc_t proc, mobject_store_write
break;
case HG_FREE:
mobject_store_release_write_op(*write_op);
release_write_op(*write_op);
return HG_SUCCESS;
}
......
......@@ -12,7 +12,7 @@
#include "src/util/utlist.h"
#include "src/util/log.h"
mobject_store_read_op_t mobject_store_create_read_op(void)
mobject_store_read_op_t create_read_op(void)
{
mobject_store_read_op_t read_op =
(mobject_store_read_op_t)calloc(1, sizeof(*read_op));
......@@ -23,7 +23,7 @@ mobject_store_read_op_t mobject_store_create_read_op(void)
return read_op;
}
void mobject_store_release_read_op(mobject_store_read_op_t read_op)
void release_read_op(mobject_store_read_op_t read_op)
{
if(read_op == MOBJECT_READ_OP_NULL) return;
......@@ -36,213 +36,3 @@ void mobject_store_release_read_op(mobject_store_read_op_t read_op)
free(read_op);
}
void mobject_store_read_op_stat(mobject_store_read_op_t read_op,
uint64_t *psize,
time_t *pmtime,
int *prval)
{
MOBJECT_ASSERT(read_op != MOBJECT_READ_OP_NULL, "invalid mobject_store_read_op_t obect");
MOBJECT_ASSERT(!(read_op->ready), "can't modify a read_op that is ready to be processed");
rd_action_stat_t action = (rd_action_stat_t)calloc(1, sizeof(*action));
action->base.type = READ_OPCODE_STAT;
action->psize = psize;
action->pmtime = pmtime;
action->prval = prval;
READ_ACTION_UPCAST(base, action);
DL_APPEND(read_op->actions, base);
read_op->num_actions += 1;
}
void mobject_store_read_op_read(mobject_store_read_op_t read_op,
uint64_t offset,
size_t len,
char *buffer,
size_t *bytes_read,
int *prval)
{
MOBJECT_ASSERT(read_op != MOBJECT_READ_OP_NULL, "invalid mobject_store_read_op_t obect");
MOBJECT_ASSERT(!(read_op->ready), "can't modify a read_op that is ready to be processed");
rd_action_read_t action = (rd_action_read_t)calloc(1, sizeof(*action));
action->base.type = READ_OPCODE_READ;
action->offset = offset;
action->len = len;
action->buffer.as_pointer = buffer;
action->bytes_read = bytes_read;
action->prval = prval;
READ_ACTION_UPCAST(base, action);
DL_APPEND(read_op->actions, base);
read_op->num_actions += 1;
}
void mobject_store_read_op_omap_get_keys(mobject_store_read_op_t read_op,
const char *start_after,
uint64_t max_return,
mobject_store_omap_iter_t *iter,
int *prval)
{
MOBJECT_ASSERT(read_op != MOBJECT_READ_OP_NULL, "invalid mobject_store_read_op_t obect");
MOBJECT_ASSERT(!(read_op->ready), "can't modify a read_op that is ready to be processed");
size_t strl = strlen(start_after);
rd_action_omap_get_keys_t action = (rd_action_omap_get_keys_t)calloc(1, sizeof(*action)+strl);
action->base.type = READ_OPCODE_OMAP_GET_KEYS;
action->start_after = action->data;
action->max_return = max_return;
action->iter = iter;
action->prval = prval;
action->data_size = strl+1;
strcpy(action->data, start_after);
READ_ACTION_UPCAST(base, action);
DL_APPEND(read_op->actions, base);
read_op->num_actions += 1;
}
void mobject_store_read_op_omap_get_vals(mobject_store_read_op_t read_op,
const char *start_after,
const char *filter_prefix,
uint64_t max_return,
mobject_store_omap_iter_t *iter,
int *prval)
{
MOBJECT_ASSERT(read_op != MOBJECT_READ_OP_NULL, "invalid mobject_store_read_op_t obect");
MOBJECT_ASSERT(!(read_op->ready), "can't modify a read_op that is ready to be processed");
// compute required size for embedded data
size_t strl1 = strlen(start_after)+1;
size_t strl2 = strlen(filter_prefix)+1;
size_t extra_mem = strl1+strl2;
rd_action_omap_get_vals_t action = (rd_action_omap_get_vals_t)calloc(1, sizeof(*action)-1+extra_mem);
action->base.type = READ_OPCODE_OMAP_GET_VALS;
action->start_after = action->data;
action->filter_prefix = action->data + strl1;
action->max_return = max_return;
action->iter = iter;
action->prval = prval;
action->data_size = extra_mem;
strcpy(action->data, start_after);
strcpy(action->data + strl1, filter_prefix);
READ_ACTION_UPCAST(base, action);
DL_APPEND(read_op->actions, base);
read_op->num_actions += 1;
}
void mobject_store_read_op_omap_get_vals_by_keys(mobject_store_read_op_t read_op,
char const* const* keys,
size_t keys_len,
mobject_store_omap_iter_t *iter,
int *prval)
{
MOBJECT_ASSERT(read_op != MOBJECT_READ_OP_NULL, "invalid mobject_store_read_op_t obect");
MOBJECT_ASSERT(!(read_op->ready), "can't modify a read_op that is ready to be processed");
// computing extra memory required to hold keys
size_t extra_mem = 0;
size_t i;
for(i = 0; i < keys_len; i++) {
extra_mem += strlen(keys[i]) + 1;
}
rd_action_omap_get_vals_by_keys_t action =
(rd_action_omap_get_vals_by_keys_t)calloc(1, sizeof(*action) - 1 + extra_mem);
action->base.type = READ_OPCODE_OMAP_GET_VALS_BY_KEYS;
action->num_keys = keys_len;
action->iter = iter;
action->prval = prval;
action->data_size = extra_mem;
char* s = action->data;