// 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, "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; }
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: * 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()