Example #1
0
int test_unique(cl_cluster *clc)
{
	cl_object key;
	cl_object key2;
	cl_bin    bin;
	cl_rv     rv;
	cl_write_parameters cl_wp;

	citrusleaf_object_init_str(&key, myKey);
	citrusleaf_object_init_str(&key2, myKey2);
	strcpy(&bin.bin_name[0],bin1);
	citrusleaf_object_init_str(&bin.object, strData2);

	cl_write_parameters_set_default(&cl_wp);
	cl_wp.unique = 1;

	rv = citrusleaf_put(clc, ns, myset, &key, &bin, 1, &cl_wp);
	if( rv != CITRUSLEAF_FAIL_KEY_EXISTS ){
		printf(" TEST FAILED - test unique: should return key exists, returns %d\n", rv);
		return -1;
	}

	rv = citrusleaf_put(clc, ns, myset, &key2, &bin, 1, &cl_wp);
	if( rv != CITRUSLEAF_OK ){
		printf(" TEST FAILED - test unique: value should have been able to be written, actual value %d\n",rv);
		return -1;
	}
	
	return 0;
}
int
write_new_value(uint32_t key, cl_object *key_o, cf_digest *d)
{
	uint64_t new_value_int;
	do {
		new_value_int = rand_64();
	} while (new_value_int == VALUE_UNINIT || new_value_int == VALUE_DELETED);
	
	g_config.values[key] = new_value_int;
	char new_value_str[g_config.value_len+1];
	my_itoa(new_value_str, new_value_int, g_config.value_len); 
	
	cl_bin values[1];
	strcpy(values[0].bin_name, g_config.bin);
	citrusleaf_object_init_str(&values[0].object, new_value_str);

	cl_write_parameters cl_w_p;	
	cl_write_parameters_set_default(&cl_w_p);
	cl_w_p.timeout_ms = g_config.timeout_ms;
	
	int rv;
	rv = citrusleaf_put(g_config.asc, g_config.ns, g_config.set, key_o, values, 1, &cl_w_p);
	if (rv != 0) {
		fprintf(stderr, "aerospike put returned error %d, fail digest %"PRIx64"\n",rv, *(uint64_t *)d);
		if (g_config.strict)
			return(-1);
	}
	
	citrusleaf_object_init(&values[0].object);
	
	rv = citrusleaf_verify(g_config.asc, g_config.ns, g_config.set, key_o, values, 1, g_config.timeout_ms, NULL);
	if (rv != 0) {
		fprintf(stderr, "aerospike get returned error %d digest %"PRIx64"\n",rv, *(uint64_t *)d);
		if (g_config.strict)
			return(-1);
	}

	// test!
	if (values[0].object.type != CL_STR) {
		fprintf(stderr, "read value has wrong type: expect string (3) got %d, fail digest %"PRIx64"\n",(int)values[0].object.type, *(uint64_t *)d);
		if (g_config.strict)
			return(-1);
	}
	if (strcmp(values[0].object.u.str, new_value_str) != 0) {
		fprintf(stderr, "read value does not match set value. digest %"PRIx64"\n", *(uint64_t *)d);
		fprintf(stderr, "  expecting: %s\n",new_value_str);
		fprintf(stderr, "  got: %s\n",values[0].object.u.str);
		if (g_config.strict)
			return( -1);
	}
	
	citrusleaf_object_free(&values[0].object);
	
	atomic_int_add(g_config.read_counter, 1);
	atomic_int_add(g_config.write_counter, 1);

	
	return(0);
}
Example #3
0
// This is a read-modify-write test. We read the data and the generation count, and 
// then write the data using varous wp parameters
int read_mod_write(cl_cluster *clc)
{
	cl_object key;
	cl_bin    bin;
	cl_rv     rv;
	uint32_t  gen_count;

	citrusleaf_object_init_str(&key, myKey);
	strcpy(&bin.bin_name[0],bin1);
	citrusleaf_object_init(&bin.object);
	rv = citrusleaf_get(clc, ns, myset, &key, &bin, 1, 0, &gen_count);

	if( rv != CITRUSLEAF_OK ){
		printf(" TEST FAILED - Get returns value %d\n", rv);
		return -1;
	}

	// reuse old bin - must free memory allocated by system first
	citrusleaf_object_free(&bin.object); // check - does free reset the free pointer? XXX
	if( bin.object.free ){
		printf(" TEST FAILED - free pointer not reset on object_free \n");
		return -1;
	}
	citrusleaf_object_init_str(&bin.object,strData2); 
	cl_write_parameters cl_wp;
	cl_write_parameters_set_default(&cl_wp);
	cl_write_parameters_set_generation(&cl_wp, gen_count);

	// now attempt to write with the same gen count - should work just fine
	citrusleaf_object_init_str(&bin.object, strData2);
	rv = citrusleaf_put(clc, ns, myset, &key, &bin, 1, &cl_wp);

	if( rv != CITRUSLEAF_OK ){
		printf(" TEST FAILED - put with gen count fails!\n");
		return -1;
	} 

	// now attempt to write again - gen count on server should have changed!
	citrusleaf_object_init_str(&bin.object, "badData");
	rv = citrusleaf_put(clc, ns, myset, &key, &bin, 1, &cl_wp);
	if( rv != CITRUSLEAF_FAIL_GENERATION ){
		printf(" TEST FAILED - generation count should fail, actual return value is %d\n", rv);
		return -1;
	}

	// check that value has not changed
	citrusleaf_object_init(&bin.object);
	uint32_t new_gen;
	rv = citrusleaf_get(clc, ns, myset, &key, &bin, 1,0, &new_gen);
	if( rv != CITRUSLEAF_OK ){
		printf(" TEST FAILED - get in rmw is failing\n");
		return -1;
	}

	if( strcmp(bin.object.u.str, strData2) ){
		printf(" TEST FAILED - data on server changes despite generation count!!\n");
		return -1;
	}
	citrusleaf_object_free(&bin.object);


	// one more time - use the generation gt thing...
	cl_write_parameters_set_default(&cl_wp);
	cl_write_parameters_set_generation_gt(&cl_wp, gen_count+2);

	citrusleaf_object_init_str(&bin.object, strData);
	rv = citrusleaf_put(clc, ns, myset, &key, &bin, 1, &cl_wp);

	if( rv != CITRUSLEAF_OK ){
		printf(" TEST FAILED - put with gen count gt fails! err %d gen count %d\n", rv, gen_count);
		return -1;
	} 

	// check that value is correct - and get the new gen_count
	citrusleaf_object_init(&bin.object);
	rv = citrusleaf_get(clc, ns, myset, &key, &bin, 1, 0, &gen_count);
	if( rv != CITRUSLEAF_OK ){
		printf(" TEST FAILED - get in rmw is failing\n");
		return -1;
	}

	if( strcmp(bin.object.u.str, strData) ){
		printf(" TEST FAILED - data on server changes despite generation count!!\n");
		return -1;
	}
	citrusleaf_object_free(&bin.object);

	// now attempt to write again - gen count on server should have changed!
	citrusleaf_object_init_str(&bin.object, "badData");
	cl_write_parameters_set_default(&cl_wp);
	cl_write_parameters_set_generation_gt(&cl_wp, gen_count);
	rv = citrusleaf_put(clc, ns, myset, &key, &bin, 1, &cl_wp);
	if( rv != CITRUSLEAF_FAIL_GENERATION ){
		printf(" TEST FAILED - generation count should fail, actual return value is %d\n", rv);
		return -1;
	}

	// check that value has not changed
	citrusleaf_object_init(&bin.object);
	rv = citrusleaf_get(clc, ns, myset, &key, &bin, 1, 0, NULL);
	if( rv != CITRUSLEAF_OK ){
		printf(" TEST FAILED - get in rmw is failing\n");
		return -1;
	}

	if( strcmp(bin.object.u.str, strData) ){
		printf(" TEST FAILED - data on server changes despite generation count!!\n");
		return -1;
	}

	// at the end of this function, bin1 is strdata
	return 0;
}
int
do_example(config *c)
{
	int rv;
	
	// Put some test values
	cl_object o_key;
	citrusleaf_object_init_str(&o_key, "example_key");
	cl_bin values[2];
	strcpy(values[0].bin_name, "test_bin_one");
	citrusleaf_object_init_str(&values[0].object, "example_value_one");
	strcpy(values[1].bin_name, "test_bin_two");
	citrusleaf_object_init_int(&values[1].object, 0xDEADBEEF);
	
	// set a non-default write parameter
	cl_write_parameters cl_wp;
	cl_write_parameters_set_default(&cl_wp);
	cl_wp.timeout_ms = 1000;
	
	if (0 != (rv = citrusleaf_put(c->asc, c->ns, c->set, &o_key, values, 2, &cl_wp))) {
		fprintf(stderr, "citrusleaf put failed: error %d\n",rv);
		return(-1);
	}
	fprintf(stderr, "citrusleaf put succeeded\n");
	
	// Get all the values in this key (enjoy the fine c99 standard)
	cl_bin *cl_v = 0;
	uint32_t generation;
	int 	cl_v_len;
	if (0 != (rv = citrusleaf_get_all(c->asc, c->ns, c->set, &o_key, &cl_v, &cl_v_len, c->timeout_ms, &generation))) {
		fprintf(stderr, "get after put failed, but there should be a key here - %d\n",rv);
		if (cl_v)	free(cl_v);
		return(-1);
	}
	fprintf(stderr, "get all returned %d bins\n",cl_v_len);
	for (int i=0;i<cl_v_len;i++) {
		fprintf(stderr, "%d:  bin %s ",i,cl_v[i].bin_name);
		switch (cl_v[i].object.type) {
			case CL_STR:
				fprintf(stderr, "type string: value %s\n", cl_v[i].object.u.str);
				break;
			case CL_INT:
				fprintf(stderr, "type int: value %"PRId64"\n",cl_v[i].object.u.i64);
				break;
			default:
				fprintf(stderr, "type unknown! (%d)\n",(int)cl_v[i].object.type);
				break;
		}
		// could have done this -- but let's free the objects in the bins later
		// citrusleaf_object_free(&cl_v[i].object);
	}
	if (cl_v)	{
		citrusleaf_bins_free(cl_v, cl_v_len);
		free(cl_v); // only one free for all bins
	}
	fprintf(stderr,"citrusleaf getall succeeded\n");
	
	// Delete the key you just set
	if (0 != (rv = citrusleaf_delete(c->asc, c->ns, c->set, &o_key, 0/*default write params*/))) {
		fprintf(stderr, "citrusleaf delete failed: error %d\n",rv);
		return(-1);
	}
	fprintf(stderr, "citrusleaf delete succeeded\n");
	
	return(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;
}