Ejemplo n.º 1
0
static int check_bin2(as_record * rec, scan_check * check)
{
	as_val * bin = (as_val *) as_record_get(rec, "bin2");
	if ( !bin ) {
		error("Expected a value in bin('%s'), but got null", "bin2");
		return !(check->failed = true);
	}
	
	as_string * string = as_string_fromval(bin);
	if ( !string ) {
		error("Expected a string in bin('%s'), but got type %d", "bin2", as_val_type(bin));
		return !(check->failed = true);
	}
	
	char * str = as_string_get(string);
	if ( !str ) {
		error("Expected a string value but it is NULL");
		return !(check->failed = true);
	}

	// Check the string bin
	char expected[SET_STRSZ];
	int64_t bin1 = as_record_get_int64(rec, "bin1", INT64_MIN);
	sprintf(expected, "str-%s-%" PRId64, rec->key.set[0] == '\0' ? "noset" : rec->key.set, bin1);

	if (strcmp(expected, str) != 0) {
		error("Expected '%s' in bin('%s'), but got '%s'", expected, "bin2", str);
		return !(check->failed = true);
	}

	return !(check->failed = false);
}
Ejemplo n.º 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;
    }
    }
}
Ejemplo n.º 3
0
/*
 * Internal Function: Entry function from UDF code path to send
 * 					  success result to the caller. Performs
 * 					  value translation.
 */
void
send_result(as_result * res, udf_call * call)
{
	as_val * v = res->value;
	if ( res->is_success ) {

		if ( cf_context_at_severity(AS_UDF, CF_DETAIL) ) {
			char * str = as_val_tostring(v);
			cf_detail(AS_UDF, "SUCCESS: %s", str);
			cf_free(str);
		}

		send_success(call, v);

	} else { // Else -- NOT success
		if (as_val_type(v) == AS_STRING) {
			send_udf_failure(call, as_string_fromval(v));
		} else {
			char lua_err_str[1024];
			size_t len = (size_t)sprintf(lua_err_str, "%s:0: in function %s() - error() argument type not handled", call->def.filename, call->def.function);

			call->tr->result_code = AS_PROTO_RESULT_FAIL_UDF_EXECUTION;
			send_failure_str(call, lua_err_str, len);
		}
	}
}
Ejemplo n.º 4
0
static size_t
as_command_user_key_size(const as_key* key)
{
    size_t size = AS_FIELD_HEADER_SIZE + 1;  // Add 1 for key's value type.
    as_val* val = (as_val*)key->valuep;

    // Key must not be list or map.
    switch (val->type) {
    case AS_NIL: {
        break;
    }
    case AS_INTEGER: {
        size += 8;
        break;
    }
    case AS_STRING: {
        as_string* v = as_string_fromval(val);
        // v->len should have been already set when calculating the digest.
        size += v->len;
        break;
    }
    case AS_BYTES: {
        as_bytes* v = as_bytes_fromval(val);
        size += v->size;
        break;
    }
    default: {
        break;
    }
    }
    return size;
}
Ejemplo n.º 5
0
as_status
as_key_set_digest(as_error* err, as_key* key)
{
	if (key->digest.init) {
		return AEROSPIKE_OK;
	}
	
	size_t set_len = strlen(key->set);
	size_t size;
	
	as_val* val = (as_val*)key->valuep;
	uint8_t* buf;
	
	switch (val->type) {
		case AS_INTEGER: {
			as_integer* v = as_integer_fromval(val);
			size = 9;
			buf = alloca(size);
			buf[0] = AS_BYTES_INTEGER;
			*(uint64_t*)&buf[1] = cf_swap_to_be64(v->value);
			break;
		}
		case AS_DOUBLE: {
			as_double* v = as_double_fromval(val);
			size = 9;
			buf = alloca(size);
			buf[0] = AS_BYTES_DOUBLE;
			*(double*)&buf[1] = cf_swap_to_big_float64(v->value);
			break;
		}
		case AS_STRING: {
			as_string* v = as_string_fromval(val);
			size_t len = as_string_len(v);
			size = len + 1;
			buf = alloca(size);
			buf[0] = AS_BYTES_STRING;
			memcpy(&buf[1], v->value, len);
			break;
		}
		case AS_BYTES: {
			as_bytes* v = as_bytes_fromval(val);
			size = v->size + 1;
			buf = alloca(size);
			// Note: v->type must be a blob type (AS_BYTES_BLOB, AS_BYTES_JAVA, AS_BYTES_PYTHON ...).
			// Otherwise, the particle type will be reassigned to a non-blob which causes a
			// mismatch between type and value.
			buf[0] = v->type;
			memcpy(&buf[1], v->value, v->size);
			break;
		}
		default: {
			return as_error_update(err, AEROSPIKE_ERR_PARAM, "Invalid key type: %d", val->type);
		}
	}
		
	cf_digest_compute2(key->set, set_len, buf, size, (cf_digest*)key->digest.value);
	key->digest.init = true;
	return AEROSPIKE_OK;
}
uint32_t
string_asval_to_wire(const as_val *val, uint8_t *wire)
{
	as_string *string = as_string_fromval(val);
	uint32_t size = (uint32_t)as_string_len(string);

	memcpy(wire, as_string_tostring(string), size);

	return size;
}
Ejemplo n.º 7
0
static uint8_t*
as_command_write_user_key(uint8_t* begin, const as_key* key)
{
    uint8_t* p = begin + AS_FIELD_HEADER_SIZE;
    as_val* val = (as_val*)key->valuep;
    uint32_t len;

    // Key must not be list or map.
    switch (val->type) {
    default:
    case AS_NIL: {
        *p++ = AS_BYTES_UNDEF;
        len = 0;
        break;
    }
    case AS_INTEGER: {
        as_integer* v = as_integer_fromval(val);
        *p++ = AS_BYTES_INTEGER;
        *(uint64_t*)p = cf_swap_to_be64(v->value);
        p += 8;
        len = 8;
        break;
    }
    case AS_DOUBLE: {
        as_double* v = as_double_fromval(val);
        *p++ = AS_BYTES_DOUBLE;
        *(double*)p = cf_swap_to_big_float64(v->value);
        p += 8;
        len = 8;
        break;
    }
    case AS_STRING: {
        as_string* v = as_string_fromval(val);
        *p++ = AS_BYTES_STRING;
        // v->len should have been already set when calculating the digest.
        memcpy(p, v->value, v->len);
        p += v->len;
        len = (uint32_t)v->len;
        break;
    }
    case AS_BYTES: {
        as_bytes* v = as_bytes_fromval(val);
        // Note: v->type must be a blob type (AS_BYTES_BLOB, AS_BYTES_JAVA, AS_BYTES_PYTHON ...).
        // Otherwise, the particle type will be reassigned to a non-blob which causes a
        // mismatch between type and value.
        *p++ = v->type;
        memcpy(p, v->value, v->size);
        p += v->size;
        len = v->size;
        break;
    }
    }
    as_command_write_field_header(begin, AS_FIELD_KEY, ++len);
    return p;
}
void
string_from_asval(const as_val *val, as_particle **pp)
{
	string_mem *p_string_mem = (string_mem *)*pp;

	as_string *string = as_string_fromval(val);

	p_string_mem->type = AS_PARTICLE_TYPE_STRING;
	p_string_mem->sz = (uint32_t)as_string_len(string);
	memcpy(p_string_mem->data, as_string_tostring(string), p_string_mem->sz);
}
Ejemplo n.º 9
0
uint32_t as_string_val_hashcode(const as_val * v)
{
	as_string * string = as_string_fromval(v);
	if ( string == NULL || string->value == NULL) return 0;
	uint32_t hash = 0;
	int c;
	char * str = string->value;
	while ( (c = *str++) ) {
		hash = c + (hash << 6) + (hash << 16) - hash;
	}
	return hash;
}
Ejemplo n.º 10
0
void as_string_val_destroy(as_val * v)
{
	as_string * string = as_string_fromval(v);
	if ( !string ) return;

	if ( string->value && string->free ) {
		cf_free(string->value);
	}
	
	string->value = NULL;
	string->free = false;
}
Ejemplo n.º 11
0
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;
		}
	}
}
Ejemplo n.º 12
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_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;
		}
	}
}
Ejemplo n.º 13
0
uint8_t*
as_command_write_bin(uint8_t* begin, uint8_t operation_type, const as_bin* bin, as_buffer* buffer)
{
	uint8_t* p = begin + AS_OPERATION_HEADER_SIZE;
	const char* name = bin->name;

	// Copy string, but do not transfer null byte.
	while (*name) {
		*p++ = *name++;
	}
	uint8_t name_len = p - begin - AS_OPERATION_HEADER_SIZE;
	as_val* val = (as_val*)bin->valuep;
	uint32_t val_len;
	uint8_t val_type;
	
	switch (val->type) {
		default:
		case AS_NIL: {
			val_len = 0;
			val_type = AS_BYTES_UNDEF;
			break;
		}
		case AS_INTEGER: {
			as_integer* v = as_integer_fromval(val);
			*(uint64_t*)p = cf_swap_to_be64(v->value);
			p += 8;
			val_len = 8;
			val_type = AS_BYTES_INTEGER;
			break;
		}
		case AS_DOUBLE: {
			as_double* v = as_double_fromval(val);
			*(double*)p = cf_swap_to_big_float64(v->value);
			p += 8;
			val_len = 8;
			val_type = AS_BYTES_DOUBLE;
			break;
		}
		case AS_STRING: {
			as_string* v = as_string_fromval(val);
			// v->len should have been already set by as_command_value_size().
			memcpy(p, v->value, v->len);
			p += v->len;
			val_len = (uint32_t)v->len;
			val_type = AS_BYTES_STRING;
			break;
		}
		case AS_GEOJSON: {
			// We send a cellid placeholder so we can fill in points
			// in place on the server w/o changing object size.

			as_geojson* v = as_geojson_fromval(val);
			// v->len should have been already set by as_command_value_size().

			// as_particle_geojson_mem::flags
			*p++ = 0;

			// as_particle_geojson_mem::ncells
			*(uint16_t *) p = cf_swap_to_be16(0);
			p += sizeof(uint16_t);
			
			// placeholder cellid
			// THIS LOOP EXECUTES 0 TIMES (still, it belongs here ...)
			for (int ii = 0; ii < 0; ++ii) {
				*(uint64_t *) p = cf_swap_to_be64(0);
				p += sizeof(uint64_t);
			}

			// json data itself
			memcpy(p, v->value, v->len);
			p += v->len;

			val_len = (uint32_t)(1 + 2 + (0 * 8) + v->len);
			val_type = AS_BYTES_GEOJSON;
			break;
		}
		case AS_BYTES: {
			as_bytes* v = as_bytes_fromval(val);
			memcpy(p, v->value, v->size);
			p += v->size;
			val_len = v->size;
			// Note: v->type must be a blob type (AS_BYTES_BLOB, AS_BYTES_JAVA, AS_BYTES_PYTHON ...).
			// Otherwise, the particle type will be reassigned to a non-blob which causes a
			// mismatch between type and value.
			val_type = v->type;
			break;
		}
		case AS_LIST: {
			memcpy(p, buffer->data, buffer->size);
			p += buffer->size;
			val_len = buffer->size;
			val_type = AS_BYTES_LIST;
			cf_free(buffer->data);
			break;
		}
		case AS_MAP: {
			memcpy(p, buffer->data, buffer->size);
			p += buffer->size;
			val_len = buffer->size;
			val_type = AS_BYTES_MAP;
			cf_free(buffer->data);
			break;
		}
	}
	*(uint32_t*)begin = cf_swap_to_be32(name_len + val_len + 4);
	begin += 4;
	*begin++ = operation_type;
	*begin++ = val_type;
	*begin++ = 0;
	*begin++ = name_len;
	return p;
}
Ejemplo n.º 14
0
uint8_t*
as_command_write_bin(uint8_t* begin, uint8_t operation_type, const as_bin* bin, as_buffer* buffer)
{
    uint8_t* p = begin + AS_OPERATION_HEADER_SIZE;
    const char* name = bin->name;

    // Copy string, but do not transfer null byte.
    while (*name) {
        *p++ = *name++;
    }
    uint8_t name_len = p - begin - AS_OPERATION_HEADER_SIZE;
    as_val* val = (as_val*)bin->valuep;
    uint32_t val_len;
    uint8_t val_type;

    switch (val->type) {
    default:
    case AS_NIL: {
        val_len = 0;
        val_type = AS_BYTES_UNDEF;
        break;
    }
    case AS_INTEGER: {
        as_integer* v = as_integer_fromval(val);
        *(uint64_t*)p = cf_swap_to_be64(v->value);
        p += 8;
        val_len = 8;
        val_type = AS_BYTES_INTEGER;
        break;
    }
    case AS_DOUBLE: {
        as_double* v = as_double_fromval(val);
        *(double*)p = cf_swap_to_big_float64(v->value);
        p += 8;
        val_len = 8;
        val_type = AS_BYTES_DOUBLE;
        break;
    }
    case AS_STRING: {
        as_string* v = as_string_fromval(val);
        // v->len should have been already set by as_command_value_size().
        memcpy(p, v->value, v->len);
        p += v->len;
        val_len = (uint32_t)v->len;
        val_type = AS_BYTES_STRING;
        break;
    }
    case AS_BYTES: {
        as_bytes* v = as_bytes_fromval(val);
        memcpy(p, v->value, v->size);
        p += v->size;
        val_len = v->size;
        // Note: v->type must be a blob type (AS_BYTES_BLOB, AS_BYTES_JAVA, AS_BYTES_PYTHON ...).
        // Otherwise, the particle type will be reassigned to a non-blob which causes a
        // mismatch between type and value.
        val_type = v->type;
        break;
    }
    case AS_LIST: {
        memcpy(p, buffer->data, buffer->size);
        p += buffer->size;
        val_len = buffer->size;
        val_type = AS_BYTES_LIST;
        break;
    }
    case AS_MAP: {
        memcpy(p, buffer->data, buffer->size);
        p += buffer->size;
        val_len = buffer->size;
        val_type = AS_BYTES_MAP;
        break;
    }
    }
    *(uint32_t*)begin = cf_swap_to_be32(name_len + val_len + 4);
    begin += 4;
    *begin++ = operation_type;
    *begin++ = val_type;
    *begin++ = 0;
    *begin++ = name_len;
    return p;
}
Ejemplo n.º 15
0
/*
 * Internal Function: Entry function from UDF code path to send
 * 					  success result to the caller. Performs
 * 					  value translation.
 */
void
send_result(as_result * res, udf_call * call, void *udata)
{
	// The following "no-op" line serves to quiet the compiler warning of an
	// otherwise unused variable.
	udata = udata;
	as_val * v = res->value;
	if ( res->is_success ) {

		if ( cf_context_at_severity(AS_UDF, CF_DETAIL) ) {
			char * str = as_val_tostring(v);
			cf_detail(AS_UDF, "SUCCESS: %s", str);
			cf_free(str);
		}

		if ( v != NULL ) {
			switch( as_val_type(v) ) {
				case AS_NIL:
				{
					send_success(call, AS_PARTICLE_TYPE_NULL, NULL, 0);
					break;
				}
				case AS_BOOLEAN:
				{
					as_boolean * b = as_boolean_fromval(v);
					int64_t bi = as_boolean_tobool(b) == true ? 1 : 0;
					send_success(call, AS_PARTICLE_TYPE_INTEGER, &bi, 8);
					break;
				}
				case AS_INTEGER:
				{
					as_integer * i = as_integer_fromval(v);
					int64_t ri = as_integer_toint(i);
					send_success(call, AS_PARTICLE_TYPE_INTEGER, &ri, 8);
					break;
				}
				case AS_STRING:
				{
					// this looks bad but it just pulls the pointer
					// out of the object
					as_string * s = as_string_fromval(v);
					char * rs = (char *) as_string_tostring(s);
					send_success(call, AS_PARTICLE_TYPE_STRING, rs, as_string_len(s));
					break;
				}
				case AS_BYTES:
				{
					as_bytes * b = as_bytes_fromval(v);
					uint8_t * rs = as_bytes_get(b);
					send_success(call, AS_PARTICLE_TYPE_BLOB, rs, as_bytes_size(b));
					break;
				}
				case AS_MAP:
				case AS_LIST:
				{
					as_buffer buf;
					as_buffer_init(&buf);

					as_serializer s;
					as_msgpack_init(&s);

					int res = as_serializer_serialize(&s, v, &buf);

					if (res != 0) {
						const char * error = "Complex Data Type Serialization failure";
						cf_warning(AS_UDF, "%s (%d)", (char *)error, res);
						as_buffer_destroy(&buf);
						send_cdt_failure(call, AS_PARTICLE_TYPE_STRING, (char *)error, strlen(error));
					}
					else {
						// Do not use this until after cf_detail_binary() can accept larger buffers.
						// cf_detail_binary(AS_UDF, buf.data, buf.size, CF_DISPLAY_HEX_COLUMNS, 
						// "serialized %d bytes: ", buf.size);
						send_success(call, to_particle_type(as_val_type(v)), buf.data, buf.size);
						// Not needed stack allocated - unless serialize has internal state
						// as_serializer_destroy(&s);
						as_buffer_destroy(&buf);
					}

					break;
				}
				default:
				{
					cf_debug(AS_UDF, "SUCCESS: VAL TYPE UNDEFINED %d\n", as_val_type(v));
					send_success(call, AS_PARTICLE_TYPE_STRING, NULL, 0);
					break;
				}
			}
		} else {
			send_success(call, AS_PARTICLE_TYPE_NULL, NULL, 0);
		}
	} else { // Else -- NOT success
		as_string * s   = as_string_fromval(v);
		char *      rs  = (char *) as_string_tostring(s);

		cf_debug(AS_UDF, "FAILURE when calling %s %s %s", call->filename, call->function, rs);
		send_udf_failure(call, AS_PARTICLE_TYPE_STRING, rs, as_string_len(s));
	}
}
uint32_t
string_asval_wire_size(const as_val *val)
{
	return as_string_len(as_string_fromval(val));
}
Ejemplo n.º 17
0
/**
 *	Get specified bin's value as an as_string.
 *	as_string * value = as_record_get_string(rec, "bin");
 *	@param rec 	- the record containing the bin
 *	@param name 	- the name of the bin
 *	@return the value if it exists, otherwise NULL.
 */
as_string * as_record_get_string(const as_record * rec, const as_bin_name name)
{
	return as_string_fromval((as_val *) as_record_get(rec, name));
}
Ejemplo n.º 18
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;
}
Ejemplo n.º 19
0
/**
 *	Get specified bin's value as an NULL terminated string.
 *	char * value = as_record_get_str(rec, "bin");
 *	@param rec 	- the record containing the bin
 *	@param name 	- the name of the bin
 *	@return the value if it exists, otherwise NULL.
 */
char * as_record_get_str(const as_record * rec, const as_bin_name name) 
{
	as_string * val = as_string_fromval((as_val *) as_record_get(rec, name));
	return val ? as_string_tostring(val) : NULL;
}
Ejemplo n.º 20
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()
uint32_t
string_size_from_asval(const as_val *val)
{
	return (uint32_t)(sizeof(string_mem) + as_string_len(as_string_fromval(val)));
}