int lset_config_test(char * keystr, char * ldt_bin) { static char * meth = "lset_config_test()"; if( LSET_DEBUG ) { INFO(" [ENTER]:<%s:%s>:From %s", MOD, LDT, meth ); } int rc = 1; char * valstr; as_result * resultp; time_t cur_t; cur_t = time(NULL); cl_cluster * c = lset_g_config->asc; cl_object o_key; char * ns = lset_g_config->ns; char * set = lset_g_config->set; char * bname = ldt_bin; citrusleaf_object_init_str( &o_key, keystr ); //print config of lset rc = aerospike_lset_config( &resultp, c, ns, set, &o_key, bname, lset_g_config->timeout_ms); if ( rc == CITRUSLEAF_OK ) { valstr = as_val_tostring( resultp->value ); printf(" Config parameters:\n %s \n", valstr); } citrusleaf_object_free( &o_key ); return rc; }
int lset_create_test (char * keystr, char * ldt_bin ){ static char * meth = "lset_create_test()"; if( LSET_DEBUG ) { INFO(" [ENTER]:<%s:%s>:From %s", MOD, LDT, meth ); } cl_cluster * c = lset_g_config->asc; cl_object o_key; char * ns = lset_g_config->ns; char * set = lset_g_config->set; char * bname = ldt_bin; char * create_package = "StandardList"; as_map *create_spec = as_hashmap_new(2); as_map_set(create_spec, (as_val *) as_string_new("Package", false), (as_val *) as_string_new( create_package, false)); citrusleaf_object_init_str( &o_key, keystr ); cl_rv rv = 0; rv = aerospike_lset_create( c, ns, set, &o_key, bname, create_spec, lset_g_config->timeout_ms); citrusleaf_object_free( &o_key ); as_val_destroy( create_spec ); return rv; }
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); }
/** * LSET Search WITH TRANSFORM TEST * For a single record, perform a series of SET Search. * and do a server side transform of the byte-packed data * Using the previously created record, repeatedly call stack search with * varying numbers of search counts. */ int lset_search_with_transform_test(char * keystr, char * ldt_bin, char * filter_function, as_list * fargs, int iterations ) { static char * meth = "lset_search_with_transform_test()"; if( LSET_DEBUG ) { INFO(" [ENTER]:<%s:%s>:From %s", MOD, LDT, meth ); } cl_rv rc = 0; INFO("[ENTER]:<%s:%s>: Iterations(%d) Key(%s) LSOBin(%s)", MOD, meth, iterations, keystr, ldt_bin ); cl_cluster * c = lset_g_config->asc; cl_object o_key; char * ns = lset_g_config->ns; char * set = lset_g_config->set; char * bname = ldt_bin; int vals_read; int misses; int errs; int i; as_result * resultp; INFO("[DEBUG]:<%s:%s>: Run search() iterations(%d)", MOD, meth, iterations ); // NOTE: Must FREE the result (resultp) for EACH ITERATION. int search_count = 2; // Soon -- set by Random Number citrusleaf_object_init_str( &o_key, keystr ); for ( i = 0; i < iterations ; i ++ ){ search_count++; rc = aerospike_lset_search_then_filter( &resultp, c, ns, set, &o_key, bname, search_count, filter_function, fargs, lset_g_config->timeout_ms); //lset_process_read_results( meth, rc, resultp, i, &vals_read, &misses, // &errs, search_count ); // Count up the reads (total) lset_g_config->read_vals_counter += search_count; lset_g_config->read_ops_counter += 1; } // end for each search iteration citrusleaf_object_free( &o_key ); INFO("[EXIT]:<%s:%s>: RC(%d)", MOD, meth, rc ); return rc; } // end lset_search_with_transform_test()
int lset_size_test(char * keystr, char * ldt_bin, uint32_t * size) { static char * meth = "lset_size_test()"; if( LSET_DEBUG ) { INFO(" [ENTER]:<%s:%s>:From %s", MOD, LDT, meth ); } int rc = 0; cl_cluster * c = lset_g_config->asc; cl_object o_key; char * ns = lset_g_config->ns; char * set = lset_g_config->set; char * bname = ldt_bin; citrusleaf_object_init_str( &o_key, keystr ); //check size of lset rc = aerospike_lset_size( size, c, ns, set, &o_key, bname, lset_g_config->timeout_ms); citrusleaf_object_free( &o_key ); return rc; }
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; }
int test_getall(cl_cluster *clc){ // set up the key. cl_object key_obj; citrusleaf_object_init_str(&key_obj, myKey); // create variables to return all values cl_bin *bins; int n_bins; // do the get citrusleaf_get_all(clc, ns, myset, &key_obj, &bins, &n_bins, 0, NULL); // check the contained values int haveStr = 0; int haveInt = 0; int haveBlob = 0; if( n_bins != 3 ){ printf(" TEST FAILED - get_all returns wrong number of bins, %d\n", n_bins); return -1; } for (int i=0;i<n_bins;i++) { printf (" bin %d name %s\n",i,bins[i].bin_name); if (bins[i].object.type == CL_STR){ if( strcmp(bins[i].object.u.str, strData) ){ printf(" TEST FAILED - str output of get_all does not match input\n"); return -1; } if( !bins[i].object.free ){ printf(" TEST FAILED - string allocated, but free pointer not set\n"); return -1; } haveStr = 1; }else if (bins[i].object.type == CL_INT ){ if( bins[i].object.u.i64 != intData ){ printf(" TEST FAILED - int output of get_all does not match input\n"); return -1; } if( bins[i].object.free ){ printf(" TEST FAILED - int output indicated as allocated but is not\n"); return -1; } haveInt = 1; }else if( bins[i].object.type == CL_BLOB ){ haveBlob = 1; if( strcmp(bins[i].object.u.blob, blobData) ){ printf(" TEST FAILED - blob output does not match input\n"); return -1; } // check - free pointer set? if( !bins[i].object.free ){ printf(" TEST FAILED - blob allocated, but free pointer not set\n"); return -1; } }else{ printf("TEST FAILED - unexpected bin type %d\n",(int) bins[i].object.type); return(-1); } } if( !(haveInt && haveStr && haveBlob ) ){ printf("TEST FAILED - not all values have correct types\n"); return -1; } // free the allocated memory for( int i=0; i<n_bins;i++) { citrusleaf_object_free(&bins[i].object); } free(bins); return 0; }
/** * LSET Insert WITH_TRANSFORM TEST * For a single record, perform a series of SET Insert of BYTE-PACKED data. * Create a new record, then repeatedly call stack insert. */ int lset_insert_with_transform_test(char * keystr, char * ldt_bin, int iterations) { static char * meth = "lset_insert_with_transform_test()"; if( LSET_DEBUG ) { INFO(" [ENTER]:<%s:%s>:From %s", MOD, LDT, meth ); } int rc = 0; int i; INFO("[ENTER]:<%s:%s>: It(%d) Key(%s) LSOBin(%s)", MOD, meth, iterations, keystr, ldt_bin ); // Abbreviate for simplicity. cl_cluster * c = lset_g_config->asc; char * ns = lset_g_config->ns; char * set = lset_g_config->set; char * bname = ldt_bin; cl_object o_key; // Set up the Creation Spec parameter -- mostly setting the Package // (which is the name for a canned set of settings). char * create_package = "ProdListValBinStore"; as_map *create_spec = as_hashmap_new(2); as_map_set(create_spec, (as_val *) as_string_new("Package", false), (as_val *) as_string_new( create_package, false)); INFO("[DEBUG]:<%s:%s>: Run insert_with_transform() iterations(%d)", MOD, meth, iterations ); citrusleaf_object_init_str( &o_key, keystr ); for ( i = 0; i < iterations; i++ ) { int val = i * 10; as_list * listp = as_arraylist_new( 5, 5 ); int64_t urlid = val + 1; as_list_add_integer( listp, urlid ); int64_t created = val + 2; as_list_add_integer( listp, created ); int64_t meth_a = val + 3; as_list_add_integer( listp, meth_a ); int64_t meth_b = val + 4; as_list_add_integer( listp, meth_b ); int64_t status = val + 5; as_list_add_integer( listp, status ); rc = aerospike_lset_create_and_insert( c, ns, set, &o_key, bname, (as_val *)listp, create_spec, lset_g_config->timeout_ms); if ( rc != CITRUSLEAF_OK ) { INFO("[ERROR]:<%s:%s>:LSO PUSH WITH TRANSFROM Error: i(%d) rc(%d)", MOD, meth, i, rc ); as_val_destroy ( listp ); goto cleanup; } // Count the write operation for stats gathering lset_g_config->write_ops_counter += 1; lset_g_config->write_vals_counter += 1; as_val_destroy( listp ); // must destroy every iteration. listp = NULL; } // end for cleanup: citrusleaf_object_free( &o_key ); as_val_destroy( create_spec ); return rc; } // end lset_insert_with_transform_test()
/** * LSET READ TEST * For a single record, perform a series of SET READS. * Using the previously created record, repeatedly call set read with * varying keys (value type is passed in via "format"). * NOTE: We must EXPLICITLY FREE the result, as it is a malloc'd * object that is handed to us. * + keystr: String Key to find the record * + ldt_bin: Bin Name of the LDT * + iterations: Number of iterations to run this test * + seed: Seed value for the random number pattern * + data_format: Type of value (number, string, list) */ int lset_search_test(char * keystr, char * ldt_bin, int iterations, int seed, int data_format ) { static char * meth = "lset_search_test()"; cl_rv rc = CITRUSLEAF_OK; as_result * resultp; char * valstr; // INFO("[ENTER]:<%s:%s>: Iterations(%d) Key(%s) LSOBin(%s) Sd(%d) DF(%d)", // MOD, meth, iterations, keystr, ldt_bin, seed, data_format); cl_cluster * c = lset_g_config->asc; cl_object o_key; char * ns = lset_g_config->ns; char * set = lset_g_config->set; char * bname = ldt_bin; int vals_read = 0; int misses = 0; int errs = 0; // INFO("[DEBUG]:<%s:%s>: Run search() iterations(%d)", MOD, meth, iterations ); as_val * valp ; srand( seed ); // NOTE: Must FREE the result for EACH ITERATION. citrusleaf_object_init_str( &o_key, keystr ); int iseed; if(iterations == 0) { rc = aerospike_lset_search( &resultp, c, ns, set, &o_key, bname, NULL, lset_g_config->timeout_ms); //printf("search result is %s\n", as_val_tostring(resultp->value)); if( resultp != NULL ) as_result_destroy( resultp ); } else { for ( int i = 0; i < iterations ; i ++ ){ iseed = i * 10; lset_generate_value( &valp, iseed, data_format ); // INFO("[DEBUG]:<%s:%s>: Peek(%d)", MOD, meth, iterations ); rc = aerospike_lset_search( &resultp, c, ns, set, &o_key, bname, valp, lset_g_config->timeout_ms); if(rc == CITRUSLEAF_OK) { rc = lset_process_read_results( meth, rc, resultp, i, &vals_read, &misses, &errs, valp); } //printf("compared result: exp-%s act-%s ",as_val_tostring(valp),as_val_tostring(resultp->value)); // Clean up -- release the result object if( resultp != NULL ) as_result_destroy( resultp ); // Count up the reads (total) if(rc == 0) { lset_g_config->read_vals_counter += 1; } lset_g_config->read_ops_counter += 1; } // end for each search iteration } citrusleaf_object_free( &o_key ); // INFO("[EXIT]:<%s:%s>: RC(%d)", MOD, meth, rc ); return rc; } // end lset_search_test()
/** * LSET INSERT TEST * For a single record, perform a series of SET insert. * Create a new record, then repeatedly call lset insert. * This should work for data that is a NUMBER, a STRING or a LIST. * Parms: * + keystr: String Key to find the record * + ldt_bin: Bin Name of the LDT * + iterations: Number of iterations to run this test * + seed: Seed value for the random number pattern * + data_format: Type of value (number, string, list) */ int lset_insert_test(char * keystr, char * ldt_bin, int iterations, int seed, int data_format ) { static char * meth = "lset_insert_test()"; if( LSET_DEBUG ) { INFO(" [ENTER]:<%s:%s>:From %s", MOD, LDT, meth ); } int rc = CITRUSLEAF_OK; int i; as_val *valp; time_t cur_t; cur_t = time(NULL); // INFO("[ENTER]:<%s:%s>: It(%d) Key(%s) LSOBin(%s) Seed(%d)", // MOD, meth, iterations, keystr, ldt_bin, seed); // We have two choices: We can create the LSO bin here, and then // do a bunch of inserts into it -- or we can just do the combined // "create_and_insert" insert, which upon reflection, is really the // most likely mode we'll be in. We'll choose the later. // Set up the Creation Spec parameter -- mostly setting the Package // (which is the name for a canned set of settings). char * create_package = "StandardList"; as_map *create_spec = as_hashmap_new(2); as_map_set(create_spec, (as_val *) as_string_new("Package", false), (as_val *) as_string_new( create_package, false)); cl_cluster * c = lset_g_config->asc; cl_object o_key; char * ns = lset_g_config->ns; char * set = lset_g_config->set; char * bname = ldt_bin; int iseed; //INFO("[DEBUG]:<%s:%s>: Run insert() iterations(%d)", MOD, meth, iterations ); citrusleaf_object_init_str( &o_key, keystr ); for ( i = 0; i < iterations; i++ ) { iseed = i * 10; lset_generate_value( &valp, iseed, data_format ); rc = aerospike_lset_create_and_insert( c, ns, set, &o_key, bname, valp, create_spec, lset_g_config->timeout_ms); if ( rc != CITRUSLEAF_OK ) { //INFO("[ERROR]:<%s:%s>:H Error: i(%d) rc(%d)", MOD, meth,i,rc ); as_val_destroy ( valp ); goto cleanup; } // Count the write operation for stats gathering lset_g_config->write_ops_counter += 1; lset_g_config->write_vals_counter += 1; as_val_destroy( valp ); // must destroy every iteration. valp = NULL; // unnecessary insurance } // end for cleanup: citrusleaf_object_free( &o_key ); as_val_destroy( create_spec ); return rc; } // end lset_insert_test()
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 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); }