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); }
// 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; }