コード例 #1
0
ファイル: _shim.c プロジェクト: BlueCava/aerospike-client-c
void asval_to_clobject(as_val * val, cl_object * obj)
{
	switch(val->type) {
		case AS_NIL: {
			citrusleaf_object_init_null(obj);
			break;
		}
		case AS_INTEGER: {
			as_integer * v = as_integer_fromval(val);
			citrusleaf_object_init_int(obj, as_integer_toint(v));
			break;
		}
		case AS_STRING: {
			as_string * v = as_string_fromval(val);
			citrusleaf_object_init_str(obj, as_string_get(v));
			break;
		}
		case AS_BYTES: {
			as_bytes * v = as_bytes_fromval(val);
			citrusleaf_object_init_blob2(obj, v->value, v->size, (cl_type)v->type);
			break;
		}
		case AS_LIST:{
			as_buffer buffer;
			as_buffer_init(&buffer);

			as_serializer ser;
			as_msgpack_init(&ser);
			as_serializer_serialize(&ser, val, &buffer);
			as_serializer_destroy(&ser);
			
			citrusleaf_object_init_blob_handoff(obj, buffer.data, buffer.size, CL_LIST);
			break;
		}
		case AS_MAP: {
			as_buffer buffer;
			as_buffer_init(&buffer);

			as_serializer ser;
			as_msgpack_init(&ser);
			as_serializer_serialize(&ser, val, &buffer);
			as_serializer_destroy(&ser);

			citrusleaf_object_init_blob_handoff(obj, buffer.data, buffer.size, CL_MAP);
			break;
		}
		default: {
			// raise an error
			break;
		}
	}
}
コード例 #2
0
size_t
as_command_value_size(as_val* val, as_buffer* buffer)
{
    switch (val->type) {
    case AS_NIL: {
        return 0;
    }
    case AS_INTEGER: {
        return 8;
    }
    case AS_STRING: {
        as_string* v = as_string_fromval(val);
        return as_string_len(v);
    }
    case AS_BYTES: {
        as_bytes* v = as_bytes_fromval(val);
        return v->size;
    }
    case AS_LIST:
    case AS_MAP: {
        as_serializer ser;
        as_msgpack_init(&ser);
        as_serializer_serialize(&ser, val, buffer);
        as_serializer_destroy(&ser);
        return buffer->size;
    }
    default: {
        return 0;
    }
    }
}
コード例 #3
0
static size_t
as_scan_command_size(const as_scan* scan, uint16_t* fields, as_buffer* argbuffer)
{
	// Build Command.  It's okay to share command across threads because scan does not have retries.
	// If retries were allowed, the timeout field in the command would change on retry which
	// would conflict with other threads.
	size_t size = AS_HEADER_SIZE;
	uint16_t n_fields = 0;
	
	if (scan->ns) {
		size += as_command_string_field_size(scan->ns);
		n_fields++;
	}
	
	if (scan->set) {
		size += as_command_string_field_size(scan->set);
		n_fields++;
	}
	
	// Estimate scan options size.
	size += as_command_field_size(2);
	n_fields++;
	
	// Estimate taskId size.
	size += as_command_field_size(8);
	n_fields++;
	
	// Estimate background function size.
	as_buffer_init(argbuffer);
	
	if (scan->apply_each.function[0]) {
		size += as_command_field_size(1);
		size += as_command_string_field_size(scan->apply_each.module);
		size += as_command_string_field_size(scan->apply_each.function);
		
		if (scan->apply_each.arglist) {
			// If the query has a udf w/ arglist, then serialize it.
			as_serializer ser;
			as_msgpack_init(&ser);
            as_serializer_serialize(&ser, (as_val*)scan->apply_each.arglist, argbuffer);
			as_serializer_destroy(&ser);
		}
		size += as_command_field_size(argbuffer->size);
		n_fields += 4;
	}
	
	// Estimate size for selected bin names.
	if (scan->select.size > 0) {
		for (uint16_t i = 0; i < scan->select.size; i++) {
			size += as_command_string_operation_size(scan->select.entries[i]);
		}
	}
	*fields = n_fields;
	return size;
}
コード例 #4
0
uint32_t
map_size_from_asval(const as_val *val)
{
	as_serializer s;
	as_msgpack_init(&s);

	uint32_t size = as_serializer_serialize_getsize(&s, (as_val *)val);

	as_serializer_destroy(&s);

	return (uint32_t)sizeof(map_mem) + size;
}
コード例 #5
0
uint32_t
map_asval_wire_size(const as_val *val)
{
	as_serializer s;
	as_msgpack_init(&s);

	uint32_t size = as_serializer_serialize_getsize(&s, (as_val *)val);

	as_serializer_destroy(&s);

	return size;
}
コード例 #6
0
uint32_t
map_asval_to_wire(const as_val *val, uint8_t *wire)
{
	as_serializer s;
	as_msgpack_init(&s);

	uint32_t size = as_serializer_serialize_presized(&s, val, wire);

	as_serializer_destroy(&s);

	return size;
}
コード例 #7
0
static int mod_lua_map_nbytes(lua_State * l) {
	as_map *    map     = mod_lua_checkmap(l, 1);
	uint32_t    nbytes  = 0;
	if ( map ) {
		as_serializer s;
		as_msgpack_init(&s);
		nbytes = as_serializer_serialize_getsize(&s, (as_val *) map);
		as_serializer_destroy(&s);
	}
	lua_pushinteger(l, nbytes);
	return 1;
}
コード例 #8
0
/**
 * Get a value for a bin of with the given key.
 */
static as_val * scan_response_get(const as_rec * rec, const char * name)  {
    as_val * v = NULL;
    as_serializer ser;
    as_msgpack_init(&ser);
    cl_scan_response_rec * r = (cl_scan_response_rec *) rec;
    for (int i = 0; i < r->n_bins; i++) {
        if (!strcmp(r->bins[i].bin_name, name)) {
            v = citrusleaf_udf_bin_to_val(&ser, &r->bins[i]);
            break;
        }
    }
    as_serializer_destroy(&ser);
    return v;
}
コード例 #9
0
// Creates a message, internally calling cl_compile to pass to the server
static int scan_compile(const cl_scan * scan, uint8_t ** buf_r, size_t * buf_sz_r) {

    if (!scan) return CITRUSLEAF_FAIL_CLIENT;

    //  Prepare udf call to send to the server
    as_call call;
    as_serializer ser;
    as_buffer argbuffer;
    as_buffer_init(&argbuffer);

    if ( scan->udf.type != CL_SCAN_UDF_NONE) {
        as_string file;
        as_string_init(&file, (char *) scan->udf.filename, true /*ismalloc*/);

        as_string func;
        as_string_init(&func, (char *) scan->udf.function, true /*ismalloc*/);

        if (scan->udf.arglist != NULL) {
            /**
             * If the query has a udf w/ arglist,
             * then serialize it.
             */
            as_msgpack_init(&ser);
            as_serializer_serialize(&ser, (as_val *) scan->udf.arglist, &argbuffer);
        }
        call.file = &file;
        call.func = &func;
        call.args = &argbuffer;
    }

    // Prepare to send scan parameters
    cl_scan_param_field     scan_param_field;
    cl_scan_params params = scan->params;
    scan_param_field.scan_pct = params.pct > 100 ? 100 : params.pct;
    scan_param_field.byte1 = (params.priority << 4)  | (params.fail_on_cluster_change << 3);

    // Prepare the msg type to be sent
    uint info;
    info = CL_MSG_INFO1_READ;

    // Pass on to the cl_compile to create the msg
    cl_compile(info /*info1*/, 0, 0, scan->ns /*namespace*/, scan->setname /*setname*/, 0 /*key*/, 0/*digest*/, NULL /*bins*/, 0/*op*/, 0/*operations*/, 0/*n_values*/, buf_r, buf_sz_r, 0 /*w_p*/, NULL /*d_ret*/, scan->job_id, &scan_param_field, scan->udf.type != CL_SCAN_UDF_NONE ? &call : NULL/*udf call*/, scan->udf.type);

    if (scan->udf.arglist) {
        as_serializer_destroy(&ser);
    }
    as_buffer_destroy(&argbuffer);
    return CITRUSLEAF_OK;
}
コード例 #10
0
void
map_from_asval(const as_val *val, as_particle **pp)
{
	map_mem *p_map_mem = (map_mem *)*pp;

	as_serializer s;
	as_msgpack_init(&s);

	uint32_t size = as_serializer_serialize_presized(&s, val, p_map_mem->data);

	p_map_mem->type = AS_PARTICLE_TYPE_MAP;
	p_map_mem->sz = size;

	as_serializer_destroy(&s);
}
コード例 #11
0
static void
as_command_parse_value(uint8_t* p, uint8_t type, uint32_t value_size, as_val** value)
{
    // Allocate values on heap.
    switch (type) {
    case AS_BYTES_UNDEF: {
        *value = (as_val*)&as_nil;
        break;
    }
    case AS_BYTES_INTEGER: {
        int64_t v = 0;
        as_command_bytes_to_int(p, value_size, &v);
        *value = (as_val*)as_integer_new(v);
        break;
    }
    case AS_BYTES_DOUBLE: {
        double v = cf_swap_from_big_float64(*(double*)p);
        *value = (as_val*)as_double_new(v);
        break;
    }
    case AS_BYTES_STRING: {
        char* v = malloc(value_size + 1);
        memcpy(v, p, value_size);
        v[value_size] = 0;
        *value = (as_val*)as_string_new_wlen(v, value_size, true);
        break;
    }
    case AS_BYTES_LIST:
    case AS_BYTES_MAP: {
        as_buffer buffer;
        buffer.data = p;
        buffer.size = value_size;

        as_serializer ser;
        as_msgpack_init(&ser);
        as_serializer_deserialize(&ser, &buffer, value);
        as_serializer_destroy(&ser);
        break;
    }
    default: {
        void* v = malloc(value_size);
        memcpy(v, p, value_size);
        *value = (as_val*)as_bytes_new_wrap(v, value_size, true);
        break;
    }
    }
}
コード例 #12
0
ファイル: as_command.c プロジェクト: nutsi/aerospike-client-c
size_t
as_command_value_size(as_val* val, as_buffer* buffer)
{
	switch (val->type) {
		case AS_NIL: {
			return 0;
		}
		case AS_INTEGER: {
			return 8;
		}
		case AS_DOUBLE: {
			return 8;
		}
		case AS_STRING: {
			as_string* v = as_string_fromval(val);
			return as_string_len(v);
		}
		case AS_GEOJSON: {
			as_geojson* v = as_geojson_fromval(val);
			return 
				1 +					// as_particle_geojson_mem::flags
				2 +					// as_particle_geojson_mem::ncells
				(0 * 8) +			// <placeholder-cellids> EMPTY!
				as_geojson_len(v);
		}
		case AS_BYTES: {
			as_bytes* v = as_bytes_fromval(val);
			return v->size;
		}
		case AS_LIST:
		case AS_MAP: {
			as_serializer ser;
			as_msgpack_init(&ser);
			as_serializer_serialize(&ser, val, buffer);
			as_serializer_destroy(&ser);
			return buffer->size;
		}
		default: {
			return 0;
		}
	}
}
コード例 #13
0
as_val *
map_to_asval(const as_particle *p)
{
	map_mem *p_map_mem = (map_mem *)p;

	as_buffer buf;
	as_buffer_init(&buf);

	buf.data = p_map_mem->data;
	buf.capacity = p_map_mem->sz;
	buf.size = p_map_mem->sz;

	as_serializer s;
	as_msgpack_init(&s);

	as_val *val;

	as_serializer_deserialize(&s, &buf, &val);
	as_serializer_destroy(&s);

	return val;
}
コード例 #14
0
uint8_t*
as_command_parse_bins(as_record* rec, uint8_t* p, uint32_t n_bins, bool deserialize)
{
    as_bin* bin = rec->bins.entries;

    // Parse bins
    for (uint32_t i = 0; i < n_bins; i++, bin++) {
        uint32_t op_size = cf_swap_from_be32(*(uint32_t*)p);
        p += 5;
        uint8_t type = *p;
        p += 2;

        uint8_t name_size = *p++;
        uint8_t name_len = (name_size <= AS_BIN_NAME_MAX_LEN)? name_size : AS_BIN_NAME_MAX_LEN;
        memcpy(bin->name, p, name_len);
        bin->name[name_len] = 0;
        p += name_size;

        uint32_t value_size = (op_size - (name_size + 4));

        switch (type) {
        case AS_BYTES_UNDEF: {
            bin->valuep = (as_bin_value*)&as_nil;
            break;
        }
        case AS_BYTES_INTEGER: {
            int64_t value;
            if (as_command_bytes_to_int(p, value_size, &value) == 0) {
                as_integer_init((as_integer*)&bin->value, value);
                bin->valuep = &bin->value;
            }
            break;
        }
        case AS_BYTES_DOUBLE: {
            double value = cf_swap_from_big_float64(*(double*)p);
            as_double_init((as_double*)&bin->value, value);
            bin->valuep = &bin->value;
            break;
        }
        case AS_BYTES_STRING: {
            char* value = malloc(value_size + 1);
            memcpy(value, p, value_size);
            value[value_size] = 0;
            as_string_init_wlen((as_string*)&bin->value, (char*)value, value_size, true);
            bin->valuep = &bin->value;
            break;
        }
        case AS_BYTES_LIST:
        case AS_BYTES_MAP: {
            if (deserialize) {
                as_val* value = 0;

                as_buffer buffer;
                buffer.data = p;
                buffer.size = value_size;

                as_serializer ser;
                as_msgpack_init(&ser);
                as_serializer_deserialize(&ser, &buffer, &value);
                as_serializer_destroy(&ser);

                bin->valuep = (as_bin_value*)value;
            }
            else {
                void* value = malloc(value_size);
                memcpy(value, p, value_size);
                as_bytes_init_wrap((as_bytes*)&bin->value, value, value_size, true);
                bin->value.bytes.type = (as_bytes_type)type;
                bin->valuep = &bin->value;
            }
            break;
        }
        default: {
            void* value = malloc(value_size);
            memcpy(value, p, value_size);
            as_bytes_init_wrap((as_bytes*)&bin->value, value, value_size, true);
            bin->value.bytes.type = (as_bytes_type)type;
            bin->valuep = &bin->value;
            break;
        }
        }
        rec->bins.size++;
        p += value_size;
    }
    return p;
}
コード例 #15
0
ファイル: _shim.c プロジェクト: BlueCava/aerospike-client-c
void clbin_to_asval(cl_bin * bin, as_serializer * ser, as_val ** val) 
{
	if ( val == NULL ) return;

	switch( bin->object.type ) {
		case CL_NULL :{
			*val = (as_val *) &as_nil;
			break;
		}
		case CL_INT : {
			*val = (as_val *) as_integer_new(bin->object.u.i64);
			break;
		}
		case CL_STR : {
			// steal the pointer from the object into the val
			*val = (as_val *) as_string_new(strdup(bin->object.u.str), true /*ismalloc*/);
			// TODO: re-evaluate the follow zero-copy for strings from cl_bins
			// *val = (as_val *) as_string_new(bin->object.u.str, true /*ismalloc*/);
			// bin->object.free = NULL;
			break;
		}
		case CL_LIST :
		case CL_MAP : {
			// use a temporary buffer, which doesn't need to be destroyed
			as_buffer buf = {
				.capacity = (uint32_t) bin->object.sz,
				.size = (uint32_t) bin->object.sz,
				.data = (uint8_t *) bin->object.u.blob
			};
			// print_buffer(&buf);
			as_serializer_deserialize(ser, &buf, val);
			break;
		}
		case CL_BLOB:
		case CL_JAVA_BLOB:
		case CL_CSHARP_BLOB:
		case CL_PYTHON_BLOB:
		case CL_RUBY_BLOB:
		case CL_ERLANG_BLOB:
		default : {
			*val = NULL;
			uint8_t * raw = malloc(sizeof(bin->object.sz));
			memcpy(raw, bin->object.u.blob, bin->object.sz);
			as_bytes * b = as_bytes_new_wrap(raw, (uint32_t)bin->object.sz, true /*ismalloc*/);
			b->type = (as_bytes_type)bin->object.type;
			*val = (as_val *) b;
			break;
		}
	}
}


void clbin_to_asrecord(cl_bin * bin, as_record * r)
{
	switch(bin->object.type) {
		case CL_NULL: {
			as_record_set_nil(r, bin->bin_name);
			break;
		}
		case CL_INT: {
			as_record_set_int64(r, bin->bin_name, bin->object.u.i64);
			break;
		}
		case CL_STR: {
			as_record_set_strp(r, bin->bin_name, bin->object.u.str, true);
			// the following completes the handoff of the value.
			bin->object.free = NULL;
			break;
		}
		case CL_LIST:
		case CL_MAP: {

			as_val * val = NULL;

			as_buffer buffer;
			buffer.data = (uint8_t *) bin->object.u.blob;
			buffer.size = (uint32_t)bin->object.sz;

			as_serializer ser;
			as_msgpack_init(&ser);
			as_serializer_deserialize(&ser, &buffer, &val);
			as_serializer_destroy(&ser);

			as_record_set(r, bin->bin_name, (as_bin_value *) val);
			break;
		}
		default: {
			as_record_set_rawp(r, bin->bin_name, bin->object.u.blob, (uint32_t)bin->object.sz, true);
			// the following completes the handoff of the value.
			bin->object.free = NULL;
			break;
		}
	}
}


void clbins_to_asrecord(cl_bin * bins, uint32_t nbins, as_record * r) 
{
	uint32_t n = nbins < r->bins.capacity ? nbins : r->bins.capacity;
	for ( int i = 0; i < n; i++ ) {
		clbin_to_asrecord(&bins[i], r);
	}
}
コード例 #16
0
/**
 * Call with AS_OPERATIONS_CDT_OP only.
 */
static bool as_operations_cdt_op(as_operations *ops, const as_bin_name name, as_cdt_optype op, size_t n, ...)
{
	if (op >= cdt_op_table_size) {
		return false;
	}

	const cdt_op_table_entry *entry = &cdt_op_table[op];
	if (n < entry->count - entry->opt_args || n > entry->count) {
		return false;
	}

	va_list vl;
	if (n > 0) {
		va_start(vl, n);
	}

	as_arraylist list;
	as_arraylist_inita(&list, (uint32_t)n + 1); // +1 to avoid alloca(0) undefined behavior

	for (size_t i = 0; i < n; i++) {
		as_cdt_paramtype type = entry->args[i];
		switch (type) {
		case AS_CDT_PARAM_PAYLOAD: {
			as_val *arg = va_arg(vl, as_val *);

			if (as_arraylist_append(&list, arg) != AS_ARRAYLIST_OK) {
				va_end(vl);
				as_arraylist_destroy(&list);
				return false;
			}
			break;
		}
		case AS_CDT_PARAM_COUNT: {
			uint64_t arg = va_arg(vl, uint64_t);

			if (as_arraylist_append(&list, (as_val *)as_integer_new(arg)) != AS_ARRAYLIST_OK) {
				va_end(vl);
				as_arraylist_destroy(&list);
				return false;
			}
			break;
		}
		case AS_CDT_PARAM_INDEX: {
			int64_t arg = va_arg(vl, int64_t);

			if (as_arraylist_append(&list, (as_val *)as_integer_new(arg)) != AS_ARRAYLIST_OK) {
				va_end(vl);
				as_arraylist_destroy(&list);
				return false;
			}
			break;
		}
		default:
			break;
		}
	}

	if (n > 0) {
		va_end(vl);
	}

	as_serializer ser;
	as_msgpack_init(&ser);

	uint32_t list_size = as_serializer_serialize_getsize(&ser, (as_val *) &list);
	as_bytes *bytes = as_bytes_new(sizeof(uint16_t) + list_size);
	uint8_t *list_write = as_bytes_get(bytes);
	uint16_t *list_write_op = (uint16_t *)list_write;

	*list_write_op = cf_swap_to_be16(op);
	list_write += sizeof(uint16_t);

	as_serializer_serialize_presized(&ser, (const as_val *) &list, list_write);
	as_serializer_destroy(&ser);
	as_arraylist_destroy(&list);
	bytes->size = bytes->capacity;
	// as_bytes->type default to AS_BYTES_BLOB

	if (entry->rw_type == CDT_RW_TYPE_MODIFY) {
		return as_operations_add_cdt_modify(ops, name, (as_bin_value *) bytes);
	}

	return as_operations_add_cdt_read(ops, name, (as_bin_value *) bytes);
}
コード例 #17
0
ファイル: as_command.c プロジェクト: nutsi/aerospike-client-c
static void
as_command_parse_value(uint8_t* p, uint8_t type, uint32_t value_size, as_val** value)
{
	// Allocate values on heap.
	switch (type) {
		case AS_BYTES_UNDEF: {
			*value = (as_val*)&as_nil;
			break;
		}
		case AS_BYTES_INTEGER: {
			int64_t v = 0;
			as_command_bytes_to_int(p, value_size, &v);
			*value = (as_val*)as_integer_new(v);
			break;
		}
		case AS_BYTES_DOUBLE: {
			double v = cf_swap_from_big_float64(*(double*)p);
			*value = (as_val*)as_double_new(v);
			break;
		}
		case AS_BYTES_STRING: {
			char* v = cf_malloc(value_size + 1);
			memcpy(v, p, value_size);
			v[value_size] = 0;
			*value = (as_val*)as_string_new_wlen(v, value_size, true);
			break;
		}
		case AS_BYTES_GEOJSON: {
			uint8_t * ptr = p;

			// skip flags
			ptr++;

			// ncells
			uint16_t ncells = cf_swap_from_be16(* (uint16_t *) ptr);
			ptr += sizeof(uint16_t);

			// skip any cells
			ptr += sizeof(uint64_t) * ncells;

			// Use the json bytes.
			size_t jsonsz = value_size - 1 - 2 - (ncells * sizeof(uint64_t));
			char* v = cf_malloc(jsonsz + 1);
			memcpy(v, ptr, jsonsz);
			v[jsonsz] = 0;
			*value = (as_val*) as_geojson_new_wlen(v, jsonsz, true);
			break;
		}
		case AS_BYTES_LIST:
		case AS_BYTES_MAP: {
			as_buffer buffer;
			buffer.data = p;
			buffer.size = value_size;
			
			as_serializer ser;
			as_msgpack_init(&ser);
			as_serializer_deserialize(&ser, &buffer, value);
			as_serializer_destroy(&ser);
			break;
		}
		default: {
			void* v = cf_malloc(value_size);
			memcpy(v, p, value_size);
			*value = (as_val*)as_bytes_new_wrap(v, value_size, true);
			break;
		}
	}
}
コード例 #18
0
/*
 * Internal function: udf_aerospike_setbin
 *
 * Parameters:
 * 		r 		-- udf_record to be manipulated
 * 		bname 	-- name of the bin to be deleted
 *		val		-- value to be updated with
 *
 * Return value:
 * 		0  on success
 * 	   -1  on failure
 *
 * Description:
 * 		The function sets the bin with the name
 * 		passed in as parameter to the value, passed as the third parameter.
 * 		Before updating the bin, it is checked if the value can fit in the storage
 *
 * 		Synchronization : object lock acquired by the transaction thread executing UDF.
 * 		Partition reservation takes place just before the transaction starts executing
 * 		( look for as_partition_reserve_udf in thr_tsvc.c )
 *
 * 		Callers:
 * 		udf_aerospike__apply_update_atomic
 * 		In this function, if it fails at the time of update, the record is set
 * 		to rollback all the updates till this point. The case where it fails in
 * 		rollback is not handled.
 *
 * 		Side Notes:
 * 		i.	write_to_device will be set to true on a successful bin update.
 * 		If all the updates from udf_aerospike__apply_update_atomic (including this) are
 * 		successful, the record will be written to disk and reopened so that the rest of
 * 		sets of updates can be applied.
 *
 * 		ii.	If put in sindex fails, we do not handle it.
 *
 * 		TODO make sure anything goes into setbin only if the bin value is
 * 		          changed
 */
static const int
udf_aerospike_setbin(udf_record * urecord, const char * bname, const as_val * val, bool is_hidden)
{
	if (bname == NULL || bname[0] == 0 ) {
		cf_warning(AS_UDF, "no bin name supplied");
		return -1;
	}

	uint8_t type = as_val_type(val);
	if (is_hidden &&
			((type != AS_MAP) && (type != AS_LIST))) {
		cf_warning(AS_UDF, "Hidden %d Type Not allowed", type);
		return -3;
	}

	size_t          blen    = strlen(bname);
	as_storage_rd * rd      = urecord->rd;
	as_transaction *tr      = urecord->tr;
	as_index_ref  * index   = urecord->r_ref;

	as_bin * b = as_bin_get(rd, (byte *)bname, blen);

	if ( !b && (blen > (AS_ID_BIN_SZ - 1 )
				|| !as_bin_name_within_quota(rd->ns, (byte *)bname, blen)) ) {
		// Can't write bin
		cf_warning(AS_UDF, "bin name %s too big. Bin not added", bname);
		return -1;
	}
	if ( !b ) {
		// See if there's a free one, the hope is you will always find the bin because
		// you have already allocated bin space before calling this function.
		b = as_bin_create(index->r, rd, (byte *)bname, blen, 0);
		if (!b) {
			cf_warning(AS_UDF, "ERROR: udf_aerospike_setbin: as_bin_create: bin not found, something went really wrong!");
			return -1;
		}
	}

	SINDEX_BINS_SETUP(oldbin, 1);
	SINDEX_BINS_SETUP(newbin, 1);
	bool needs_sindex_delete = false;
	bool needs_sindex_put    = false;
	bool needs_sindex_update = false;
	bool has_sindex          = as_sindex_ns_has_sindex(rd->ns);

	if (has_sindex
			&& (as_sindex_sbin_from_bin(rd->ns,
					as_index_get_set_name(rd->r, rd->ns),
					b, oldbin) == AS_SINDEX_OK)) {
		needs_sindex_delete = true;
	}

	// we know we are doing an update now, make sure there is particle data,
	// set to be 1 wblock size now @TODO!
	uint32_t pbytes = 0;
	int ret = 0;
	if (!rd->ns->storage_data_in_memory && !urecord->particle_data) {
		urecord->particle_data = cf_malloc(rd->ns->storage_write_block_size);
		urecord->cur_particle_data = urecord->particle_data;
		urecord->end_particle_data = urecord->particle_data + rd->ns->storage_write_block_size;
	}

	cf_detail(AS_UDF, "udf_setbin: bin %s type %d ", bname, type );

	switch(type) {
		case AS_STRING: {
			as_string * v   = as_string_fromval(val);
			byte *      s   = (byte *) as_string_tostring(v);
			size_t      l   = as_string_len(v);

			// Save for later.
			// cf_detail(AS_UDF, "udf_setbin: string: binname %s value is %s",bname,s);

			if ( !as_storage_bin_can_fit(rd->ns, l) ) {
				cf_warning(AS_UDF, "string: bin size too big");
				ret = -1;
				break;
			}
			if (rd->ns->storage_data_in_memory) {
				as_particle_frombuf(b, AS_PARTICLE_TYPE_STRING, s, l, NULL, true);
			} else {
				pbytes = l + as_particle_get_base_size(AS_PARTICLE_TYPE_STRING);
				if ((urecord->cur_particle_data + pbytes) < urecord->end_particle_data) {
					as_particle_frombuf(b, AS_PARTICLE_TYPE_STRING, s, l,
										urecord->cur_particle_data,
										rd->ns->storage_data_in_memory);
					urecord->cur_particle_data += pbytes;
				} else {
					cf_warning(AS_UDF, "string: bin data size too big: pbytes %d"
								" pdata %p cur_part+pbytes %p pend %p", pbytes,
								urecord->particle_data, urecord->cur_particle_data + pbytes,
								urecord->end_particle_data);
					ret = -1;
					break;
				}
			}
			break;
		}
		case AS_BYTES: {
			as_bytes *  v   = as_bytes_fromval(val);
			uint8_t *   s   = as_bytes_get(v);
			size_t      l   = as_bytes_size(v);

			if ( !as_storage_bin_can_fit(rd->ns, l) ) {
				cf_warning(AS_UDF, "bytes: bin size too big");
				ret = -1;
				break;
			}
			if (rd->ns->storage_data_in_memory) {
				as_particle_frombuf(b, AS_PARTICLE_TYPE_BLOB, s, l, NULL, true);
			} else {
				pbytes = l + as_particle_get_base_size(AS_PARTICLE_TYPE_BLOB);
				if ((urecord->cur_particle_data + pbytes) < urecord->end_particle_data) {
					as_particle_frombuf(b, AS_PARTICLE_TYPE_BLOB, s, l, urecord->cur_particle_data,
										rd->ns->storage_data_in_memory);
					urecord->cur_particle_data += pbytes;
				} else {
					cf_warning(AS_UDF, "bytes: bin data size too big pbytes %d"
								" pdata %p cur_part+pbytes %p pend %p", pbytes,
								urecord->particle_data, urecord->cur_particle_data + pbytes,
								urecord->end_particle_data);
					ret = -1;
					break;
				}
			}
			break;
		}
		case AS_BOOLEAN: {
			as_boolean *    v   = as_boolean_fromval(val);
			bool            d   = as_boolean_get(v);
			int64_t         i   = __be64_to_cpup((void *)&d);

			if ( !as_storage_bin_can_fit(rd->ns, 8) ) {
				cf_warning(AS_UDF, "bool: bin size too big");
				ret = -1;
				break;
			}
			if (rd->ns->storage_data_in_memory) {
				as_particle_frombuf(b, AS_PARTICLE_TYPE_INTEGER, (uint8_t *) &i, 8, NULL, true);
			} else {
				pbytes = 8 + as_particle_get_base_size(AS_PARTICLE_TYPE_INTEGER);
				if ((urecord->cur_particle_data + pbytes) < urecord->end_particle_data) {
					as_particle_frombuf(b, AS_PARTICLE_TYPE_INTEGER,
										(uint8_t *) &i, 8,
										urecord->cur_particle_data,
										rd->ns->storage_data_in_memory);
					urecord->cur_particle_data += pbytes;
				} else {
					cf_warning(AS_UDF, "bool: bin data size too big: pbytes %d %p %p %p",
								pbytes, urecord->particle_data, urecord->cur_particle_data,
								urecord->end_particle_data);
					ret = -1;
					break;
				}
			}
			break;
		}
		case AS_INTEGER: {
			as_integer *    v   = as_integer_fromval(val);
			int64_t         i   = as_integer_get(v);
			int64_t         j   = __be64_to_cpup((void *)&i);

			if ( !as_storage_bin_can_fit(rd->ns, 8) ) {
				cf_warning(AS_UDF, "int: bin size too big");
				ret = -1;
				break;
			}
			if (rd->ns->storage_data_in_memory) {
				as_particle_frombuf(b, AS_PARTICLE_TYPE_INTEGER, (uint8_t *) &j, 8, NULL, true);
			} else {
				pbytes = 8 + as_particle_get_base_size(AS_PARTICLE_TYPE_INTEGER);
				if ((urecord->cur_particle_data + pbytes) < urecord->end_particle_data) {
					as_particle_frombuf(b, AS_PARTICLE_TYPE_INTEGER,
										(uint8_t *) &j, 8, urecord->cur_particle_data,
										rd->ns->storage_data_in_memory);
					urecord->cur_particle_data += pbytes;
				} else {
					cf_warning(AS_UDF, "int: bin data size too big: pbytes %d %p %p %p",
								pbytes, urecord->particle_data, urecord->cur_particle_data,
								urecord->end_particle_data);
					ret = -1;
					break;
				}
			}
			break;
		}
		// @LDT : Possibly include AS_LDT in this list.  We need the LDT
		// bins to be updated by LDT lua calls, and that path takes us thru here.
		// However, we ALSO need to be able to set the particle type for the
		// bins -- so that requires extra processing here to take the LDT flags
		// and set the appropriate bin flags in the particle data.
		case AS_MAP:
		case AS_LIST: {
			as_buffer buf;
			as_buffer_init(&buf);
			as_serializer s;
			as_msgpack_init(&s);
			int rsp = 0;
			as_serializer_serialize(&s, (as_val *) val, &buf);

			if ( !as_storage_bin_can_fit(rd->ns, buf.size) ) {
				cf_warning(AS_UDF, "map-list: bin size too big");
				ret = -1;
				// Clean Up and jump out.
				as_serializer_destroy(&s);
				as_buffer_destroy(&buf);
				break; // can't continue if value too big.
			}
			uint8_t ptype;
			if(is_hidden) {
				ptype = as_particle_type_convert_to_hidden(to_particle_type(type));
			} else {
				ptype = to_particle_type(type);
			}
			if (rd->ns->storage_data_in_memory) {
				as_particle_frombuf(b, ptype, (uint8_t *) buf.data, buf.size, NULL, true);
			}
			else {
				pbytes = buf.size + as_particle_get_base_size(ptype);
				if ((urecord->cur_particle_data + pbytes) < urecord->end_particle_data) {
					as_particle_frombuf(b, ptype, (uint8_t *) buf.data, buf.size,
										urecord->cur_particle_data,	rd->ns->storage_data_in_memory);
					urecord->cur_particle_data += pbytes;
				} else {
					cf_warning(AS_UDF, "map-list: bin data size too big: pbytes %d %p %p %p",
								pbytes, urecord->particle_data, urecord->cur_particle_data,
								urecord->end_particle_data);
					rsp = -1;
				}
			}
			as_serializer_destroy(&s);
			as_buffer_destroy(&buf);
			if (rsp) {
				ret = rsp;
				break;
			}
			break;
		}
		default: {
			cf_warning(AS_UDF, "unrecognized object type %d, skipping", as_val_type(val) );
			break;
		}

	}

	// If something fail bailout
	if (ret) {
		as_sindex_sbin_freeall(oldbin, 1);
		as_sindex_sbin_freeall(newbin, 1);
		return ret;
	}

	// Update sindex if required
	if (has_sindex) {
		if (as_sindex_sbin_from_bin(rd->ns,
				as_index_get_set_name(rd->r, rd->ns), b, newbin) == AS_SINDEX_OK) {
			if (!as_sindex_sbin_match(newbin, oldbin)) {
				needs_sindex_put    = true;
			} else {
				needs_sindex_update = true;
			}
		}

		if (needs_sindex_update) {
			tr->flag |= AS_TRANSACTION_FLAG_SINDEX_TOUCHED;
			as_sindex_delete_by_sbin(rd->ns,
					as_index_get_set_name(rd->r, rd->ns), 1, oldbin, rd);
			as_sindex_put_by_sbin(rd->ns,
					as_index_get_set_name(rd->r, rd->ns), 1, newbin, rd);
		} else {
			if (needs_sindex_delete) {
				tr->flag |= AS_TRANSACTION_FLAG_SINDEX_TOUCHED;
				as_sindex_delete_by_sbin(rd->ns,
					as_index_get_set_name(rd->r, rd->ns), 1, oldbin, rd);
			}
			if (needs_sindex_put) {
				tr->flag |= AS_TRANSACTION_FLAG_SINDEX_TOUCHED;
				as_sindex_put_by_sbin(rd->ns,
					as_index_get_set_name(rd->r, rd->ns), 1, newbin, rd);
			}
		}
		as_sindex_sbin_freeall(oldbin, 1);
		as_sindex_sbin_freeall(newbin, 1);
	}
	return ret;
} // end udf_aerospike_setbin()
コード例 #19
0
/**
 *	Lookup a record by key, then apply the UDF.
 *
 *	~~~~~~~~~~{.c}
 *		as_key key;
 *		as_key_init(&key, "ns", "set", "key");
 *
 *		as_arraylist args;
 *		as_arraylist_init(&args, 2, 0);
 *		as_arraylist_append_int64(&args, 1);
 *		as_arraylist_append_int64(&args, 2);
 *		
 *		as_val * res = NULL;
 *		
 *		if ( aerospike_key_apply(&as, &err, NULL, &key, "math", "add", &args, &res) != AEROSPIKE_OK ) {
 *			fprintf(stderr, "error(%d) %s at [%s:%d]", err.code, err.message, err.file, err.line);
 *		}
 *		else {
 *			as_val_destroy(res);
 *		}
 *		
 *		as_arraylist_destroy(&args);
 *	~~~~~~~~~~
 *
 *
 *	@param as			The aerospike instance to use for this operation.
 *	@param err			The as_error to be populated if an error occurs.
 *	@param policy		The policy to use for this operation. If NULL, then the default policy will be used.
 *	@param key			The key of the record.
 *	@param module		The module containing the function to execute.
 *	@param function 	The function to execute.
 *	@param arglist 		The arguments for the function.
 *	@param result 		The return value from the function.
 *
 *	@return AEROSPIKE_OK if successful. Otherwise an error.
 */
as_status aerospike_key_apply(
	aerospike * as, as_error * err, const as_policy_apply * policy, 
	const as_key * key, 
	const char * module, const char * function, as_list * arglist, 
	as_val ** result) 
{
	// we want to reset the error so, we have a clean state
	as_error_reset(err);
	
	// resolve policies
	as_policy_apply p;
	as_policy_apply_resolve(&p, &as->config.policies, policy);

	cl_write_parameters wp;
	cl_write_parameters_set_default(&wp);
	wp.timeout_ms = p.timeout == UINT32_MAX ? 0 : p.timeout;

	cl_object okey;
	asval_to_clobject((as_val *) key->valuep, &okey);

	as_serializer ser;
	as_msgpack_init(&ser);

	as_string file;
	as_string_init(&file, (char *) module, true /*ismalloc*/);

	as_string func;
	as_string_init(&func, (char *) function, true /*ismalloc*/);
	
	as_buffer args;
	as_buffer_init(&args);

	as_serializer_serialize(&ser, (as_val *) arglist, &args);

	as_call call = {
		.file = &file,
		.func = &func,
		.args = &args
	};

	uint64_t trid = 0;
	cl_bin * bins = 0;
	int n_bins = 0;

	cl_rv rc = CITRUSLEAF_OK;

	switch ( p.key ) {
		case AS_POLICY_KEY_DIGEST: {
			as_digest * digest = as_key_digest((as_key *) key);
			rc = do_the_full_monte( 
				as->cluster, 0, CL_MSG_INFO2_WRITE, 0, 
				key->ns, key->set, 0, (cf_digest *) digest->value, &bins, CL_OP_WRITE, 0, &n_bins, 
				NULL, &wp, &trid, NULL, &call, NULL
			);
			break;
		}
		case AS_POLICY_KEY_SEND: {
			cl_object okey;
			asval_to_clobject((as_val *) key->valuep, &okey);
			as_digest * digest = as_key_digest((as_key *) key);
			rc = do_the_full_monte( 
				as->cluster, 0, CL_MSG_INFO2_WRITE, 0, 
				key->ns, key->set, &okey, (cf_digest*)digest->value, &bins, CL_OP_WRITE, 0, &n_bins,
				NULL, &wp, &trid, NULL, &call, NULL
			);
			break;
		}
		default: {
			// ERROR CASE
			break;
		}
	}

	as_buffer_destroy(&args);

	if (! (rc == CITRUSLEAF_OK || rc == CITRUSLEAF_FAIL_UDF_BAD_RESPONSE)) {
		as_error_fromrc(err, rc);
	}
	else {

		// Begin processing the data returned from the server,
		// IFF `result` argument is not NULL.
		// The reason is if `result` is NULL, then it implies the end user
		// does not care about the data returned from the server.

		if ( n_bins == 1  ) {
			cl_bin * bin = &bins[0];

			if ( strcmp(bin->bin_name,"SUCCESS") == 0 ) {
				if ( result ) {
					as_val * val = NULL;
					clbin_to_asval(bin, &ser, &val);
					*result = val;
				}
			}
			else if ( strcmp(bin->bin_name,"FAILURE") == 0 ) {
				as_val * val = NULL;
				clbin_to_asval(bin, &ser, &val);
				if ( val->type == AS_STRING ) {
					as_string * s = as_string_fromval(val);
					as_error_update(err, AEROSPIKE_ERR_UDF, as_string_tostring(s));
				}
				else {
					as_error_update(err, AEROSPIKE_ERR_SERVER, "unexpected failure bin type");
				}
				as_val_destroy(val);
			}
			else {
				as_error_update(err, AEROSPIKE_ERR_SERVER, "unexpected bin name");
			}
		}
		else {
			as_error_update(err, AEROSPIKE_ERR_SERVER, "unexpected number of bins");
		}
	}

	if ( bins ) {
		citrusleaf_bins_free(bins, n_bins);
		free(bins);
	}

	as_serializer_destroy(&ser);
	
	return err->code;
}
コード例 #20
0
ファイル: proto.c プロジェクト: DarkDare/aerospike-server
int as_msg_make_response_bufbuilder(as_record *r, as_storage_rd *rd,
		cf_buf_builder **bb_r, bool nobindata, char *nsname, bool use_sets,
		bool include_key, bool skip_empty_records, cf_vector *binlist)
{
	// Sanity checks. Either rd should be there or nobindata and nsname should be present.
	if (!(rd || (nobindata && nsname))) {
		cf_detail(AS_PROTO, "Neither storage record nor nobindata is set. Skipping the record.");
		return 0;
	}

	// figure out the size of the entire buffer
	int         set_name_len = 0;
	const char *set_name     = NULL;
	int         ns_len       = rd ? strlen(rd->ns->name) : strlen(nsname);

	if (use_sets && as_index_get_set_id(r) != INVALID_SET_ID) {
		as_namespace *ns = NULL;

		if (rd) {
			ns = rd->ns;
		} else if (nsname) {
			ns = as_namespace_get_byname(nsname);
		}
		if (!ns) {
			cf_info(AS_PROTO, "Cannot get namespace, needed to get set information. Skipping record.");
			return -1;
		}
		set_name = as_index_get_set_name(r, ns);
		if (set_name) {
			set_name_len = strlen(set_name);
		}
	}

	uint8_t* key = NULL;
	uint32_t key_size = 0;

	if (include_key && as_index_is_flag_set(r, AS_INDEX_FLAG_KEY_STORED)) {
		if (! as_storage_record_get_key(rd)) {
			cf_info(AS_PROTO, "can't get key - skipping record");
			return -1;
		}

		key = rd->key;
		key_size = rd->key_size;
	}

	uint16_t n_fields = 2;
	int msg_sz = sizeof(as_msg);
	msg_sz += sizeof(as_msg_field) + sizeof(cf_digest);
	msg_sz += sizeof(as_msg_field) + ns_len;
	if (set_name) {
		n_fields++;
		msg_sz += sizeof(as_msg_field) + set_name_len;
	}
	if (key) {
		n_fields++;
		msg_sz += sizeof(as_msg_field) + key_size;
	}

	int list_bins   = 0;
	int num_bins = 0;
	if (rd) {
		num_bins = as_bin_inuse_count(rd);
	}
	if (binlist) {
		num_bins = cf_vector_size(binlist);
	}
	
	as_val *ldtBinVal[num_bins];
	as_particle_type ldtBinParticleType[num_bins];

	if (nobindata == false) {
		if (binlist) {
			for(uint16_t i = 0; i < num_bins; i++) {
				char binname[AS_ID_BIN_SZ];
				cf_vector_get(binlist, i, (void*)&binname);
				cf_debug(AS_PROTO, " Binname projected inside is |%s| \n", binname);
				as_bin *p_bin = as_bin_get (rd, (uint8_t*)binname, strlen(binname));
				if (!p_bin)
				{
					cf_debug(AS_PROTO, "To be projected bin |%s| not found \n", binname);
					continue;
				}
				cf_debug(AS_PROTO, "Adding bin |%s| to projected bins |%s| \n", binname);
				msg_sz += sizeof(as_msg_op);
				msg_sz += rd->ns->single_bin ? 0 : strlen(binname);
				uint32_t psz;
				if (as_bin_is_hidden(p_bin)) {
					ldtBinVal[list_bins] = as_llist_scan(rd->ns, rd->ns->partitions[as_partition_getid(rd->keyd)].sub_vp, rd, p_bin);
					if (ldtBinVal[list_bins]) {
						ldtBinParticleType[list_bins] = AS_PARTICLE_TYPE_HIDDEN_LIST;
					}
					as_serializer s;
					as_msgpack_init(&s);
					psz = as_serializer_serialize_getsize(&s, (as_val *)ldtBinVal[list_bins]);
					as_serializer_destroy(&s);
				} else {
					as_particle_tobuf(p_bin, 0, &psz); // get size
				}
				list_bins++;
				msg_sz += psz;
			}

			// Don't return an empty record.
			if (skip_empty_records && list_bins == 0) {
				return 0;
			}
		}
		else {
			msg_sz += sizeof(as_msg_op) * num_bins; // the bin headers
			for (uint16_t i = 0; i < num_bins; i++) {
				as_bin *p_bin = &rd->bins[i];
				msg_sz += rd->ns->single_bin ? 0 : strlen(as_bin_get_name_from_id(rd->ns, p_bin->id));
				uint32_t psz;
				if (as_bin_is_hidden(p_bin)) {
					ldtBinVal[list_bins] = as_llist_scan(rd->ns, rd->ns->partitions[as_partition_getid(rd->keyd)].sub_vp, rd, p_bin);
					if (ldtBinVal[list_bins]) {
						ldtBinParticleType[list_bins] = AS_PARTICLE_TYPE_HIDDEN_LIST;
					}
					as_serializer s;
					as_msgpack_init(&s);
					psz = as_serializer_serialize_getsize(&s, (as_val *)ldtBinVal[list_bins]);
					as_serializer_destroy(&s);
				} else {
					as_particle_tobuf(p_bin, 0, &psz); // get size
				}
				msg_sz += psz;
				list_bins++;
			}
		}
	}

	uint8_t *b;
	cf_buf_builder_reserve(bb_r, msg_sz, &b);

	// set up the header
	uint8_t *buf = b;
	as_msg *msgp = (as_msg *) buf;

	msgp->header_sz = sizeof(as_msg);
	msgp->info1 = (nobindata ? AS_MSG_INFO1_GET_NOBINDATA : 0);
	msgp->info2 = 0;
	msgp->info3 = 0;
	msgp->unused = 0;
	msgp->result_code = 0;
	msgp->generation = r->generation;
	msgp->record_ttl = r->void_time;
	msgp->transaction_ttl = 0;
	msgp->n_fields = n_fields;
	if (rd) {
		if (binlist)
			msgp->n_ops = list_bins;
		else
			msgp->n_ops = num_bins;
	} else {
		msgp->n_ops = 0;
	}
	as_msg_swap_header(msgp);

	buf += sizeof(as_msg);

	as_msg_field *mf = (as_msg_field *) buf;
	mf->field_sz = sizeof(cf_digest) + 1;
	mf->type = AS_MSG_FIELD_TYPE_DIGEST_RIPE;
	if (rd) {
		memcpy(mf->data, &rd->keyd, sizeof(cf_digest));
	} else {
		memcpy(mf->data, &r->key, sizeof(cf_digest));
	}
	as_msg_swap_field(mf);
	buf += sizeof(as_msg_field) + sizeof(cf_digest);

	mf = (as_msg_field *) buf;
	mf->field_sz = ns_len + 1;
	mf->type = AS_MSG_FIELD_TYPE_NAMESPACE;
	if (rd) {
		memcpy(mf->data, rd->ns->name, ns_len);
	} else {
		memcpy(mf->data, nsname, ns_len);
	}
	as_msg_swap_field(mf);
	buf += sizeof(as_msg_field) + ns_len;

	if (set_name) {
		mf = (as_msg_field *) buf;
		mf->field_sz = set_name_len + 1;
		mf->type = AS_MSG_FIELD_TYPE_SET;
		memcpy(mf->data, set_name, set_name_len);
		as_msg_swap_field(mf);
		buf += sizeof(as_msg_field) + set_name_len;
	}

	if (key) {
		mf = (as_msg_field *) buf;
		mf->field_sz = key_size + 1;
		mf->type = AS_MSG_FIELD_TYPE_KEY;
		memcpy(mf->data, key, key_size);
		as_msg_swap_field(mf);
		buf += sizeof(as_msg_field) + key_size;
	}

	if (nobindata) {
		goto Out;
	}
	list_bins = 0;

	if (binlist) {
		for (uint16_t i = 0; i < num_bins; i++) {

			char binname[AS_ID_BIN_SZ];
			cf_vector_get(binlist, i, (void*)&binname);
			cf_debug(AS_PROTO, " Binname projected inside is |%s| \n", binname);
			as_bin *p_bin = as_bin_get (rd, (uint8_t*)binname, strlen(binname));
			if (!p_bin) // should it be checked before ???
				continue;

			as_msg_op *op = (as_msg_op *)buf;
			buf += sizeof(as_msg_op);

			op->op = AS_MSG_OP_READ;

			op->name_sz = as_bin_memcpy_name(rd->ns, op->name, p_bin);
			buf += op->name_sz;

			// Since there are two variable bits, the size is everything after
			// the data bytes - and this is only the head, we're patching up
			// the rest in a minute.
			op->op_sz = 4 + op->name_sz;

			if (as_bin_inuse(p_bin)) {
				op->particle_type = as_particle_type_convert(as_bin_get_particle_type(p_bin));
				op->version = as_bin_get_version(p_bin, rd->ns->single_bin);

				uint32_t psz = msg_sz - (buf - b); // size remaining in buffer, for safety
				if (as_bin_is_hidden(p_bin)) {
					if (!ldtBinVal[list_bins]) {
						op->particle_type = AS_PARTICLE_TYPE_NULL;
						psz = 0;
					} else {
						op->particle_type = ldtBinParticleType[list_bins];
						as_buffer abuf;
						as_buffer_init(&abuf);
						as_serializer s;
						as_msgpack_init(&s);
						as_serializer_serialize(&s, (as_val *)ldtBinVal[list_bins], &abuf);
						psz = abuf.size;
						memcpy(buf, abuf.data, abuf.size);
						as_serializer_destroy(&s);
						as_buffer_destroy(&abuf);
						as_val_destroy(ldtBinVal[list_bins]);
					}
				} else {
					if (0 != as_particle_tobuf(p_bin, buf, &psz)) {
						cf_warning(AS_PROTO, "particle to buf: could not copy data!");
					}
				}
				list_bins++;
				buf += psz;
				op->op_sz += psz;
			}
			else {
				cf_debug(AS_PROTO, "Whoops !! bin not in use");
				op->particle_type = AS_PARTICLE_TYPE_NULL;
			}
			as_msg_swap_op(op);
		}
	}
	else {
		// over all bins, copy into the buffer
		for (uint16_t i = 0; i < num_bins; i++) {

			as_msg_op *op = (as_msg_op *)buf;
			buf += sizeof(as_msg_op);

			op->op = AS_MSG_OP_READ;

			op->name_sz = as_bin_memcpy_name(rd->ns, op->name, &rd->bins[i]);
			buf += op->name_sz;

			// Since there are two variable bits, the size is everything after
			// the data bytes - and this is only the head, we're patching up
			// the rest in a minute.
			op->op_sz = 4 + op->name_sz;

			if (as_bin_inuse(&rd->bins[i])) {
				op->particle_type = as_particle_type_convert(as_bin_get_particle_type(&rd->bins[i]));
				op->version = as_bin_get_version(&rd->bins[i], rd->ns->single_bin);

				uint32_t psz = msg_sz - (buf - b); // size remaining in buffer, for safety
				if (as_bin_is_hidden(&rd->bins[i])) {
					if (!ldtBinVal[list_bins]) {
						op->particle_type = AS_PARTICLE_TYPE_NULL;
						psz = 0;
					} else {
						op->particle_type = ldtBinParticleType[list_bins];
						as_buffer abuf;
						as_buffer_init(&abuf);
						as_serializer s;
						as_msgpack_init(&s);
						as_serializer_serialize(&s, (as_val *)ldtBinVal[list_bins], &abuf);
						psz = abuf.size;
						memcpy(buf, abuf.data, abuf.size);
						as_serializer_destroy(&s);
						as_buffer_destroy(&abuf);
						as_val_destroy(ldtBinVal[list_bins]);
					}
				} else {
					if (0 != as_particle_tobuf(&rd->bins[i], buf, &psz)) {
						cf_warning(AS_PROTO, "particle to buf: could not copy data!");
					}
				}
				list_bins++;
				buf += psz;
				op->op_sz += psz;
			}
			else {
				op->particle_type = AS_PARTICLE_TYPE_NULL;
			}
			as_msg_swap_op(op);
		}
	}
Out:
	return(0);
}