void as_integer_val_destroy(as_val * v) { as_integer * integer = as_integer_fromval(v); if ( !integer ) return; integer->value = INT64_MIN; }
as_status as_key_set_digest(as_error* err, as_key* key) { if (key->digest.init) { return AEROSPIKE_OK; } size_t set_len = strlen(key->set); size_t size; as_val* val = (as_val*)key->valuep; uint8_t* buf; switch (val->type) { case AS_INTEGER: { as_integer* v = as_integer_fromval(val); size = 9; buf = alloca(size); buf[0] = AS_BYTES_INTEGER; *(uint64_t*)&buf[1] = cf_swap_to_be64(v->value); break; } case AS_DOUBLE: { as_double* v = as_double_fromval(val); size = 9; buf = alloca(size); buf[0] = AS_BYTES_DOUBLE; *(double*)&buf[1] = cf_swap_to_big_float64(v->value); break; } case AS_STRING: { as_string* v = as_string_fromval(val); size_t len = as_string_len(v); size = len + 1; buf = alloca(size); buf[0] = AS_BYTES_STRING; memcpy(&buf[1], v->value, len); break; } case AS_BYTES: { as_bytes* v = as_bytes_fromval(val); size = v->size + 1; buf = alloca(size); // Note: v->type must be a blob type (AS_BYTES_BLOB, AS_BYTES_JAVA, AS_BYTES_PYTHON ...). // Otherwise, the particle type will be reassigned to a non-blob which causes a // mismatch between type and value. buf[0] = v->type; memcpy(&buf[1], v->value, v->size); break; } default: { return as_error_update(err, AEROSPIKE_ERR_PARAM, "Invalid key type: %d", val->type); } } cf_digest_compute2(key->set, set_len, buf, size, (cf_digest*)key->digest.value); key->digest.init = true; return AEROSPIKE_OK; }
as_status aerospike_lset_exists( aerospike * as, as_error * err, const as_policy_apply * policy, const as_key * key, const as_ldt * ldt, const as_val * val, as_boolean *exists) { if ( !err ) { return AEROSPIKE_ERR_PARAM; } as_error_reset(err); if (!as || !key || !ldt || !exists) { return as_error_set(err, AEROSPIKE_ERR_PARAM, "invalid parameter. " "as/key/ldt/n cannot be null"); } if (ldt->type != AS_LDT_LSET) { return as_error_set(err, AEROSPIKE_ERR_PARAM, "invalid parameter. " "not lset type"); } /* stack allocate the arg list */ as_string ldt_bin; as_string_init(&ldt_bin, (char *)ldt->name, false); as_arraylist arglist; as_arraylist_inita(&arglist, 2); as_arraylist_append_string(&arglist, &ldt_bin); as_val_reserve( val ); // bump the ref count as_arraylist_append(&arglist, (as_val *)val); as_val* p_return_val = NULL; aerospike_key_apply( as, err, policy, key, DEFAULT_LSET_PACKAGE, LDT_SET_OP_EXISTS, (as_list *)&arglist, &p_return_val); as_arraylist_destroy(&arglist); if (ldt_parse_error(err) != AEROSPIKE_OK) { return err->code; } if (!p_return_val) { return as_error_set(err, AEROSPIKE_ERR_LDT_INTERNAL, "no value returned from server"); } int64_t ival = as_integer_getorelse(as_integer_fromval(p_return_val), -1); as_val_destroy(p_return_val); if (ival == -1) { return as_error_set(err, AEROSPIKE_ERR_LDT_INTERNAL, "value returned from server not parse-able"); } as_boolean_init(exists, ival==1 ? true: false); return err->code; } // aerospike_lset_exists()
// ======================================================================= // Pass in a value into the UDF -- and then get it back. Simple. // This is used to measure the performance of the end to end // call infrastructure. // Pass in LDT Bin and Value. // Return Value. // ======================================================================= as_status aerospike_lstack_same( aerospike * as, as_error * err, const as_policy_apply * policy, const as_key * key, const as_ldt * ldt, uint32_t in_val, uint32_t * out_valp) { if ( !err ) { return AEROSPIKE_ERR_PARAM; } as_error_reset(err); if (!as || !key || !ldt || !out_valp) { return as_error_set(err, AEROSPIKE_ERR_PARAM, "invalid parameter. " "as/key/ldt/out_valp cannot be null"); } if (ldt->type != AS_LDT_LSTACK) { return as_error_set(err, AEROSPIKE_ERR_PARAM, "invalid parameter. " "not LSTACK type"); } // stack allocate the arg list. // Pass in the LDT Bin and the IN VALUE. as_string ldt_bin; as_string_init(&ldt_bin, (char *)ldt->name, false); as_arraylist arglist; as_arraylist_inita(&arglist, 2); as_arraylist_append_string(&arglist, &ldt_bin); as_arraylist_append_int64(&arglist, in_val); as_val* p_return_val = NULL; aerospike_key_apply( as, err, policy, key, DEFAULT_LSTACK_PACKAGE, LDT_STACK_OP_SAME, (as_list *)&arglist, &p_return_val); as_arraylist_destroy(&arglist); if (ldt_parse_error(err) != AEROSPIKE_OK) { return err->code; } int64_t ival = as_integer_getorelse(as_integer_fromval(p_return_val), -1); as_val_destroy(p_return_val); if (ival == -1) { return as_error_set(err, AEROSPIKE_ERR_LDT_INTERNAL, "value returned from server not parse-able"); } if (ival !=0 ) { return as_error_set(err, AEROSPIKE_ERR_LDT_INTERNAL, "same() Function Failed"); } *out_valp = (uint32_t)ival; return err->code; } // end as_status aerospike_lstack_same()
static uint8_t* as_command_write_user_key(uint8_t* begin, const as_key* key) { uint8_t* p = begin + AS_FIELD_HEADER_SIZE; as_val* val = (as_val*)key->valuep; uint32_t len; // Key must not be list or map. switch (val->type) { default: case AS_NIL: { *p++ = AS_BYTES_UNDEF; len = 0; break; } case AS_INTEGER: { as_integer* v = as_integer_fromval(val); *p++ = AS_BYTES_INTEGER; *(uint64_t*)p = cf_swap_to_be64(v->value); p += 8; len = 8; break; } case AS_DOUBLE: { as_double* v = as_double_fromval(val); *p++ = AS_BYTES_DOUBLE; *(double*)p = cf_swap_to_big_float64(v->value); p += 8; len = 8; break; } case AS_STRING: { as_string* v = as_string_fromval(val); *p++ = AS_BYTES_STRING; // v->len should have been already set when calculating the digest. memcpy(p, v->value, v->len); p += v->len; len = (uint32_t)v->len; break; } case AS_BYTES: { as_bytes* v = as_bytes_fromval(val); // Note: v->type must be a blob type (AS_BYTES_BLOB, AS_BYTES_JAVA, AS_BYTES_PYTHON ...). // Otherwise, the particle type will be reassigned to a non-blob which causes a // mismatch between type and value. *p++ = v->type; memcpy(p, v->value, v->size); p += v->size; len = v->size; break; } } as_command_write_field_header(begin, AS_FIELD_KEY, ++len); return p; }
// ======================================================================= // Internal function to handle all of the functions that get an int back // from a call. // size() // one() // ======================================================================= as_status aerospike_lstack_ask_internal( aerospike * as, as_error * err, const as_policy_apply * policy, const as_key * key, const as_ldt * ldt, uint32_t *n, const char *operation ) { if ( !err ) { return AEROSPIKE_ERR_PARAM; } as_error_reset(err); if (!as || !key || !ldt || !n) { return as_error_set(err, AEROSPIKE_ERR_PARAM, "invalid parameter. " "as/key/ldt/n cannot be null"); } if (ldt->type != AS_LDT_LSTACK) { return as_error_set(err, AEROSPIKE_ERR_PARAM, "invalid parameter. " "not stack type"); } /* stack allocate the arg list */ as_string ldt_bin; as_string_init(&ldt_bin, (char *)ldt->name, false); // All we need to pass in is the LDT Bin Name as_arraylist arglist; as_arraylist_inita(&arglist, 1); as_arraylist_append_string(&arglist, &ldt_bin); as_val* p_return_val = NULL; aerospike_key_apply( as, err, policy, key, DEFAULT_LSTACK_PACKAGE, operation, (as_list *)&arglist, &p_return_val); as_arraylist_destroy(&arglist); if (ldt_parse_error(err) != AEROSPIKE_OK) { return err->code; } if (!p_return_val) { return as_error_set(err, AEROSPIKE_ERR_LDT_INTERNAL, "no value returned from server"); } int64_t ival = as_integer_getorelse(as_integer_fromval(p_return_val), -1); as_val_destroy(p_return_val); if (ival == -1) { return as_error_set(err, AEROSPIKE_ERR_LDT_INTERNAL, "value returned from server not parse-able"); } *n = (uint32_t)ival; return err->code; } // end as_status aerospike_lstack_ask_internal()
// ======================================================================= as_status aerospike_lstack_set_capacity( aerospike * as, as_error * err, const as_policy_apply * policy, const as_key * key, const as_ldt * ldt, uint32_t elements_capacity ) { if ( !err ) { return AEROSPIKE_ERR_PARAM; } as_error_reset(err); if (!as || !key || !ldt || !elements_capacity) { return as_error_set(err, AEROSPIKE_ERR_PARAM, "invalid parameter. " "as/key/ldt/capacity cannot be null"); } if (ldt->type != AS_LDT_LSTACK) { return as_error_set(err, AEROSPIKE_ERR_PARAM, "invalid parameter. " "not stack type"); } /* stack allocate the arg list */ as_string ldt_bin; as_string_init(&ldt_bin, (char *)ldt->name, false); as_arraylist arglist; as_arraylist_inita(&arglist, 2); as_arraylist_append_string(&arglist, &ldt_bin); as_arraylist_append_int64(&arglist, elements_capacity); as_val* p_return_val = NULL; aerospike_key_apply( as, err, policy, key, DEFAULT_LSTACK_PACKAGE, LDT_STACK_OP_CAPACITY_SET, (as_list *)&arglist, &p_return_val); as_arraylist_destroy(&arglist); if (ldt_parse_error(err) != AEROSPIKE_OK) { return err->code; } int64_t ival = as_integer_getorelse(as_integer_fromval(p_return_val), -1); as_val_destroy(p_return_val); if (ival == -1) { return as_error_set(err, AEROSPIKE_ERR_LDT_INTERNAL, "value returned from server not parse-able"); } if (ival !=0 ) { return as_error_set(err, AEROSPIKE_ERR_LDT_INTERNAL, "capacity setting failed"); } return err->code; }
void asval_to_clobject(as_val * val, cl_object * obj) { switch(val->type) { case AS_NIL: { citrusleaf_object_init_null(obj); break; } case AS_INTEGER: { as_integer * v = as_integer_fromval(val); citrusleaf_object_init_int(obj, as_integer_toint(v)); break; } case AS_STRING: { as_string * v = as_string_fromval(val); citrusleaf_object_init_str(obj, as_string_get(v)); break; } case AS_BYTES: { as_bytes * v = as_bytes_fromval(val); citrusleaf_object_init_blob2(obj, v->value, v->size, (cl_type)v->type); break; } case AS_LIST:{ as_buffer buffer; as_buffer_init(&buffer); as_serializer ser; as_msgpack_init(&ser); as_serializer_serialize(&ser, val, &buffer); as_serializer_destroy(&ser); citrusleaf_object_init_blob_handoff(obj, buffer.data, buffer.size, CL_LIST); break; } case AS_MAP: { as_buffer buffer; as_buffer_init(&buffer); as_serializer ser; as_msgpack_init(&ser); as_serializer_serialize(&ser, val, &buffer); as_serializer_destroy(&ser); citrusleaf_object_init_blob_handoff(obj, buffer.data, buffer.size, CL_MAP); break; } default: { // raise an error break; } } }
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); }
bool query_cb(const as_val* p_val, void* udata) { if (! p_val) { LOG("query callback returned null - query is complete"); return true; } // Because of the UDF used, we expect an as_integer to be returned. as_integer* p_integer = as_integer_fromval(p_val); if (! p_integer) { LOG("query callback returned non-as_integer object"); return true; } LOG("query callback returned %" PRId64, as_integer_get(p_integer)); return true; }
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); }
/* * 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)); } }
uint8_t* as_command_write_bin(uint8_t* begin, uint8_t operation_type, const as_bin* bin, as_buffer* buffer) { uint8_t* p = begin + AS_OPERATION_HEADER_SIZE; const char* name = bin->name; // Copy string, but do not transfer null byte. while (*name) { *p++ = *name++; } uint8_t name_len = p - begin - AS_OPERATION_HEADER_SIZE; as_val* val = (as_val*)bin->valuep; uint32_t val_len; uint8_t val_type; switch (val->type) { default: case AS_NIL: { val_len = 0; val_type = AS_BYTES_UNDEF; break; } case AS_INTEGER: { as_integer* v = as_integer_fromval(val); *(uint64_t*)p = cf_swap_to_be64(v->value); p += 8; val_len = 8; val_type = AS_BYTES_INTEGER; break; } case AS_DOUBLE: { as_double* v = as_double_fromval(val); *(double*)p = cf_swap_to_big_float64(v->value); p += 8; val_len = 8; val_type = AS_BYTES_DOUBLE; break; } case AS_STRING: { as_string* v = as_string_fromval(val); // v->len should have been already set by as_command_value_size(). memcpy(p, v->value, v->len); p += v->len; val_len = (uint32_t)v->len; val_type = AS_BYTES_STRING; break; } case AS_BYTES: { as_bytes* v = as_bytes_fromval(val); memcpy(p, v->value, v->size); p += v->size; val_len = v->size; // Note: v->type must be a blob type (AS_BYTES_BLOB, AS_BYTES_JAVA, AS_BYTES_PYTHON ...). // Otherwise, the particle type will be reassigned to a non-blob which causes a // mismatch between type and value. val_type = v->type; break; } case AS_LIST: { memcpy(p, buffer->data, buffer->size); p += buffer->size; val_len = buffer->size; val_type = AS_BYTES_LIST; break; } case AS_MAP: { memcpy(p, buffer->data, buffer->size); p += buffer->size; val_len = buffer->size; val_type = AS_BYTES_MAP; break; } } *(uint32_t*)begin = cf_swap_to_be32(name_len + val_len + 4); begin += 4; *begin++ = operation_type; *begin++ = val_type; *begin++ = 0; *begin++ = name_len; return p; }
/** * Get specified bin's value as an as_integer. * as_integer * value = as_record_get_integer(rec, "bin"); * @param rec - the record containing the bin * @param name - the name of the bin * @return the value if it exists, otherwise NULL. */ as_integer * as_record_get_integer(const as_record * rec, const as_bin_name name) { return as_integer_fromval((as_val *) as_record_get(rec, name)); }
/** * Get specified bin's value as an int64_t. * ~~~~~~~~~~{.c} * int64_t value = as_record_get_int64(rec, "bin", INT64_MAX); * ~~~~~~~~~~ * @param rec The record containing the bin. * @param name The name of the bin. * @param fallback The default value to use, if the bin doesn't exist or is not an integer. * @return the value if it exists, otherwise 0. */ int64_t as_record_get_int64(const as_record * rec, const as_bin_name name, int64_t fallback) { as_integer * val = as_integer_fromval((as_val *) as_record_get(rec, name)); return val ? as_integer_toint(val) : fallback; }
uint8_t* as_command_write_bin(uint8_t* begin, uint8_t operation_type, const as_bin* bin, as_buffer* buffer) { uint8_t* p = begin + AS_OPERATION_HEADER_SIZE; const char* name = bin->name; // Copy string, but do not transfer null byte. while (*name) { *p++ = *name++; } uint8_t name_len = p - begin - AS_OPERATION_HEADER_SIZE; as_val* val = (as_val*)bin->valuep; uint32_t val_len; uint8_t val_type; switch (val->type) { default: case AS_NIL: { val_len = 0; val_type = AS_BYTES_UNDEF; break; } case AS_INTEGER: { as_integer* v = as_integer_fromval(val); *(uint64_t*)p = cf_swap_to_be64(v->value); p += 8; val_len = 8; val_type = AS_BYTES_INTEGER; break; } case AS_DOUBLE: { as_double* v = as_double_fromval(val); *(double*)p = cf_swap_to_big_float64(v->value); p += 8; val_len = 8; val_type = AS_BYTES_DOUBLE; break; } case AS_STRING: { as_string* v = as_string_fromval(val); // v->len should have been already set by as_command_value_size(). memcpy(p, v->value, v->len); p += v->len; val_len = (uint32_t)v->len; val_type = AS_BYTES_STRING; break; } case AS_GEOJSON: { // We send a cellid placeholder so we can fill in points // in place on the server w/o changing object size. as_geojson* v = as_geojson_fromval(val); // v->len should have been already set by as_command_value_size(). // as_particle_geojson_mem::flags *p++ = 0; // as_particle_geojson_mem::ncells *(uint16_t *) p = cf_swap_to_be16(0); p += sizeof(uint16_t); // placeholder cellid // THIS LOOP EXECUTES 0 TIMES (still, it belongs here ...) for (int ii = 0; ii < 0; ++ii) { *(uint64_t *) p = cf_swap_to_be64(0); p += sizeof(uint64_t); } // json data itself memcpy(p, v->value, v->len); p += v->len; val_len = (uint32_t)(1 + 2 + (0 * 8) + v->len); val_type = AS_BYTES_GEOJSON; break; } case AS_BYTES: { as_bytes* v = as_bytes_fromval(val); memcpy(p, v->value, v->size); p += v->size; val_len = v->size; // Note: v->type must be a blob type (AS_BYTES_BLOB, AS_BYTES_JAVA, AS_BYTES_PYTHON ...). // Otherwise, the particle type will be reassigned to a non-blob which causes a // mismatch between type and value. val_type = v->type; break; } case AS_LIST: { memcpy(p, buffer->data, buffer->size); p += buffer->size; val_len = buffer->size; val_type = AS_BYTES_LIST; cf_free(buffer->data); break; } case AS_MAP: { memcpy(p, buffer->data, buffer->size); p += buffer->size; val_len = buffer->size; val_type = AS_BYTES_MAP; cf_free(buffer->data); break; } } *(uint32_t*)begin = cf_swap_to_be32(name_len + val_len + 4); begin += 4; *begin++ = operation_type; *begin++ = val_type; *begin++ = 0; *begin++ = name_len; return p; }
uint32_t as_integer_val_hashcode(const as_val * v) { as_integer * i = as_integer_fromval(v); return i != NULL ? (uint32_t)i->value : 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[]) { // 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); // Register the UDF in the database cluster. if (! example_register_udf(&as, UDF_FILE_PATH)) { example_cleanup(&as); exit(-1); } // Write a record to the database. if (! write_record(&as)) { cleanup(&as); exit(-1); } as_error err; // Apply a simple UDF, with no arguments and no return value. if (aerospike_key_apply(&as, &err, NULL, &g_key, UDF_MODULE, "test_bin_1_add_1000", NULL, NULL) != AEROSPIKE_OK) { LOG("aerospike_key_apply() returned %d - %s", err.code, err.message); cleanup(&as); exit(-1); } LOG("test_bin_1_add_1000() was successfully applied"); if (! example_read_test_record(&as)) { example_cleanup(&as); exit(-1); } // Create an argument list for a (different) UDF. By using // as_arraylist_inita() we avoid some but not all internal heap usage, so we // must call as_arraylist_destroy(). as_arraylist args; as_arraylist_inita(&args, 3); as_arraylist_append_str(&args, "test-bin-2"); as_arraylist_append_int64(&args, 4); as_arraylist_append_int64(&args, 400); // Expect an integer return value. as_val* p_return_val = NULL; // Apply a UDF with arguments and a return value. if (aerospike_key_apply(&as, &err, NULL, &g_key, UDF_MODULE, "bin_transform", (as_list*)&args, &p_return_val) != AEROSPIKE_OK) { LOG("aerospike_key_apply() returned %d - %s", err.code, err.message); as_arraylist_destroy(&args); cleanup(&as); exit(-1); } as_arraylist_destroy(&args); if (! p_return_val) { LOG("aerospike_key_apply() retrieved null as_val object"); cleanup(&as); exit(-1); } // Extract an integer from the as_val returned. int64_t i_val = as_integer_getorelse(as_integer_fromval(p_return_val), -1); // Caller's responsibility to destroy as_val returned. as_val_destroy(p_return_val); if (i_val == -1) { LOG("aerospike_key_apply() retrieved non-as_integer object"); cleanup(&as); exit(-1); } LOG("bin_transform() was successfully applied - returned %" PRId64, i_val); if (! example_read_test_record(&as)) { example_cleanup(&as); exit(-1); } // Cleanup and disconnect from the database cluster. cleanup(&as); LOG("udf example successfully completed"); return 0; }