int test_batch(cl_cluster *clc) { cl_rv rv; cl_bin bins[3]; cl_object keys[2]; cf_digest digests[2]; char *userData = "foobar"; citrusleaf_object_init_str(&keys[0],myKey); citrusleaf_object_init_str(&keys[1],myKey2); citrusleaf_object_init(&bins[0].object); citrusleaf_object_init(&bins[1].object); citrusleaf_object_init(&bins[2].object); strcpy(&bins[0].bin_name[0], bin1); strcpy(&bins[1].bin_name[0], bin2); strcpy(&bins[2].bin_name[0], bin3); citrusleaf_calculate_digest(myset, &keys[0], &digests[0]); citrusleaf_calculate_digest(myset, &keys[1], &digests[1]); rv = citrusleaf_get_many_digest(clc, (char *)ns, digests, 2, bins, 3, false, batch_cb, userData); if( rv != CITRUSLEAF_OK ){ printf(" TEST FAILS - get many (batch) fails with %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); }
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; }
int main(int argc, char **argv){ cl_cluster *clc; cl_rv return_value; cl_object key1; cl_object key2; printf(" STARTING TESTS\n"); // initialize internal citrusleaf structures just once citrusleaf_init(); // Create a cluster with a particular starting host printf(" STARTING CLUSTER CREATION TEST .... \n"); clc = citrusleaf_cluster_create(); if (!clc){ printf("TEST FAILED: Could not create cluster object"); return(-1); } return_value = citrusleaf_cluster_add_host(clc, host, 3000, 1000); if( return_value != CITRUSLEAF_OK ){ printf("TEST FAILED - cannot connect to host\n"); return -1; } // XXX - need to do some info calls with a bigger cluster! printf(" DONE\n"); // set up the key. Create a stack object, set its value to a string cl_object key_obj; citrusleaf_object_init_str(&key_obj, myKey); // set up a specific bins to fetch // the response will be in this value cl_bin values[3]; strcpy( &values[0].bin_name[0], bin1 ); citrusleaf_object_init_str( &values[0].object, strData); strcpy( &values[1].bin_name[0], bin2); citrusleaf_object_init_int( &values[1].object, intData ); strcpy( &values[2].bin_name[0], bin3); citrusleaf_object_init_blob( &values[2].object, blobData, strlen(blobData)+1); printf("params to put are clc %p, ns %s, set %s, key %p, values %p\n", clc, ns, myset, &key_obj, values); return_value = citrusleaf_put(clc, ns, myset, &key_obj, values, 3, NULL); if( return_value != CITRUSLEAF_OK ){ printf(" TEST FAILS - INITIAL PUT FAILS, value is %d\n", return_value); return(-1); } citrusleaf_object_init(&values[0].object); citrusleaf_object_init(&values[1].object); citrusleaf_object_init(&values[2].object); return_value = citrusleaf_get(clc, ns, myset, &key_obj, values, 3, 0, NULL); switch (return_value) { case CITRUSLEAF_OK: if (values[0].object.type != CL_STR) { printf(" TEST FAILS - value has unexpected type %d\n",values[0].object.type); goto cleanup; } else if( strcmp(values[0].object.u.str, strData) ){ printf("TEST FAILS - WRITE DOES NOT RETURN WHAT WAS WRITTEN: %s, %s\n", values[0].object.u.str, strData); goto cleanup; } if (values[1].object.type != CL_INT) { printf(" TEST FAILS - value has unexpected type %d\n",values[1].object.type); goto cleanup; } else if( values[1].object.u.i64 != intData){ printf("TEST FAILS - WRITE DOES NOT RETURN WHAT WAS WRITTEN, %lu, %lu\n", values[1].object.u.i64, intData); goto cleanup; } if( values[2].object.type != CL_BLOB) { printf(" TEST FAILS - value has unexpected type %d\n",values[1].object.type); goto cleanup; }else if( strcmp(values[2].object.u.blob, blobData) ){ printf(" TEST FAILS - WRITE DOES NOT RETURN CORRECT BLOB DATA\n"); goto cleanup; } break; case CITRUSLEAF_FAIL_NOTFOUND: printf(" TEST FAILS - citrusleaf says that key does not exist\n"); goto cleanup; break; case CITRUSLEAF_FAIL_CLIENT: printf(" TEST FAILS - citrusleaf client error: local error\n"); goto cleanup; break; case CITRUSLEAF_FAIL_PARAMETER: printf(" TEST FAILS - citrusleaf - bad parameter passed in \n"); goto cleanup; break; case CITRUSLEAF_FAIL_TIMEOUT: printf(" TEST FAILS - citrusleaf - timeout on get\n"); goto cleanup; break; case CITRUSLEAF_FAIL_UNKNOWN: printf(" TEST _FAILS - citrusleaf - unknown server error\n"); goto cleanup; break; default : printf(" TEST_FAILS - error %d\n", return_value); goto cleanup; } // clean up the retrieved objects citrusleaf_object_free(&values[0].object); citrusleaf_object_free(&values[1].object); if( test_getall(clc) ) goto cleanup; if( read_mod_write(clc) ) goto cleanup; if( test_unique(clc) ) goto cleanup; if( test_operate(clc) ) goto cleanup; if( test_batch(clc) ) goto cleanup; printf("TEST SUCCESSFUL!\n"); cleanup: citrusleaf_object_init_str(&key1,myKey); citrusleaf_object_init_str(&key2,myKey2); citrusleaf_delete(clc, ns, myset, &key1, NULL); citrusleaf_delete(clc, ns, myset, &key2, NULL); // Clean up the cluster object citrusleaf_cluster_destroy(clc); // Clean up the unit citrusleaf_shutdown(); }
// 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; }
void * work_fn(void *gcc_is_ass) { // Forever, do { // Pick a key to use. Look it up to see if anyone else is using it. uint32_t key = rand_64() % g_config.n_keys; uint32_t die = rand_64() & 0x03; if (SHASH_OK == shash_put_unique(g_config.in_progress_hash, &key, 0) ) { cl_rv rv; // Make the key into a string char key_s[g_config.key_len+1]; my_itoa(key_s, key, g_config.key_len); // Make an cl_object that represents the key cl_object key_o; citrusleaf_object_init_str(&key_o, key_s); cf_digest d; citrusleaf_calculate_digest(g_config.set, &key_o, &d); if (VALUE_UNINIT == g_config.values[key]) { // simply set the value to something - can't really check anything because we don't know the state if (0 != write_new_value(key, &key_o, &d)) { if (g_config.strict) goto Fail; } atomic_int_add(g_config.key_counter, 1); } else if (VALUE_DELETED == g_config.values[key]) { // Shouldn't exist cl_bin *cl_v = 0; int cl_v_len; rv = citrusleaf_get_all(g_config.asc, g_config.ns, g_config.set, &key_o, &cl_v, &cl_v_len, g_config.timeout_ms, NULL); if (rv != CITRUSLEAF_FAIL_NOTFOUND) { fprintf(stderr, "Get after delete returned improper value when should be deleted %d key %s digest %"PRIx64"\n",rv,key_s, *(uint64_t *)&d); if (g_config.strict) goto Fail; } if (cl_v) free(cl_v); atomic_int_add(g_config.read_counter, 1); // did two ops here // write a new value if (die < 2) { if (0 != write_new_value(key, &key_o, &d)) { if (g_config.strict) goto Fail; } atomic_int_add(g_config.key_counter, 1); } } // Value is well known. Check to see that it's still right. else { cl_bin values[1]; strcpy(values[0].bin_name, g_config.bin); citrusleaf_object_init(&values[0].object); // Make string version of old value for checking char new_value_str[g_config.value_len+1]; my_itoa(new_value_str, g_config.values[key], g_config.value_len); citrusleaf_object_init_str(&values[0].object, new_value_str); 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, "Get returned improper value %d when should be set : key %d digest %"PRIx64"\n",rv,key, *(uint64_t *)&d); if (g_config.strict) goto Fail; goto V1; } // test! if (values[0].object.type != CL_STR) { fprintf(stderr, "read value has wrong type: expect string (3) got %d\n",(int)values[0].object.type); if (g_config.strict) return((void *)-1); } else if (strcmp(values[0].object.u.str, new_value_str) != 0) { fprintf(stderr, "read value does not match set value.\n"); fprintf(stderr, " expecting: %s\n",new_value_str); fprintf(stderr, " got: %s\n",values[0].object.u.str); if (g_config.strict) goto Fail; } citrusleaf_object_free(&values[0].object); atomic_int_add(g_config.read_counter, 1); // Delete, write new value, what's your pleasure? V1: if (die < 2) { if (0 != write_new_value(key, &key_o, &d)) { if (g_config.strict) return((void *)-1); } } // Delete! else if (die == 2) { rv = citrusleaf_delete_verify(g_config.asc, g_config.ns, g_config.set, &key_o, 0); if (rv != 0) { fprintf(stderr, "Delete returned improper value %d, fail: key %d digest %"PRIx64"\n",rv, key, *(uint64_t *)&d); if (g_config.strict) goto Fail; } cl_bin values[1]; strcpy(values[0].bin_name, g_config.bin); citrusleaf_object_init(&values[0].object); rv = citrusleaf_get(g_config.asc, g_config.ns, g_config.set, &key_o, values, 1, g_config.timeout_ms, NULL); if (rv != CITRUSLEAF_FAIL_NOTFOUND) { fprintf(stderr, "Get after delete returned improper value %d digest %"PRIx64"\n",rv, *(uint64_t *)&d); if (g_config.strict) goto Fail; } citrusleaf_object_free(&values[0].object); g_config.values[key] = VALUE_DELETED; atomic_int_add(g_config.read_counter, 1); // did two ops here atomic_int_add(g_config.delete_counter, 1); atomic_int_add(g_config.key_counter, -1); } } // remove my lock on this key shash_delete(g_config.in_progress_hash, &key); } } while (1); Fail: abort(); return((void *)-1); }
/** * Lookup a record by key, then return specified bins. * * @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 bins The bins to select. A NULL terminated array of NULL terminated strings. * @param rec The record to be populated with the data from request. * * @return AEROSPIKE_OK if successful. Otherwise an error. */ as_status aerospike_key_select( aerospike * as, as_error * err, const as_policy_read * policy, const as_key * key, const char * bins[], as_record ** rec) { // we want to reset the error so, we have a clean state as_error_reset(err); // resolve policies as_policy_read p; as_policy_read_resolve(&p, &as->config.policies, policy); uint32_t timeout = p.timeout == UINT32_MAX ? 0 : p.timeout; uint32_t gen = 0; uint32_t ttl = 0; int nvalues = 0; cl_bin * values = NULL; for (nvalues = 0; bins[nvalues] != NULL && bins[nvalues][0] != '\0'; nvalues++) ; values = (cl_bin *) alloca(sizeof(cl_bin) * nvalues); for ( int i = 0; i < nvalues; i++ ) { if ( strlen(bins[i]) > AS_BIN_NAME_MAX_LEN ) { return as_error_update(err, AEROSPIKE_ERR_PARAM, "bin name too long: %s", bins[i]); } strcpy(values[i].bin_name, bins[i]); citrusleaf_object_init(&values[i].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_get_digest(as->cluster, key->ns, (cf_digest *) digest->value, values, nvalues, timeout, &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_get(as->cluster, key->ns, key->set, &okey, (cf_digest*)digest->value, values, nvalues, timeout, &gen, &ttl); break; } default: { // ERROR CASE break; } } if ( 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 = nvalues; r->bins.size = 0; r->bins.entries = malloc(sizeof(as_bin) * nvalues); r->bins._free = true; } clbins_to_asrecord(values, nvalues, r); r->gen = (uint16_t) gen; r->ttl = ttl; *rec = r; } if ( values != NULL ) { // We are freeing the bins' objects, as opposed to bins themselves. citrusleaf_bins_free(values, nvalues); } return as_error_fromrc(err,rc); }