Example #1
0
int test_operate(cl_cluster *clc)
{
	cl_object key;
	cl_operation ops[3];
	cl_rv rv;
	
	citrusleaf_object_init_str(&key, myKey);
	strcpy(&ops[0].bin.bin_name[0],bin1);
	strcpy(&ops[1].bin.bin_name[0],bin2);
	strcpy(&ops[2].bin.bin_name[0],bin3);
	citrusleaf_object_init(&ops[0].bin.object);
	citrusleaf_object_init_int(&ops[1].bin.object, 2);
	citrusleaf_object_init_blob(&ops[2].bin.object, blobData2, strlen(blobData2)+1);
	
	ops[0].op = CL_OP_READ;
	ops[1].op = CL_OP_INCR;
	ops[2].op = CL_OP_WRITE;
	

	rv = citrusleaf_operate(clc, ns, myset, &key, &ops[0], 3, NULL, false, NULL);
	if( rv != CITRUSLEAF_OK ){
		printf(" TEST FAILED - go-right case of Operate is failing with %d\n", rv);
		return -1;
	}
	// and look at the value we read...
	if( strcmp(ops[0].bin.object.u.str, strData) ){
		printf( "TEST FAILED - Operate did not read back correct data! %s, %s\n", ops[0].bin.object.u.str, strData);
		return -1;
	}

	// and release that value...
	citrusleaf_object_free(&ops[0].bin.object);

	// now read the values back.
	ops[0].op = CL_OP_READ;
	ops[1].op = CL_OP_READ;
	ops[2].op = CL_OP_READ;
	
	citrusleaf_object_init(&ops[0].bin.object);
	citrusleaf_object_init(&ops[1].bin.object);
	citrusleaf_object_init(&ops[2].bin.object);


	rv = citrusleaf_operate(clc, ns, myset, &key, &ops[0], 3, NULL ,false, NULL);
	if( rv != CITRUSLEAF_OK ){
		printf(" TEST FAILED - go-right case of Operate is failing with %d\n", rv);
		return -1;
	}

	// check the values...
	if( strcmp(ops[0].bin.object.u.str, strData) ){
		printf(" TEST FAILED - did not read back the same string\n");
		return -1;
	}

	if( ops[1].bin.object.u.i64 != intData+2 ){
		printf(" TEST FAILED - did not read back correct int %lu %lu\n", ops[1].bin.object.u.i64, intData+2);
		return -1;
	}

	if( strcmp(ops[2].bin.object.u.blob, blobData2 ) ){
		printf(" TEST FAILED - did not read back blob correctly %s, %s\n", (char *)ops[2].bin.object.u.blob, blobData2);
		return -1;
	}

	// and free them all...
	citrusleaf_object_free(&ops[0].bin.object);	
	citrusleaf_object_free(&ops[1].bin.object);	
	citrusleaf_object_free(&ops[2].bin.object);
	
	// what happens if I request something that doesn't exist?  // XXX - should do this elsewhere...
/*	strcpy(&ops[0].bin.bin_name[0], "doesnt exist");
	rv = citrusleaf_operate(clc, mySet, myKey, &ops[3], 3, NULL );
*/		

	return 0;	
}
/**
 *	Lookup a record by key, then perform specified operations.
 *
 *	~~~~~~~~~~{.c}
 *		as_key key;
 *		as_key_init(&key, "ns", "set", "key");
 *
 *		as_operations ops;
 *		as_operations_inita(&ops,2);
 *		as_operations_append_int64(&ops, AS_OPERATOR_INCR, "bin1", 456);
 *		as_operations_append_str(&ops, AS_OPERATOR_APPEND, "bin1", "def");
 *
 *		if ( aerospike_key_remove(&as, &err, NULL, &key, &ops) != AEROSPIKE_OK ) {
 *			fprintf(stderr, "error(%d) %s at [%s:%d]", err.code, err.message, err.file, err.line);
 *		}
 *	~~~~~~~~~~
 *	
 *	@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 ops			The operations to perform on the record.
 *	@param rec			The record to be populated with the data from AS_OPERATOR_READ operations.
 *
 *	@return AEROSPIKE_OK if successful. Otherwise an error.
 */
as_status aerospike_key_operate(
	aerospike * as, as_error * err, const as_policy_operate * policy, 
	const as_key * key, const as_operations * ops,
	as_record ** rec)
{
	// we want to reset the error so, we have a clean state
	as_error_reset(err);
	
	// resolve policies
	as_policy_operate p;
	as_policy_operate_resolve(&p, &as->config.policies, policy);

	cl_write_parameters wp;
	aspolicyoperate_to_clwriteparameters(&p, ops, &wp);

	uint32_t 		gen = 0;
	uint32_t 		ttl = 0;
	int 			n_operations = ops->binops.size;
	cl_operation * 	operations = (cl_operation *) alloca(sizeof(cl_operation) * n_operations);
	int				n_read_ops = 0;
	as_bin_name *	read_op_bins = alloca(sizeof(as_bin_name) * n_operations);

	for(int i=0; i<n_operations; i++) {
		cl_operation * clop = &operations[i];
		as_binop * op = &ops->binops.entries[i];

		// Length check already done on as_bin name length. For performance we
		// we'll leave out this down-size check since this is a temporary shim
		// and we know the CL and AS limits are the same...
//		if ( strlen(op->bin.name) > CL_BINNAME_SIZE - 1 ) {
//			return as_error_update(err, AEROSPIKE_ERR_PARAM, "bin name too long: %s", op->bin.name);
//		}

		strcpy(clop->bin.bin_name, op->bin.name);
		clop->op = (cl_operator)op->op;

		// Collect bin names that are read.
		if (op->op == AS_OPERATOR_READ) {
			strcpy(read_op_bins[n_read_ops++], op->bin.name);
		}

		asbinvalue_to_clobject(op->bin.valuep, &clop->bin.object);
	}

	cl_rv rc = CITRUSLEAF_OK;

	switch ( p.key ) {
		case AS_POLICY_KEY_DIGEST: {
			as_digest * digest = as_key_digest((as_key *) key);
			rc = citrusleaf_operate_digest(as->cluster, key->ns, key->set, (cf_digest *) digest->value,
					operations, n_operations, &wp, &gen, &ttl);
			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 = citrusleaf_operate(as->cluster, key->ns, key->set, &okey, (cf_digest*)digest->value,
					operations, n_operations, &wp, &gen, &ttl);
			break;
		}
		default: {
			// ERROR CASE
			break;
		}
	}

	if ( n_read_ops != 0 && rc == CITRUSLEAF_OK && rec != NULL ) {
		as_record * r = *rec;
		if ( r == NULL ) {
			r = as_record_new(0);
		}
		if ( r->bins.entries == NULL ) {
			r->bins.capacity = n_read_ops;
			r->bins.size = 0;
			r->bins.entries = malloc(sizeof(as_bin) * n_read_ops);
			r->bins._free = true;
		}
		r->gen = (uint16_t) gen;
		r->ttl = ttl;

		// This works around an existing client bug where the data returned for
		// a read operation is stored in the first bin struct with that bin
		// name, not necessarily the bin struct corresponding to the read.
		for (int i = 0; i < n_read_ops; i++) {
			for (int j = 0; j < n_operations; j++) {
				if (strcmp(read_op_bins[i], operations[j].bin.bin_name) == 0) {
					clbin_to_asrecord(&operations[j].bin, r);
					citrusleaf_object_free(&operations[j].bin.object);
					break;
				}
			}
		}

		*rec = r;
	}

	return as_error_fromrc(err,rc);
}