// TODO - rename as as_record_..., move to record.c, take r instead of set_name, // and lose keyd parameter? void remove_from_sindex(as_namespace* ns, const char* set_name, cf_digest* keyd, as_bin* bins, uint32_t n_bins) { SINDEX_GRLOCK(); SINDEX_BINS_SETUP(sbins, ns->sindex_cnt); as_sindex* si_arr[ns->sindex_cnt]; int si_arr_index = 0; int sbins_populated = 0; // Reserve matching sindexes. for (int i = 0; i < (int)n_bins; i++) { si_arr_index += as_sindex_arr_lookup_by_set_binid_lockfree(ns, set_name, bins[i].id, &si_arr[si_arr_index]); } for (int i = 0; i < (int)n_bins; i++) { sbins_populated += as_sindex_sbins_from_bin(ns, set_name, &bins[i], &sbins[sbins_populated], AS_SINDEX_OP_DELETE); } SINDEX_GRUNLOCK(); if (sbins_populated) { as_sindex_update_by_sbin(ns, set_name, sbins, sbins_populated, keyd); as_sindex_sbin_freeall(sbins, sbins_populated); } as_sindex_release_arr(si_arr, si_arr_index); }
/* * Internal Function: udf_aerospike_delbin * * Parameters: * r - udf_record to be manipulated * bname - name of the bin to be deleted * * Return value: * 0 on success * -1 on failure * * Description: * The function deletes the bin with the name * passed in as parameter. The as_bin_destroy function * which is called here, only frees the data and * the bin is marked as not in use. The bin can then be reused later. * * 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 destroy. * 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 delete from sindex fails, we do not handle it. */ static int udf_aerospike_delbin(udf_record * urecord, const char * bname) { // Check that bname is not completely invalid if ( !bname || !bname[0] ) { cf_warning(AS_UDF, "delete bin: no bin name supplied"); return -1; } size_t blen = strlen(bname); as_storage_rd *rd = urecord->rd; as_transaction *tr = urecord->tr; // Check quality of bname -- first check that it is proper length, then // check that we're not over quota for bins, then finally make sure that // the bin exists. if (blen > (AS_ID_BIN_SZ - 1 ) || !as_bin_name_within_quota(rd->ns, (byte *)bname, blen)) { // Can't read bin if name too large or over quota cf_warning(AS_UDF, "bin name(%s) too big. Bin not added", bname); return -1; } as_bin * b = as_bin_get(rd, (byte *)bname, blen); if ( !b ) { cf_warning(AS_UDF, "as_bin_get failed: bin name(%s) not found", bname); return -1; } SINDEX_BINS_SETUP(delbin, 1); int sindex_ret = AS_SINDEX_OK; bool has_sindex = as_sindex_ns_has_sindex(rd->ns); if (has_sindex) { sindex_ret = as_sindex_sbin_from_bin(rd->ns, as_index_get_set_name(rd->r, rd->ns), b, delbin); } int32_t i = as_bin_get_index(rd, (byte *)bname, blen); if (i != -1) { if (has_sindex) { tr->flag |= AS_TRANSACTION_FLAG_SINDEX_TOUCHED; if (AS_SINDEX_OK == sindex_ret) { as_sindex_delete_by_sbin(rd->ns, as_index_get_set_name(rd->r, rd->ns), 1, delbin, rd); //TODO: Check the error code returned through sindex_ret. (like out of sync ) } } as_bin_destroy(rd, i); } else { cf_warning(AS_UDF, "deleting non-existing bin %s ignored", bname); } if (has_sindex) { as_sindex_sbin_freeall(delbin, 1); } return 0; }
bool write_sindex_update(as_namespace* ns, const char* set_name, cf_digest* keyd, as_bin* old_bins, uint32_t n_old_bins, as_bin* new_bins, uint32_t n_new_bins) { int n_populated = 0; bool not_just_created[n_new_bins]; memset(not_just_created, 0, sizeof(not_just_created)); // Maximum number of sindexes which can be changed in one transaction is // 2 * ns->sindex_cnt. SINDEX_GRLOCK(); SINDEX_BINS_SETUP(sbins, 2 * ns->sindex_cnt); as_sindex* si_arr[2 * ns->sindex_cnt]; int si_arr_index = 0; // Reserve matching SIs. for (int i = 0; i < n_old_bins; i++) { si_arr_index += as_sindex_arr_lookup_by_set_binid_lockfree(ns, set_name, old_bins[i].id, &si_arr[si_arr_index]); } for (int i = 0; i < n_new_bins; i++) { si_arr_index += as_sindex_arr_lookup_by_set_binid_lockfree(ns, set_name, new_bins[i].id, &si_arr[si_arr_index]); } // For every old bin, find the corresponding new bin (if any) and adjust the // secondary index if the bin was modified. If no corresponding new bin is // found, it means the old bin was deleted - also adjust the secondary index // accordingly. for (int32_t i_old = 0; i_old < (int32_t)n_old_bins; i_old++) { as_bin* b_old = &old_bins[i_old]; bool found = false; // Loop over new bins. Start at old bin index (if possible) and go down, // wrapping around to do the higher indexes last. This will find a match // (if any) very quickly - instantly, unless there were bins deleted. bool any_new = n_new_bins != 0; int32_t n_new_minus_1 = (int32_t)n_new_bins - 1; int32_t i_new = n_new_minus_1 < i_old ? n_new_minus_1 : i_old; while (any_new) { as_bin* b_new = &new_bins[i_new]; if (b_old->id == b_new->id) { if (as_bin_get_particle_type(b_old) != as_bin_get_particle_type(b_new) || b_old->particle != b_new->particle) { n_populated += as_sindex_sbins_populate( &sbins[n_populated], ns, set_name, b_old, b_new); } found = true; not_just_created[i_new] = true; break; } if (--i_new < 0 && (i_new = n_new_minus_1) <= i_old) { break; } if (i_new == i_old) { break; } } if (! found) { n_populated += as_sindex_sbins_from_bin(ns, set_name, b_old, &sbins[n_populated], AS_SINDEX_OP_DELETE); } } // Now find the new bins that are just-created bins. We've marked the others // in the loop above, so any left are just-created. for (uint32_t i_new = 0; i_new < n_new_bins; i_new++) { if (not_just_created[i_new]) { continue; } n_populated += as_sindex_sbins_from_bin(ns, set_name, &new_bins[i_new], &sbins[n_populated], AS_SINDEX_OP_INSERT); } SINDEX_GRUNLOCK(); if (n_populated != 0) { as_sindex_update_by_sbin(ns, set_name, sbins, n_populated, keyd); as_sindex_sbin_freeall(sbins, n_populated); } as_sindex_release_arr(si_arr, si_arr_index); return n_populated != 0; }
/* * 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: udf_aerospike_delbin * * Parameters: * r - udf_record to be manipulated * bname - name of the bin to be deleted * * Return value: * 0 on success * -1 on failure * * Description: * The function deletes the bin with the name * passed in as parameter. The as_bin_destroy function * which is called here, only frees the data and * the bin is marked as not in use. The bin can then be reused later. * * 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 destroy. * 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 delete from sindex fails, we do not handle it. */ static int udf_aerospike_delbin(udf_record * urecord, const char * bname) { // Check that bname is not completely invalid if ( !bname || !bname[0] ) { cf_warning(AS_UDF, "udf_aerospike_delbin: Invalid Parameters [No bin name supplied]... Fail"); return -1; } as_storage_rd *rd = urecord->rd; as_transaction *tr = urecord->tr; // Check quality of bname -- check that it is proper length, then make sure // that the bin exists. if (strlen(bname) >= AS_ID_BIN_SZ) { // Can't read bin if name too large. cf_warning(AS_UDF, "udf_aerospike_delbin: Invalid Parameters [bin name(%s) too big]... Fail", bname); return -1; } as_bin * b = as_bin_get(rd, bname); if ( !b ) { cf_debug(AS_UDF, "udf_aerospike_delbin: Invalid Operation [Bin name(%s) not found of delete]... Fail", bname); return -1; } const char * set_name = as_index_get_set_name(rd->r, rd->ns); bool has_sindex = as_sindex_ns_has_sindex(rd->ns); if (has_sindex) { SINDEX_GRLOCK(); } SINDEX_BINS_SETUP(sbins, rd->ns->sindex_cnt); as_sindex * si_arr[rd->ns->sindex_cnt]; int si_arr_index = 0; int sbins_populated = 0; 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, AS_SINDEX_OP_DELETE); SINDEX_GUNLOCK(); } int32_t i = as_bin_get_index(rd, bname); if (i != -1) { if (has_sindex) { 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_bin_destroy(rd, i); } else { cf_warning(AS_UDF, "udf_aerospike_delbin: Internal Error [Deleting non-existing bin %s]... Fail", bname); } if (has_sindex) { as_sindex_sbin_freeall(sbins, sbins_populated); as_sindex_release_arr(si_arr, si_arr_index); } return 0; }
/* * 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()