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); }
size_t as_command_value_size(as_val* val, as_buffer* buffer) { switch (val->type) { case AS_NIL: { return 0; } case AS_INTEGER: { return 8; } case AS_STRING: { as_string* v = as_string_fromval(val); return as_string_len(v); } case AS_BYTES: { as_bytes* v = as_bytes_fromval(val); return v->size; } case AS_LIST: case AS_MAP: { as_serializer ser; as_msgpack_init(&ser); as_serializer_serialize(&ser, val, buffer); as_serializer_destroy(&ser); return buffer->size; } default: { return 0; } } }
/* * 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); } } }
static size_t as_command_user_key_size(const as_key* key) { size_t size = AS_FIELD_HEADER_SIZE + 1; // Add 1 for key's value type. as_val* val = (as_val*)key->valuep; // Key must not be list or map. switch (val->type) { case AS_NIL: { break; } case AS_INTEGER: { size += 8; break; } case AS_STRING: { as_string* v = as_string_fromval(val); // v->len should have been already set when calculating the digest. size += v->len; break; } case AS_BYTES: { as_bytes* v = as_bytes_fromval(val); size += v->size; break; } default: { break; } } return size; }
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; }
uint32_t string_asval_to_wire(const as_val *val, uint8_t *wire) { as_string *string = as_string_fromval(val); uint32_t size = (uint32_t)as_string_len(string); memcpy(wire, as_string_tostring(string), size); return size; }
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; }
void string_from_asval(const as_val *val, as_particle **pp) { string_mem *p_string_mem = (string_mem *)*pp; as_string *string = as_string_fromval(val); p_string_mem->type = AS_PARTICLE_TYPE_STRING; p_string_mem->sz = (uint32_t)as_string_len(string); memcpy(p_string_mem->data, as_string_tostring(string), p_string_mem->sz); }
uint32_t as_string_val_hashcode(const as_val * v) { as_string * string = as_string_fromval(v); if ( string == NULL || string->value == NULL) return 0; uint32_t hash = 0; int c; char * str = string->value; while ( (c = *str++) ) { hash = c + (hash << 6) + (hash << 16) - hash; } return hash; }
void as_string_val_destroy(as_val * v) { as_string * string = as_string_fromval(v); if ( !string ) return; if ( string->value && string->free ) { cf_free(string->value); } string->value = NULL; string->free = false; }
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; } } }
size_t as_command_value_size(as_val* val, as_buffer* buffer) { switch (val->type) { case AS_NIL: { return 0; } case AS_INTEGER: { return 8; } case AS_DOUBLE: { return 8; } case AS_STRING: { as_string* v = as_string_fromval(val); return as_string_len(v); } case AS_GEOJSON: { as_geojson* v = as_geojson_fromval(val); return 1 + // as_particle_geojson_mem::flags 2 + // as_particle_geojson_mem::ncells (0 * 8) + // <placeholder-cellids> EMPTY! as_geojson_len(v); } case AS_BYTES: { as_bytes* v = as_bytes_fromval(val); return v->size; } case AS_LIST: case AS_MAP: { as_serializer ser; as_msgpack_init(&ser); as_serializer_serialize(&ser, val, buffer); as_serializer_destroy(&ser); return buffer->size; } default: { return 0; } } }
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; }
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; }
/* * 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)); } }
uint32_t string_asval_wire_size(const as_val *val) { return as_string_len(as_string_fromval(val)); }
/** * Get specified bin's value as an as_string. * as_string * value = as_record_get_string(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_string * as_record_get_string(const as_record * rec, const as_bin_name name) { return as_string_fromval((as_val *) as_record_get(rec, name)); }
/** * Lookup a record by key, then apply the UDF. * * ~~~~~~~~~~{.c} * as_key key; * as_key_init(&key, "ns", "set", "key"); * * as_arraylist args; * as_arraylist_init(&args, 2, 0); * as_arraylist_append_int64(&args, 1); * as_arraylist_append_int64(&args, 2); * * as_val * res = NULL; * * if ( aerospike_key_apply(&as, &err, NULL, &key, "math", "add", &args, &res) != AEROSPIKE_OK ) { * fprintf(stderr, "error(%d) %s at [%s:%d]", err.code, err.message, err.file, err.line); * } * else { * as_val_destroy(res); * } * * as_arraylist_destroy(&args); * ~~~~~~~~~~ * * * @param as The aerospike instance to use for this operation. * @param err The as_error to be populated if an error occurs. * @param policy The policy to use for this operation. If NULL, then the default policy will be used. * @param key The key of the record. * @param module The module containing the function to execute. * @param function The function to execute. * @param arglist The arguments for the function. * @param result The return value from the function. * * @return AEROSPIKE_OK if successful. Otherwise an error. */ as_status aerospike_key_apply( aerospike * as, as_error * err, const as_policy_apply * policy, const as_key * key, const char * module, const char * function, as_list * arglist, as_val ** result) { // we want to reset the error so, we have a clean state as_error_reset(err); // resolve policies as_policy_apply p; as_policy_apply_resolve(&p, &as->config.policies, policy); cl_write_parameters wp; cl_write_parameters_set_default(&wp); wp.timeout_ms = p.timeout == UINT32_MAX ? 0 : p.timeout; cl_object okey; asval_to_clobject((as_val *) key->valuep, &okey); as_serializer ser; as_msgpack_init(&ser); as_string file; as_string_init(&file, (char *) module, true /*ismalloc*/); as_string func; as_string_init(&func, (char *) function, true /*ismalloc*/); as_buffer args; as_buffer_init(&args); as_serializer_serialize(&ser, (as_val *) arglist, &args); as_call call = { .file = &file, .func = &func, .args = &args }; uint64_t trid = 0; cl_bin * bins = 0; int n_bins = 0; cl_rv rc = CITRUSLEAF_OK; switch ( p.key ) { case AS_POLICY_KEY_DIGEST: { as_digest * digest = as_key_digest((as_key *) key); rc = do_the_full_monte( as->cluster, 0, CL_MSG_INFO2_WRITE, 0, key->ns, key->set, 0, (cf_digest *) digest->value, &bins, CL_OP_WRITE, 0, &n_bins, NULL, &wp, &trid, NULL, &call, NULL ); break; } case AS_POLICY_KEY_SEND: { cl_object okey; asval_to_clobject((as_val *) key->valuep, &okey); as_digest * digest = as_key_digest((as_key *) key); rc = do_the_full_monte( as->cluster, 0, CL_MSG_INFO2_WRITE, 0, key->ns, key->set, &okey, (cf_digest*)digest->value, &bins, CL_OP_WRITE, 0, &n_bins, NULL, &wp, &trid, NULL, &call, NULL ); break; } default: { // ERROR CASE break; } } as_buffer_destroy(&args); if (! (rc == CITRUSLEAF_OK || rc == CITRUSLEAF_FAIL_UDF_BAD_RESPONSE)) { as_error_fromrc(err, rc); } else { // Begin processing the data returned from the server, // IFF `result` argument is not NULL. // The reason is if `result` is NULL, then it implies the end user // does not care about the data returned from the server. if ( n_bins == 1 ) { cl_bin * bin = &bins[0]; if ( strcmp(bin->bin_name,"SUCCESS") == 0 ) { if ( result ) { as_val * val = NULL; clbin_to_asval(bin, &ser, &val); *result = val; } } else if ( strcmp(bin->bin_name,"FAILURE") == 0 ) { as_val * val = NULL; clbin_to_asval(bin, &ser, &val); if ( val->type == AS_STRING ) { as_string * s = as_string_fromval(val); as_error_update(err, AEROSPIKE_ERR_UDF, as_string_tostring(s)); } else { as_error_update(err, AEROSPIKE_ERR_SERVER, "unexpected failure bin type"); } as_val_destroy(val); } else { as_error_update(err, AEROSPIKE_ERR_SERVER, "unexpected bin name"); } } else { as_error_update(err, AEROSPIKE_ERR_SERVER, "unexpected number of bins"); } } if ( bins ) { citrusleaf_bins_free(bins, n_bins); free(bins); } as_serializer_destroy(&ser); return err->code; }
/** * Get specified bin's value as an NULL terminated string. * char * value = as_record_get_str(rec, "bin"); * @param rec - the record containing the bin * @param name - the name of the bin * @return the value if it exists, otherwise NULL. */ char * as_record_get_str(const as_record * rec, const as_bin_name name) { as_string * val = as_string_fromval((as_val *) as_record_get(rec, name)); return val ? as_string_tostring(val) : NULL; }
/* * 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()
uint32_t string_size_from_asval(const as_val *val) { return (uint32_t)(sizeof(string_mem) + as_string_len(as_string_fromval(val))); }