/** * @brief Callback for batch_exists * * @param[in] results The results * @param[in] n number for resulsts * @param udata The user data * * @return true on success. Otherwise, an error occurred */ static bool batch_exists_callback(const as_batch_read * results, uint32_t n, VALUE return_data) { for (uint32_t i = 0; i < n; ++i) { if ( results[i].result != AEROSPIKE_OK ) continue; as_val * rec_val = (as_val *) results[i].key->valuep; VALUE ns = rb_str_new2(results[i].key->ns); VALUE set = rb_str_new2(results[i].key->set); VALUE val; switch ( as_val_type(rec_val) ) { case AS_INTEGER: { val = as_val_int_2_val(rec_val); break; } case AS_STRING: { val = as_val_str_2_val(rec_val); break; } } VALUE key; key = rb_funcall(rb_aero_Key, rb_intern("new"), 3, ns, set, val); rb_hash_aset(return_data, key, Qtrue); } return true; }
static int check_bin2(as_record * rec, scan_check * check) { as_val * bin = (as_val *) as_record_get(rec, "bin2"); if ( !bin ) { error("Expected a value in bin('%s'), but got null", "bin2"); return !(check->failed = true); } as_string * string = as_string_fromval(bin); if ( !string ) { error("Expected a string in bin('%s'), but got type %d", "bin2", as_val_type(bin)); return !(check->failed = true); } char * str = as_string_get(string); if ( !str ) { error("Expected a string value but it is NULL"); return !(check->failed = true); } // Check the string bin char expected[SET_STRSZ]; int64_t bin1 = as_record_get_int64(rec, "bin1", INT64_MIN); sprintf(expected, "str-%s-%" PRId64, rec->key.set[0] == '\0' ? "noset" : rec->key.set, bin1); if (strcmp(expected, str) != 0) { error("Expected '%s' in bin('%s'), but got '%s'", expected, "bin2", str); return !(check->failed = true); } return !(check->failed = false); }
static bool udf_arglist_foreach(const as_list * l, as_list_foreach_callback callback, void * context) { as_msg_field * field = (as_msg_field *) l->data; if ( field != NULL ) { as_unpacker unpacker; unpacker.buffer = (const unsigned char*)field->data; unpacker.length = as_msg_field_get_value_sz(field); unpacker.offset = 0; if ( unpacker.length == 0 ) return true; as_val* val = 0; int ret = as_unpack_val(&unpacker, &val); if (ret == 0 && as_val_type(val) == AS_LIST) { as_list_iterator list_iter; as_iterator* iter = (as_iterator*) &list_iter; as_list_iterator_init(&list_iter, (as_list*)val); while (as_iterator_has_next(iter)) { const as_val* v = as_iterator_next(iter); callback((as_val *) v, context); } as_iterator_destroy(iter); } as_val_destroy(val); return ret == 0; } return true; }
/* * Internal Function: Entry function from UDF code path to send * success result to the caller. Performs * value translation. */ void send_result(as_result * res, udf_call * call) { as_val * v = res->value; if ( res->is_success ) { if ( cf_context_at_severity(AS_UDF, CF_DETAIL) ) { char * str = as_val_tostring(v); cf_detail(AS_UDF, "SUCCESS: %s", str); cf_free(str); } send_success(call, v); } else { // Else -- NOT success if (as_val_type(v) == AS_STRING) { send_udf_failure(call, as_string_fromval(v)); } else { char lua_err_str[1024]; size_t len = (size_t)sprintf(lua_err_str, "%s:0: in function %s() - error() argument type not handled", call->def.filename, call->def.function); call->tr->result_code = AS_PROTO_RESULT_FAIL_UDF_EXECUTION; send_failure_str(call, lua_err_str, len); } } }
int as_msg_make_val_response_bufbuilder(const as_val *val, cf_buf_builder **bb_r, int val_sz, bool success) { int msg_sz = sizeof(as_msg); msg_sz += sizeof(as_msg_op) + val_sz; if (success) { msg_sz += strlen("SUCCESS"); // fake bin name } else { msg_sz += strlen("FAILURE"); // fake bin name } uint8_t *b; cf_buf_builder_reserve(bb_r, msg_sz, &b); // set up the header uint8_t *buf = b; as_msg *msgp = (as_msg *) buf; msgp->header_sz = sizeof(as_msg); msgp->info1 = 0; msgp->info2 = 0; msgp->info3 = 0; msgp->unused = 0; msgp->result_code = 0; // Default is OK msgp->generation = 0; msgp->record_ttl = 0; msgp->transaction_ttl = 0; msgp->n_fields = 0; // No Fields corresponding to aggregation response msgp->n_ops = 1; // only 1 bin as_msg_swap_header(msgp); buf += sizeof(as_msg); as_msg_op *op = (as_msg_op *)buf; buf += sizeof(as_msg_op); op->op = AS_MSG_OP_READ; if (success) { op->name_sz = strlen("SUCCESS"); memcpy(op->name, "SUCCESS", op->name_sz); } else { op->name_sz = strlen("FAILURE"); memcpy(op->name, "FAILURE", op->name_sz); } op->op_sz = 4 + op->name_sz; op->particle_type = to_particle_type(as_val_type(val)); op->version = 0; buf += op->name_sz; uint32_t psz = msg_sz - (buf - b); // size remaining in buffer, for safety as_val_tobuf(val, buf, &psz); if (psz == 0) { cf_warning(AS_PROTO, "particle to buf: could not copy data!"); } buf += psz; op->op_sz += psz; as_msg_swap_op(op); return(0); }
static int check_bin4(as_record * rec, scan_check * check) { as_val * bin = (as_val *) as_record_get(rec, "bin4"); if ( !bin ) { error("Expected a value in bin('%s'), but got null", "bin4"); return !(check->failed = true); } as_list * list = as_list_fromval(bin); if ( !list ) { error("Expected a list in bin('%s'), but got type %d", "bin4", as_val_type(bin)); return !(check->failed = true); } int sz = as_list_size(list); if ( sz < 3 ) { error("Expected list size of %d, but got %d", 3, sz); return !(check->failed = true); } for ( int i = 0; i < sz; i++ ) { as_val * val = as_list_get(list, i); if ( !val ) { error("Expecting value at %d, but got null", i); return !(check->failed = true); } as_integer * ival = as_integer_fromval(val); if ( !ival ) { error("Expecting integer at %d, but got type %d", i, as_val_type(val)); return !(check->failed = true); } } return !(check->failed = false); }
static int check_bin1(as_record * rec, scan_check * check) { as_val * bin = (as_val *) as_record_get(rec, "bin1"); if ( !bin ) { error("Expected a value in bin('%s'), but got null", "bin1"); return !(check->failed = true); } as_integer * integer = as_integer_fromval(bin); if ( !integer ) { error("Expected a integer in bin('%s'), but got type %d", "bin1", as_val_type(bin)); return !(check->failed = true); } return !(check->failed = false); }
char * as_boolean_val_tostring(const as_val * v) { if ( as_val_type(v) != AS_BOOLEAN ) return NULL; as_boolean * b = (as_boolean *) v; char * str = (char *) cf_malloc(sizeof(char) * 6); if (!str) return str; bzero(str,6); if ( b->value ) { strcpy(str,"true"); } else { strcpy(str,"false"); } return str; }
static bool check_bin3(as_record * rec, scan_check * check) { as_val * bin = (as_val *) as_record_get(rec, "bin3"); if ( !bin ) { error("Expected a value in bin('%s'), but got null", "bin3"); return !(check->failed = true); } as_map * map = as_map_fromval(bin); if ( !map ) { error("Expected a map in bin('%s'), but got type %d", "bin3", as_val_type(bin)); return !(check->failed = true); } int sz = as_map_size(map); if ( sz != 3 ) { error("Expected map size of %d, but got %d", 3, sz); return !(check->failed = true); } int64_t bin1 = as_record_get_int64(rec, "bin1", INT64_MIN); int64_t ival = 0; ival = as_stringmap_get_int64(map, "x"); if ( ival != bin1 ) { error("Expected map value '%s'=%ld, but got %ld", "x", bin1, ival); return !(check->failed = true); } ival = as_stringmap_get_int64(map, "y"); if ( ival != bin1+1 ) { error("Expected map value '%s'=%ld, but got %ld", "y", bin1+1, ival); return !(check->failed = true); } ival = as_stringmap_get_int64(map, "z"); if ( ival != bin1+2 ) { error("Expected map value '%s'=%ld, but got %ld", "z", bin1+2, ival); return !(check->failed = true); } return !(check->failed = false); }
static as_val *udf_arglist_get(const as_list * l, const uint32_t idx) { as_msg_field * field = (as_msg_field *) l->data; if ( field != NULL ) { as_unpacker unpacker; unpacker.buffer = (const unsigned char*)field->data; unpacker.length = as_msg_field_get_value_sz(field); unpacker.offset = 0; if ( unpacker.length == 0 ) return NULL; as_val* item = 0; as_val* val = 0; int ret = as_unpack_val(&unpacker, &val); if (ret == 0 && as_val_type(val) == AS_LIST) { item = as_list_get((as_list*)val, idx); } as_val_destroy(val); return item; } return NULL; }
/** * @brief Callback for batch_exists * * @param[in] results The results * @param[in] n number for resulsts * @param udata The user data * * @return true on success. Otherwise, an error occurred */ static bool batch_read_callback(const as_batch_read * results, uint32_t n, VALUE return_data) { for (uint32_t i = 0; i < n; ++i) { as_val * rec_val = (as_val *) results[i].key->valuep; VALUE ns = rb_str_new2(results[i].key->ns); VALUE set = rb_str_new2(results[i].key->set); VALUE val; switch ( as_val_type(rec_val) ) { case AS_INTEGER: { val = as_val_int_2_val(rec_val); break; } case AS_STRING: { val = as_val_str_2_val(rec_val); break; } } VALUE key = rb_funcall(rb_aero_Key, rb_intern("new"), 3, ns, set, val); if ( results[i].result == AEROSPIKE_OK ) { rb_hash_aset(return_data, key, record2hash(&results[i].record)); } else if ( results[i].result == AEROSPIKE_ERR_RECORD_NOT_FOUND ) { rb_hash_aset(return_data, key, Qnil); } else { VALUE ErrCodes = rb_const_get(rb_cObject, rb_intern("AerospikeC::ErrorCodes")); rb_hash_aset(return_data, key, rb_funcall(ErrCodes, rb_intern("new"), 1, INT2FIX(results[i].result))); } } return true; }
int main(int argc, char* argv[]) { // Parse command line arguments. if (! example_get_opts(argc, argv, EXAMPLE_BASIC_OPTS)) { exit(-1); } // Connect to the aerospike database cluster. aerospike as; example_connect_to_aerospike(&as); // Start clean. example_remove_test_record(&as); as_ldt lstack; // Create a large stack bin to use. No need to destroy as_ldt if using // as_ldt_init() on stack object. if (! as_ldt_init(&lstack, "mystack", AS_LDT_LSTACK, NULL)) { LOG("unable to initialize ldt"); example_cleanup(&as); exit(-1); } as_error err; // No need to destroy as_integer if using as_integer_init() on stack object. as_integer ival; as_integer_init(&ival, 123); // Push a few values onto the stack. if (aerospike_lstack_push(&as, &err, NULL, &g_key, &lstack, (const as_val*)&ival) != AEROSPIKE_OK) { LOG("first aerospike_lstack_push() returned %d - %s", err.code, err.message); example_cleanup(&as); exit(-1); } // No need to destroy as_string if using as_string_init() on stack object. as_string sval; as_string_init(&sval, "string stack value", false); if (aerospike_lstack_push(&as, &err, NULL, &g_key, &lstack, (const as_val*)&sval) != AEROSPIKE_OK) { LOG("second aerospike_lstack_push() returned %d - %s", err.code, err.message); example_cleanup(&as); exit(-1); } LOG("2 values pushed"); uint32_t n_elements = 0; // Look at the stack size right now. if (aerospike_lstack_size(&as, &err, NULL, &g_key, &lstack, &n_elements) != AEROSPIKE_OK) { LOG("aerospike_lstack_size() returned %d - %s", err.code, err.message); example_cleanup(&as); exit(-1); } if (n_elements != 2) { LOG("unexpected stack size %u", n_elements); example_cleanup(&as); exit(-1); } LOG("stack size confirmed to be %u", n_elements); as_ldt lstack2; as_ldt_init(&lstack2, "mystack", AS_LDT_LSTACK, NULL); uint32_t peek_count = 3; as_list* p_list = NULL; // Peek a few values back. if (aerospike_lstack_peek(&as, &err, NULL, &g_key, &lstack2, peek_count, &p_list) != AEROSPIKE_OK) { LOG("first aerospike_lstack_peek() returned %d - %s", err.code, err.message); as_list_destroy(p_list); example_cleanup(&as); exit(-1); } as_arraylist_iterator it; as_arraylist_iterator_init(&it, (const as_arraylist*)p_list); // See if the elements match what we expect. while (as_arraylist_iterator_has_next(&it)) { const as_val* p_val = as_arraylist_iterator_next(&it); char* p_str = as_val_tostring(p_val); LOG(" peek - type = %d, value = %s", as_val_type(p_val), p_str); free(p_str); } as_list_destroy(p_list); p_list = NULL; // Push 3 more items onto the stack. By using as_arraylist_inita() we avoid // some but not all internal heap usage, so we must call // as_arraylist_destroy(). as_arraylist vals; as_arraylist_inita(&vals, 3); as_arraylist_append_int64(&vals, 1000); as_arraylist_append_int64(&vals, 2000); as_arraylist_append_int64(&vals, 3000); if (aerospike_lstack_push_all(&as, &err, NULL, &g_key, &lstack, (const as_list*)&vals) != AEROSPIKE_OK) { LOG("aerospike_lstack_pushall() returned %d - %s", err.code, err.message); as_arraylist_destroy(&vals); example_cleanup(&as); exit(-1); } as_arraylist_destroy(&vals); LOG("3 more values pushed"); as_ldt_init(&lstack2, "mystack", AS_LDT_LSTACK, NULL); peek_count = 10; // Peek all the values back again. if (aerospike_lstack_peek(&as, &err, NULL, &g_key, &lstack2, peek_count, &p_list) != AEROSPIKE_OK) { LOG("second aerospike_lstack_peek() returned %d - %s", err.code, err.message); as_list_destroy(p_list); example_cleanup(&as); exit(-1); } // See if the elements match what we expect. as_arraylist_iterator_init(&it, (const as_arraylist*)p_list); while (as_arraylist_iterator_has_next(&it)) { const as_val* p_val = as_arraylist_iterator_next(&it); char* p_str = as_val_tostring(p_val); LOG(" peek - type = %d, value = %s", as_val_type(p_val), p_str); free(p_str); } as_list_destroy(p_list); // Set capacity for the lstack. if (aerospike_lstack_set_capacity(&as, &err, NULL, &g_key, &lstack, 10000) != AEROSPIKE_OK) { LOG("aerospike_lstack_set_capacity() returned %d - %s", err.code, err.message); example_cleanup(&as); exit(-1); } uint32_t cap_size = 0; // Get capacity from the lstack. if (aerospike_lstack_get_capacity(&as, &err, NULL, &g_key, &lstack, &cap_size) != AEROSPIKE_OK) { LOG("aerospike_lstack_get_capacity() returned %d - %s", err.code, err.message); example_cleanup(&as); exit(-1); } if (cap_size != 10000) { LOG("unexpected capacity size %u", cap_size); example_cleanup(&as); exit(-1); } // Destroy the lstack. if (aerospike_lstack_destroy(&as, &err, NULL, &g_key, &lstack) != AEROSPIKE_OK) { LOG("aerospike_lstack_destroy() returned %d - %s", err.code, err.message); example_cleanup(&as); exit(-1); } n_elements = 0; // See if we can still do any lstack operations. if (aerospike_lstack_size(&as, &err, NULL, &g_key, &lstack, &n_elements) == AEROSPIKE_OK) { LOG("aerospike_lstack_size() did not return error"); example_cleanup(&as); exit(-1); } // Cleanup and disconnect from the database cluster. example_cleanup(&as); LOG("lstack example successfully completed"); return 0; }
static bool scan_check_callback(const as_val * val, void * udata) { int i; // NULL is END OF SCAN if ( !val ) { return false; } scan_check * check = (scan_check *) udata; as_record * rec = as_record_fromval(val); if ( !rec ) { error("Expected a record, but got type %d", as_val_type(val)); return !(check->failed = true); } const char * set = rec->key.set[0] == '\0' ? NULL : rec->key.set; check->count++; // Find the number of unique threads spawned under the hood. // Note that the scan callback will be called in the thread context. // As the number of threads is same as node count, they will be limited. // A linear search is good enough for this. pthread_t cur_thread = pthread_self(); for (i=0; i<check->unique_tcount; i++) { if (check->threadids[i] == cur_thread) { break; } } // Found a new thread if (i == check->unique_tcount) { check->threadids[check->unique_tcount] = cur_thread; check->unique_tcount++; } // Check if we are getting the results only from the set the scan is triggered for // If scan is called with NULL set, all the recs will come. So, no checks in this case. if ( check->set ) { // Do the check only if the rec also have a setname if ( !set ) { error("Expected set '%s', but got set NULL", check->set); return !(check->failed = true); } else if ( strcmp(check->set, set) != 0) { error("Expected set '%s', but got set '%s'", check->set, set); return !(check->failed = true); } } // Check that we got the right number of bins int numbins = as_record_numbins(rec); if ( check->nobindata ) { if ( numbins != 0 ) { error("Expected 0 bins, but got %d", numbins); return !(check->failed = true); } return !(check->failed = false); } // only validate data if in sb_set1 or sb_set2 if ( check->set && strcmp(set, SET1) != 0 && strcmp(set, SET2) != 0 ) { return !(check->failed = false); } // validate bins int nbins = sizeof(check->bins) / sizeof(char *); for( int i = 0; check->bins[i] && i < nbins; i++ ) { char * bin = check->bins[i]; if ( strcmp(bin, "bin1") == 0 ) { if ( !check_bin1(rec, check) ) { error("Failed check of bin1"); return !(check->failed = true); } } else if ( strcmp(bin, "bin2") == 0 ) { if ( !check_bin2(rec, check) ) { error("Failed check of bin2"); return !(check->failed = true); } } else if ( strcmp(bin, "bin3") == 0 ) { if ( !check_bin3(rec, check) ) { error("Failed check of bin3"); return !(check->failed = true); } } else if ( strcmp(bin, "bin4") == 0 ) { if ( !check_bin4(rec, check) ) { error("Failed check of bin4"); return !(check->failed = true); } } else { error("Unknown bin %s", bin); return !(check->failed = true); } } return !(check->failed = false); }
/* * Internal function: udf_aerospike_setbin * * Parameters: * r -- udf_record to be manipulated * bname -- name of the bin to be deleted * val -- value to be updated with * * Return value: * 0 on success * -1 on failure * * Description: * The function sets the bin with the name * passed in as parameter to the value, passed as the third parameter. * Before updating the bin, it is checked if the value can fit in the storage * * Synchronization : object lock acquired by the transaction thread executing UDF. * Partition reservation takes place just before the transaction starts executing * ( look for as_partition_reserve_udf in thr_tsvc.c ) * * Callers: * udf_aerospike__apply_update_atomic * In this function, if it fails at the time of update, the record is set * to rollback all the updates till this point. The case where it fails in * rollback is not handled. * * Side Notes: * i. write_to_device will be set to true on a successful bin update. * If all the updates from udf_aerospike__apply_update_atomic (including this) are * successful, the record will be written to disk and reopened so that the rest of * sets of updates can be applied. * * ii. If put in sindex fails, we do not handle it. * * TODO make sure anything goes into setbin only if the bin value is * changed */ static const int udf_aerospike_setbin(udf_record * urecord, const char * bname, const as_val * val, bool is_hidden) { if (bname == NULL || bname[0] == 0 ) { cf_warning(AS_UDF, "no bin name supplied"); return -1; } uint8_t type = as_val_type(val); if (is_hidden && ((type != AS_MAP) && (type != AS_LIST))) { cf_warning(AS_UDF, "Hidden %d Type Not allowed", type); return -3; } size_t blen = strlen(bname); as_storage_rd * rd = urecord->rd; as_transaction *tr = urecord->tr; as_index_ref * index = urecord->r_ref; as_bin * b = as_bin_get(rd, (byte *)bname, blen); if ( !b && (blen > (AS_ID_BIN_SZ - 1 ) || !as_bin_name_within_quota(rd->ns, (byte *)bname, blen)) ) { // Can't write bin cf_warning(AS_UDF, "bin name %s too big. Bin not added", bname); return -1; } if ( !b ) { // See if there's a free one, the hope is you will always find the bin because // you have already allocated bin space before calling this function. b = as_bin_create(index->r, rd, (byte *)bname, blen, 0); if (!b) { cf_warning(AS_UDF, "ERROR: udf_aerospike_setbin: as_bin_create: bin not found, something went really wrong!"); return -1; } } SINDEX_BINS_SETUP(oldbin, 1); SINDEX_BINS_SETUP(newbin, 1); bool needs_sindex_delete = false; bool needs_sindex_put = false; bool needs_sindex_update = false; bool has_sindex = as_sindex_ns_has_sindex(rd->ns); if (has_sindex && (as_sindex_sbin_from_bin(rd->ns, as_index_get_set_name(rd->r, rd->ns), b, oldbin) == AS_SINDEX_OK)) { needs_sindex_delete = true; } // we know we are doing an update now, make sure there is particle data, // set to be 1 wblock size now @TODO! uint32_t pbytes = 0; int ret = 0; if (!rd->ns->storage_data_in_memory && !urecord->particle_data) { urecord->particle_data = cf_malloc(rd->ns->storage_write_block_size); urecord->cur_particle_data = urecord->particle_data; urecord->end_particle_data = urecord->particle_data + rd->ns->storage_write_block_size; } cf_detail(AS_UDF, "udf_setbin: bin %s type %d ", bname, type ); switch(type) { case AS_STRING: { as_string * v = as_string_fromval(val); byte * s = (byte *) as_string_tostring(v); size_t l = as_string_len(v); // Save for later. // cf_detail(AS_UDF, "udf_setbin: string: binname %s value is %s",bname,s); if ( !as_storage_bin_can_fit(rd->ns, l) ) { cf_warning(AS_UDF, "string: bin size too big"); ret = -1; break; } if (rd->ns->storage_data_in_memory) { as_particle_frombuf(b, AS_PARTICLE_TYPE_STRING, s, l, NULL, true); } else { pbytes = l + as_particle_get_base_size(AS_PARTICLE_TYPE_STRING); if ((urecord->cur_particle_data + pbytes) < urecord->end_particle_data) { as_particle_frombuf(b, AS_PARTICLE_TYPE_STRING, s, l, urecord->cur_particle_data, rd->ns->storage_data_in_memory); urecord->cur_particle_data += pbytes; } else { cf_warning(AS_UDF, "string: bin data size too big: pbytes %d" " pdata %p cur_part+pbytes %p pend %p", pbytes, urecord->particle_data, urecord->cur_particle_data + pbytes, urecord->end_particle_data); ret = -1; break; } } break; } case AS_BYTES: { as_bytes * v = as_bytes_fromval(val); uint8_t * s = as_bytes_get(v); size_t l = as_bytes_size(v); if ( !as_storage_bin_can_fit(rd->ns, l) ) { cf_warning(AS_UDF, "bytes: bin size too big"); ret = -1; break; } if (rd->ns->storage_data_in_memory) { as_particle_frombuf(b, AS_PARTICLE_TYPE_BLOB, s, l, NULL, true); } else { pbytes = l + as_particle_get_base_size(AS_PARTICLE_TYPE_BLOB); if ((urecord->cur_particle_data + pbytes) < urecord->end_particle_data) { as_particle_frombuf(b, AS_PARTICLE_TYPE_BLOB, s, l, urecord->cur_particle_data, rd->ns->storage_data_in_memory); urecord->cur_particle_data += pbytes; } else { cf_warning(AS_UDF, "bytes: bin data size too big pbytes %d" " pdata %p cur_part+pbytes %p pend %p", pbytes, urecord->particle_data, urecord->cur_particle_data + pbytes, urecord->end_particle_data); ret = -1; break; } } break; } case AS_BOOLEAN: { as_boolean * v = as_boolean_fromval(val); bool d = as_boolean_get(v); int64_t i = __be64_to_cpup((void *)&d); if ( !as_storage_bin_can_fit(rd->ns, 8) ) { cf_warning(AS_UDF, "bool: bin size too big"); ret = -1; break; } if (rd->ns->storage_data_in_memory) { as_particle_frombuf(b, AS_PARTICLE_TYPE_INTEGER, (uint8_t *) &i, 8, NULL, true); } else { pbytes = 8 + as_particle_get_base_size(AS_PARTICLE_TYPE_INTEGER); if ((urecord->cur_particle_data + pbytes) < urecord->end_particle_data) { as_particle_frombuf(b, AS_PARTICLE_TYPE_INTEGER, (uint8_t *) &i, 8, urecord->cur_particle_data, rd->ns->storage_data_in_memory); urecord->cur_particle_data += pbytes; } else { cf_warning(AS_UDF, "bool: bin data size too big: pbytes %d %p %p %p", pbytes, urecord->particle_data, urecord->cur_particle_data, urecord->end_particle_data); ret = -1; break; } } break; } case AS_INTEGER: { as_integer * v = as_integer_fromval(val); int64_t i = as_integer_get(v); int64_t j = __be64_to_cpup((void *)&i); if ( !as_storage_bin_can_fit(rd->ns, 8) ) { cf_warning(AS_UDF, "int: bin size too big"); ret = -1; break; } if (rd->ns->storage_data_in_memory) { as_particle_frombuf(b, AS_PARTICLE_TYPE_INTEGER, (uint8_t *) &j, 8, NULL, true); } else { pbytes = 8 + as_particle_get_base_size(AS_PARTICLE_TYPE_INTEGER); if ((urecord->cur_particle_data + pbytes) < urecord->end_particle_data) { as_particle_frombuf(b, AS_PARTICLE_TYPE_INTEGER, (uint8_t *) &j, 8, urecord->cur_particle_data, rd->ns->storage_data_in_memory); urecord->cur_particle_data += pbytes; } else { cf_warning(AS_UDF, "int: bin data size too big: pbytes %d %p %p %p", pbytes, urecord->particle_data, urecord->cur_particle_data, urecord->end_particle_data); ret = -1; break; } } break; } // @LDT : Possibly include AS_LDT in this list. We need the LDT // bins to be updated by LDT lua calls, and that path takes us thru here. // However, we ALSO need to be able to set the particle type for the // bins -- so that requires extra processing here to take the LDT flags // and set the appropriate bin flags in the particle data. case AS_MAP: case AS_LIST: { as_buffer buf; as_buffer_init(&buf); as_serializer s; as_msgpack_init(&s); int rsp = 0; as_serializer_serialize(&s, (as_val *) val, &buf); if ( !as_storage_bin_can_fit(rd->ns, buf.size) ) { cf_warning(AS_UDF, "map-list: bin size too big"); ret = -1; // Clean Up and jump out. as_serializer_destroy(&s); as_buffer_destroy(&buf); break; // can't continue if value too big. } uint8_t ptype; if(is_hidden) { ptype = as_particle_type_convert_to_hidden(to_particle_type(type)); } else { ptype = to_particle_type(type); } if (rd->ns->storage_data_in_memory) { as_particle_frombuf(b, ptype, (uint8_t *) buf.data, buf.size, NULL, true); } else { pbytes = buf.size + as_particle_get_base_size(ptype); if ((urecord->cur_particle_data + pbytes) < urecord->end_particle_data) { as_particle_frombuf(b, ptype, (uint8_t *) buf.data, buf.size, urecord->cur_particle_data, rd->ns->storage_data_in_memory); urecord->cur_particle_data += pbytes; } else { cf_warning(AS_UDF, "map-list: bin data size too big: pbytes %d %p %p %p", pbytes, urecord->particle_data, urecord->cur_particle_data, urecord->end_particle_data); rsp = -1; } } as_serializer_destroy(&s); as_buffer_destroy(&buf); if (rsp) { ret = rsp; break; } break; } default: { cf_warning(AS_UDF, "unrecognized object type %d, skipping", as_val_type(val) ); break; } } // If something fail bailout if (ret) { as_sindex_sbin_freeall(oldbin, 1); as_sindex_sbin_freeall(newbin, 1); return ret; } // Update sindex if required if (has_sindex) { if (as_sindex_sbin_from_bin(rd->ns, as_index_get_set_name(rd->r, rd->ns), b, newbin) == AS_SINDEX_OK) { if (!as_sindex_sbin_match(newbin, oldbin)) { needs_sindex_put = true; } else { needs_sindex_update = true; } } if (needs_sindex_update) { tr->flag |= AS_TRANSACTION_FLAG_SINDEX_TOUCHED; as_sindex_delete_by_sbin(rd->ns, as_index_get_set_name(rd->r, rd->ns), 1, oldbin, rd); as_sindex_put_by_sbin(rd->ns, as_index_get_set_name(rd->r, rd->ns), 1, newbin, rd); } else { if (needs_sindex_delete) { tr->flag |= AS_TRANSACTION_FLAG_SINDEX_TOUCHED; as_sindex_delete_by_sbin(rd->ns, as_index_get_set_name(rd->r, rd->ns), 1, oldbin, rd); } if (needs_sindex_put) { tr->flag |= AS_TRANSACTION_FLAG_SINDEX_TOUCHED; as_sindex_put_by_sbin(rd->ns, as_index_get_set_name(rd->r, rd->ns), 1, newbin, rd); } } as_sindex_sbin_freeall(oldbin, 1); as_sindex_sbin_freeall(newbin, 1); } return ret; } // end udf_aerospike_setbin()
/* * Internal Function: Entry function from UDF code path to send * success result to the caller. Performs * value translation. */ void send_result(as_result * res, udf_call * call, void *udata) { // The following "no-op" line serves to quiet the compiler warning of an // otherwise unused variable. udata = udata; as_val * v = res->value; if ( res->is_success ) { if ( cf_context_at_severity(AS_UDF, CF_DETAIL) ) { char * str = as_val_tostring(v); cf_detail(AS_UDF, "SUCCESS: %s", str); cf_free(str); } if ( v != NULL ) { switch( as_val_type(v) ) { case AS_NIL: { send_success(call, AS_PARTICLE_TYPE_NULL, NULL, 0); break; } case AS_BOOLEAN: { as_boolean * b = as_boolean_fromval(v); int64_t bi = as_boolean_tobool(b) == true ? 1 : 0; send_success(call, AS_PARTICLE_TYPE_INTEGER, &bi, 8); break; } case AS_INTEGER: { as_integer * i = as_integer_fromval(v); int64_t ri = as_integer_toint(i); send_success(call, AS_PARTICLE_TYPE_INTEGER, &ri, 8); break; } case AS_STRING: { // this looks bad but it just pulls the pointer // out of the object as_string * s = as_string_fromval(v); char * rs = (char *) as_string_tostring(s); send_success(call, AS_PARTICLE_TYPE_STRING, rs, as_string_len(s)); break; } case AS_BYTES: { as_bytes * b = as_bytes_fromval(v); uint8_t * rs = as_bytes_get(b); send_success(call, AS_PARTICLE_TYPE_BLOB, rs, as_bytes_size(b)); break; } case AS_MAP: case AS_LIST: { as_buffer buf; as_buffer_init(&buf); as_serializer s; as_msgpack_init(&s); int res = as_serializer_serialize(&s, v, &buf); if (res != 0) { const char * error = "Complex Data Type Serialization failure"; cf_warning(AS_UDF, "%s (%d)", (char *)error, res); as_buffer_destroy(&buf); send_cdt_failure(call, AS_PARTICLE_TYPE_STRING, (char *)error, strlen(error)); } else { // Do not use this until after cf_detail_binary() can accept larger buffers. // cf_detail_binary(AS_UDF, buf.data, buf.size, CF_DISPLAY_HEX_COLUMNS, // "serialized %d bytes: ", buf.size); send_success(call, to_particle_type(as_val_type(v)), buf.data, buf.size); // Not needed stack allocated - unless serialize has internal state // as_serializer_destroy(&s); as_buffer_destroy(&buf); } break; } default: { cf_debug(AS_UDF, "SUCCESS: VAL TYPE UNDEFINED %d\n", as_val_type(v)); send_success(call, AS_PARTICLE_TYPE_STRING, NULL, 0); break; } } } else { send_success(call, AS_PARTICLE_TYPE_NULL, NULL, 0); } } else { // Else -- NOT success as_string * s = as_string_fromval(v); char * rs = (char *) as_string_tostring(s); cf_debug(AS_UDF, "FAILURE when calling %s %s %s", call->filename, call->function, rs); send_udf_failure(call, AS_PARTICLE_TYPE_STRING, rs, as_string_len(s)); } }
/* * Internal function: udf_aerospike_setbin * * Parameters: * offset -- offset of udf bin in updates array * r -- udf_record to be manipulated * bname -- name of the bin to be deleted * val -- value to be updated with * * Return value: * 0 on success * -1 on failure * * Description: * The function sets the bin with the name * passed in as parameter to the value, passed as the third parameter. * Before updating the bin, it is checked if the value can fit in the storage * * Synchronization : object lock acquired by the transaction thread executing UDF. * Partition reservation takes place just before the transaction starts executing * ( look for as_partition_reserve_udf in thr_tsvc.c ) * * Callers: * udf_aerospike__apply_update_atomic * In this function, if it fails at the time of update, the record is set * to rollback all the updates till this point. The case where it fails in * rollback is not handled. * * Side Notes: * i. write_to_device will be set to true on a successful bin update. * If all the updates from udf_aerospike__apply_update_atomic (including this) are * successful, the record will be written to disk and reopened so that the rest of * sets of updates can be applied. * * ii. If put in sindex fails, we do not handle it. * * TODO make sure anything goes into setbin only if the bin value is * changed */ static int udf_aerospike_setbin(udf_record * urecord, int offset, const char * bname, const as_val * val, bool is_hidden) { if (bname == NULL || bname[0] == 0 ) { cf_warning(AS_UDF, "udf_aerospike_setbin: Invalid Parameters: [No bin name supplied]... Fail"); return -1; } if (as_particle_type_from_asval(val) == AS_PARTICLE_TYPE_NULL) { cf_warning(AS_UDF, "udf_aerospike_setbin: [%s] called with unusable as_val", bname); return -3; } uint8_t type = as_val_type(val); if (is_hidden && ((type != AS_MAP) && (type != AS_LIST))) { cf_warning(AS_UDF, "udf_aerospike_setbin: Invalid Operation [Hidden %d type Not allowed]... Fail", type); return -3; } as_storage_rd * rd = urecord->rd; as_transaction *tr = urecord->tr; as_bin * b = as_bin_get_or_create(rd, bname); if ( !b ) { cf_warning(AS_UDF, "udf_aerospike_setbin: Internal Error [Bin %s not found.. Possibly ran out of bins]... Fail", bname); return -1; } bool has_sindex = as_sindex_ns_has_sindex(rd->ns); if (has_sindex) { SINDEX_GRLOCK(); } SINDEX_BINS_SETUP(sbins, 2 * rd->ns->sindex_cnt); as_sindex * si_arr[2 * rd->ns->sindex_cnt]; int sbins_populated = 0; int si_arr_index = 0; const char * set_name = as_index_get_set_name(rd->r, rd->ns); if (has_sindex ) { si_arr_index += as_sindex_arr_lookup_by_set_binid_lockfree(rd->ns, set_name, b->id, &si_arr[si_arr_index]); sbins_populated += as_sindex_sbins_from_bin(rd->ns, set_name, b, &sbins[sbins_populated], AS_SINDEX_OP_DELETE); } // we know we are doing an update now, make sure there is particle data, // set to be 1 wblock size now @TODO! int ret = 0; cf_detail(AS_UDF, "udf_setbin: bin %s type %d ", bname, type ); if (rd->ns->storage_data_in_memory) { if (as_bin_particle_replace_from_asval(b, val) != 0) { cf_warning(AS_UDF, "udf_aerospike_setbin: [%s] failed to replace particle", bname); ret = -4; } } else { uint32_t size = as_particle_size_from_asval(val); uint8_t *particle_buf = udf__aerospike_get_particle_buf(urecord, &urecord->updates[offset], size); if (particle_buf) { as_bin_particle_stack_from_asval(b, particle_buf, val); } else { cf_warning(AS_UDF, "udf_aerospike_setbin: [%s] failed to get space for particle size %u", bname, size); ret = -4; } } if (is_hidden && ret == 0) { if (type == AS_LIST) { as_bin_particle_list_set_hidden(b); } else if (type == AS_MAP) { as_bin_particle_map_set_hidden(b); } } // Update sindex if required if (has_sindex) { if (ret) { SINDEX_GUNLOCK(); if (sbins_populated > 0) { as_sindex_sbin_freeall(sbins, sbins_populated); } as_sindex_release_arr(si_arr, si_arr_index); return ret; } si_arr_index += as_sindex_arr_lookup_by_set_binid_lockfree(rd->ns, set_name, b->id, &si_arr[si_arr_index]); sbins_populated += as_sindex_sbins_from_bin(rd->ns, set_name, b, &sbins[sbins_populated], AS_SINDEX_OP_INSERT); SINDEX_GUNLOCK(); if (sbins_populated > 0) { tr->flags |= AS_TRANSACTION_FLAG_SINDEX_TOUCHED; as_sindex_update_by_sbin(rd->ns, as_index_get_set_name(rd->r, rd->ns), sbins, sbins_populated, &rd->keyd); as_sindex_sbin_freeall(sbins, sbins_populated); } as_sindex_release_arr(si_arr, si_arr_index); } return ret; } // end udf_aerospike_setbin()
int main(int argc, char* argv[]) { // Parse command line arguments. if (! example_get_opts(argc, argv, EXAMPLE_BASIC_OPTS)) { exit(-1); } // Connect to the aerospike database cluster. aerospike as; example_connect_to_aerospike(&as); // Start clean. example_remove_test_record(&as); // Create a large map object to use. No need to destroy lmap if using // as_ldt_init() on stack object. as_ldt lmap; if (! as_ldt_init(&lmap, "mylmap", AS_LDT_LMAP, NULL)) { LOG("unable to initialize ldt"); example_cleanup(&as); exit(-1); } as_error err; as_boolean ldt_exists; as_boolean_init(&ldt_exists, false); // Verify that the LDT is not already there. if (aerospike_lmap_ldt_exists(&as, &err, NULL, &g_key, &lmap, &ldt_exists) != AEROSPIKE_OK) { int rc = example_handle_udf_error(&err, "first aerospike_lmap_ldt_exists()"); example_cleanup(&as); exit(rc); } if (as_boolean_get(&ldt_exists)) { LOG("found ldt that should not be present"); example_cleanup(&as); exit(-1); } LOG("verified that lmap ldt is not present"); // No need to destroy ikey if using as_integer_init() on stack object. as_integer ikey; as_integer_init(&ikey, 12345); // No need to destroy sval if using as_string_init() on stack object with // free parameter false. as_string sval; as_string_init(&sval, "lmap value", false); // Put a string entry to the lmap. if (aerospike_lmap_put(&as, &err, NULL, &g_key, &lmap, (const as_val*)&ikey, (as_val *)&sval) != AEROSPIKE_OK) { LOG("first aerospike_lmap_put() returned %d - %s", err.code, err.message); example_cleanup(&as); exit(-1); } // Ok to reuse. as_integer_init(&ikey, 345); as_integer ival; as_integer_init(&ival, 1000); // Put an integer entry to the lmap. if (aerospike_lmap_put(&as, &err, NULL, &g_key, &lmap, (const as_val*)&ikey, (as_val*)&ival) != AEROSPIKE_OK) { LOG("second aerospike_lmap_put() returned %d - %s", err.code, err.message); example_cleanup(&as); exit(-1); } LOG("2 entries added to map"); uint32_t n_elements = 0; // See how many elements we have in the lmap now. if (aerospike_lmap_size(&as, &err, NULL, &g_key, &lmap, &n_elements) != AEROSPIKE_OK) { LOG("aerospike_lmap_size() returned %d - %s", err.code, err.message); example_cleanup(&as); exit(-1); } if (n_elements != 2) { LOG("unexpected lmap size %u", n_elements); example_cleanup(&as); exit(-1); } LOG("lmap size confirmed to be %u", n_elements); as_boolean_init(&ldt_exists, false); // Verify that the LDT is now present. if (aerospike_lmap_ldt_exists(&as, &err, NULL, &g_key, &lmap, &ldt_exists) != AEROSPIKE_OK) { LOG("first aerospike_lmap_ldt_exists() returned %d - %s", err.code, err.message); example_cleanup(&as); exit(-1); } if (! as_boolean_get(&ldt_exists)) { LOG("did not find ldt that should be be present"); example_cleanup(&as); exit(-1); } LOG("verified that lmap ldt is present"); as_map* p_map = NULL; // Get all the entries back. if (aerospike_lmap_get_all(&as, &err, NULL, &g_key, &lmap, &p_map) != AEROSPIKE_OK) { LOG("aerospike_lmap_filter() returned %d - %s", err.code, err.message); example_cleanup(&as); exit(-1); } as_hashmap_iterator it; as_hashmap_iterator_init(&it, (const as_hashmap*)p_map); // See if the elements match what we expect. while (as_hashmap_iterator_has_next(&it)) { const as_val* p_val = as_hashmap_iterator_next(&it); char* p_str = as_val_tostring(p_val); LOG(" element type %d, value %s", as_val_type(p_val), p_str); free(p_str); } as_map_destroy(p_map); p_map = NULL; as_integer_init(&ikey, 12345); // Remove an entry from the map. if (aerospike_lmap_remove(&as, &err, NULL, &g_key, &lmap, (const as_val*)&ikey) != AEROSPIKE_OK) { LOG("aerospike_lmap_remove() returned %d - %s", err.code, err.message); example_cleanup(&as); exit(-1); } as_val* p_val = NULL; // Make sure we can't get the value any more. as_status result = aerospike_lmap_get(&as, &err, NULL, &g_key, &lmap, (const as_val*)&ikey, &p_val); if (result == AEROSPIKE_OK) { // Server version >= 3.4.1 returns empty map if element doesn't exist. if (p_val && (as_val_type(p_val) != AS_MAP || as_map_size((as_map*)p_val) != 0)) { char* p_str = as_val_tostring(p_val); LOG("entry was not successfully removed"); LOG(" element type %d, value %s", as_val_type(p_val), p_str); free(p_str); as_val_destroy(p_val); example_cleanup(&as); exit(-1); } } else if (result != AEROSPIKE_ERR_LARGE_ITEM_NOT_FOUND) { LOG("aerospike_lmap_get() returned %d - %s", err.code, err.message); example_cleanup(&as); exit(-1); } LOG("entry successfully removed"); // Destroy the lmap. if (aerospike_lmap_destroy(&as, &err, NULL, &g_key, &lmap) != AEROSPIKE_OK) { LOG("aerospike_lmap_destroy() returned %d - %s", err.code, err.message); example_cleanup(&as); exit(-1); } n_elements = 0; // See if we can still do any lmap operations. if (aerospike_lmap_size(&as, &err, NULL, &g_key, &lmap, &n_elements) == AEROSPIKE_OK) { LOG("aerospike_lmap_size() did not return error"); example_cleanup(&as); exit(-1); } LOG("lmap successfully destroyed"); // Cleanup and disconnect from the database cluster. example_cleanup(&as); LOG("lmap example successfully completed"); return 0; }
int main(int argc, char* argv[]) { // Parse command line arguments. if (! example_get_opts(argc, argv, EXAMPLE_BASIC_OPTS)) { exit(-1); } // Connect to the aerospike database cluster. aerospike as; example_connect_to_aerospike(&as); // Start clean. example_remove_test_record(&as); as_ldt lmap; // Create a lmap bin to use. No need to destroy as_ldt if using // as_ldt_init() on stack object. if (! as_ldt_init(&lmap, "mylmap", AS_LDT_LMAP, NULL)) { LOG("unable to initialize ldt"); example_cleanup(&as); exit(-1); } as_error err; // No need to destroy as_integer if using as_integer_init() on stack object. as_integer ikey; as_integer_init(&ikey, 12345); // No need to destroy as_string if using as_string_init() on stack object // with free parameter false. as_string sval; as_string_init(&sval, "lmap value", false); // Put a string entry to the lmap. if (aerospike_lmap_put(&as, &err, NULL, &g_key, &lmap, (const as_val*)&ikey, (as_val *)&sval) != AEROSPIKE_OK) { LOG("first aerospike_lmap_put() returned %d - %s", err.code, err.message); example_cleanup(&as); exit(-1); } as_integer ival; as_integer_init(&ival, 1000); // It's ok to reset the as_integer. as_integer_init(&ikey, 345); // Put an integer entry to the lmap. if (aerospike_lmap_put(&as, &err, NULL, &g_key, &lmap, (const as_val*)&ikey, (as_val*)&ival) != AEROSPIKE_OK) { LOG("second aerospike_lmap_put() returned %d - %s", err.code, err.message); example_cleanup(&as); exit(-1); } LOG("2 entries added to map"); uint32_t n_elements = 0; // See how many elements we have in the lmap now. if (aerospike_lmap_size(&as, &err, NULL, &g_key, &lmap, &n_elements) != AEROSPIKE_OK) { LOG("aerospike_lmap_size() returned %d - %s", err.code, err.message); example_cleanup(&as); exit(-1); } if (n_elements != 2) { LOG("unexpected lmap size %u", n_elements); example_cleanup(&as); exit(-1); } LOG("lmap size confirmed to be %u", n_elements); as_ldt lmap2; as_ldt_init(&lmap2, "mylmap", AS_LDT_LMAP, NULL); as_map* p_map = NULL; // Get all the entries back. if (aerospike_lmap_get_all(&as, &err, NULL, &g_key, &lmap, &p_map) != AEROSPIKE_OK) { LOG("aerospike_lmap_filter() returned %d - %s", err.code, err.message); example_cleanup(&as); exit(-1); } // See if the elements match what we expect. as_hashmap_iterator it; as_hashmap_iterator_init(&it, (const as_hashmap*)p_map); while (as_hashmap_iterator_has_next(&it)) { const as_val* p_val = as_hashmap_iterator_next(&it); char* p_str = as_val_tostring(p_val); LOG(" element - type = %d, value = %s", as_val_type(p_val), p_str); free(p_str); } as_map_destroy(p_map); p_map = NULL; as_integer_init(&ikey, 345); as_integer_init(&ival, 2000); // Remove an entry from the map. as_integer_init(&ikey, 12345); if (aerospike_lmap_remove(&as, &err, NULL, &g_key, &lmap, (const as_val*)&ikey) != AEROSPIKE_OK) { LOG("aerospike_lmap_remove() returned %d - %s", err.code, err.message); example_cleanup(&as); exit(-1); } as_val* p_val = NULL; // Make sure we cannot get the value any more. if (aerospike_lmap_get(&as, &err, NULL, &g_key, &lmap, (const as_val*)&ikey, &p_val) == AEROSPIKE_OK) { LOG("unexpected success getting a removed entry"); as_val_destroy(p_val); example_cleanup(&as); exit(-1); } LOG("entry successfully removed"); // Destroy the lmap. if (aerospike_lmap_destroy(&as, &err, NULL, &g_key, &lmap) != AEROSPIKE_OK) { LOG("aerospike_lmap_destroy() returned %d - %s", err.code, err.message); example_cleanup(&as); exit(-1); } n_elements = 0; // See if we can still do any lmap operations. if (aerospike_lmap_size(&as, &err, NULL, &g_key, &lmap, &n_elements) == AEROSPIKE_OK) { LOG("aerospike_lmap_size() did not return error"); example_cleanup(&as); exit(-1); } LOG("lmap successfully destroyed"); // Cleanup and disconnect from the database cluster. example_cleanup(&as); LOG("lmap example successfully completed"); return 0; }
static int get(lua_State *L){ //printf("-get-\n"); aerospike* as = lua_touserdata(L, 1); const char* nameSpace = luaL_checkstring(L, 2); const char* set = luaL_checkstring(L, 3); const char* keyString = luaL_checkstring(L, 4); //printf("key-:%s\n", keyString); as_record* rec = NULL; as_key key; as_error err; as_key_init(&key, nameSpace, set, keyString); // Read the test record from the database. aerospike_key_get(as, &err, NULL, &key, &rec); // Push the error code lua_pushnumber(L, err.code); // Push the error message lua_pushstring(L, err.message); // Create an new table and push it if ( err.code == AEROSPIKE_OK){ lua_newtable(L); /* create table to hold Bins read */ /* * iterate through bin and add the bin name * and value to the table */ as_record_iterator it; as_record_iterator_init(&it, rec); while (as_record_iterator_has_next(&it)) { as_bin *bin = as_record_iterator_next(&it); as_val *value = (as_val*)as_bin_get_value(bin); char * binName = as_bin_get_name(bin); int bin_type = as_val_type(value); //Bin Type switch (bin_type){ case AS_INTEGER: //printf("--integer-%s-\n", binName); lua_pushstring(L, binName); //Bin name lua_pushnumber(L, as_integer_get(as_integer_fromval(value))); //printf("--integer-end-\n"); break; case AS_DOUBLE: //printf("--double-%s-\n", binName); lua_pushstring(L, binName); //Bin name lua_pushnumber(L, as_double_get(as_double_fromval(value))); //printf("--double-end-\n"); break; case AS_STRING: //printf("--string-%s-\n", binName); lua_pushstring(L, binName); //Bin name lua_pushstring(L, as_val_tostring(value)); //printf("--string-end-\n"); break; case AS_LIST: //printf("--list-%s-\n", binName); lua_pushstring(L, binName); //Bin name // Iterate through arraylist populating table as_list* p_list = as_list_fromval(value); as_arraylist_iterator it; as_arraylist_iterator_init(&it, (const as_arraylist*)p_list); // create a Lua inner table table for the "List" lua_newtable(L); int count = 0; // See if the elements match what we expect. while (as_arraylist_iterator_has_next(&it)) { const as_val* p_val = as_arraylist_iterator_next(&it); //Assume string char* p_str = as_val_tostring(p_val); lua_pushnumber(L, count); // table[i] lua_pushstring(L, p_str); //Value //printf("%d => %s\n", count, p_str); count++; lua_settable(L, -3); } //printf("--list-end-\n"); break; } //printf("--settable-\n"); lua_settable(L, -3); //printf("--settable-end-\n"); } } as_record_destroy(rec); as_key_destroy(&key); //printf("-get-end-\n"); return 3; }
int main(int argc, char* argv[]) { aerospike as; as_error err; as_boolean ldt_exists; as_ldt lstack, lstack2; as_integer ival; as_string sval; as_bytes bval; uint32_t n_elements, cap_size; as_arraylist_iterator it; as_list* p_list = NULL; // Parse command line arguments. if (! example_get_opts(argc, argv, EXAMPLE_BASIC_OPTS)) { exit(-1); } // Connect to the aerospike database cluster. example_connect_to_aerospike(&as); // Start clean. example_remove_test_record(&as); // Create a large stack object to use. No need to destroy lstack if using // as_ldt_init() on stack object. as_ldt_init(&lstack, "mystack", AS_LDT_LSTACK, NULL); // Verify that the LDT is not already there. as_boolean_init(&ldt_exists, false); assert (aerospike_lstack_ldt_exists(&as, &err, NULL, &g_key, &lstack, &ldt_exists) == AEROSPIKE_OK); assert (as_boolean_get(&ldt_exists) == false); LOG("verified that lstack ldt is not present"); // Push a few values onto the stack. // No need to destroy sval if using as_string_init() on stack object. // Push an integer as_integer_init(&ival, 123); assert (aerospike_lstack_push(&as, &err, NULL, &g_key, &lstack, (const as_val*)&ival) == AEROSPIKE_OK); // Push a string as_string_init(&sval, "string stack value", false); assert (aerospike_lstack_push(&as, &err, NULL, &g_key, &lstack, (const as_val*)&sval) == AEROSPIKE_OK); // Push bytes uint8_t buf[16] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}; as_bytes_init_wrap(&bval, buf, 16, false); assert (aerospike_lstack_push(&as, &err, NULL, &g_key, &lstack, (const as_val*)&bval) == AEROSPIKE_OK); // Look at the stack size right now. assert (aerospike_lstack_size(&as, &err, NULL, &g_key, &lstack, &n_elements) == AEROSPIKE_OK); LOG("%d values pushed", n_elements); // Peek a few values back. as_ldt_init(&lstack2, "mystack", AS_LDT_LSTACK, NULL); assert (aerospike_lstack_peek(&as, &err, NULL, &g_key, &lstack2, 3, &p_list) == AEROSPIKE_OK); // See if the elements match what we expect. as_arraylist_iterator_init(&it, (const as_arraylist*)p_list); while (as_arraylist_iterator_has_next(&it)) { const as_val* p_val = as_arraylist_iterator_next(&it); char* p_str = as_val_tostring(p_val); LOG(" peek - type = %d, value = %s", as_val_type(p_val), p_str); free(p_str); } as_list_destroy(p_list); p_list = NULL; // Push 3 more items onto the stack. By using as_arraylist_inita() we avoid // some but not all internal heap usage, so we must call // as_arraylist_destroy(). as_arraylist vals; as_arraylist_inita(&vals, 3); as_arraylist_append_int64(&vals, 1000); as_arraylist_append_int64(&vals, 2000); as_arraylist_append_int64(&vals, 3000); assert (aerospike_lstack_push_all(&as, &err, NULL, &g_key, &lstack, (const as_list*)&vals) == AEROSPIKE_OK); as_arraylist_destroy(&vals); LOG("3 more values pushed"); // Peek all the values back again. as_ldt_init(&lstack2, "mystack", AS_LDT_LSTACK, NULL); assert (aerospike_lstack_peek(&as, &err, NULL, &g_key, &lstack2, 10, &p_list) == AEROSPIKE_OK); // See if the elements match what we expect. #if 0 as_arraylist_iterator_init(&it, (const as_arraylist*)p_list); while (as_arraylist_iterator_has_next(&it)) { const as_val* p_val = as_arraylist_iterator_next(&it); char* p_str = as_val_tostring(p_val); LOG(" peek - type = %d, value = %s", as_val_type(p_val), p_str); free(p_str); } #else const as_arraylist* p_array = (const as_arraylist*)p_list; int i; for (i = 0; i < p_array->size; i++) { const as_val* p_val = p_array->elements[i]; char* p_str = as_val_tostring(p_val); LOG(" peek - type = %d, value = %s", as_val_type(p_val), p_str); free(p_str); } #endif as_list_destroy(p_list); p_list = NULL; // Set capacity for the lstack. assert (aerospike_lstack_set_capacity(&as, &err, NULL, &g_key, &lstack, 10000) == AEROSPIKE_OK); // Get capacity from the lstack. assert (aerospike_lstack_get_capacity(&as, &err, NULL, &g_key, &lstack, &cap_size) == AEROSPIKE_OK); assert (cap_size == 10000); // Verify that the LDT is now present. as_boolean_init(&ldt_exists, false); assert (aerospike_lstack_ldt_exists(&as, &err, NULL, &g_key, &lstack, &ldt_exists) == AEROSPIKE_OK); assert (as_boolean_get(&ldt_exists) == true); LOG("verified that lstack ldt is present"); // Destroy the lstack. assert (aerospike_lstack_destroy(&as, &err, NULL, &g_key, &lstack) == AEROSPIKE_OK); // See if we can still do any lstack operations. assert (aerospike_lstack_size(&as, &err, NULL, &g_key, &lstack, &n_elements) != AEROSPIKE_OK); // Cleanup and disconnect from the database cluster. example_cleanup(&as); LOG("lstack example successfully completed"); return 0; }