示例#1
0
/* Workhorse function to send response back to the client after UDF execution.
 *
 * Assumption: The call should be setup properly pointing to the tr.
 *
 * Special Handling: If it is background udf job do not send any
 * 					 response to client
 */
int
send_response(udf_call *call, const char *bin_name, const as_val *val)
{
	// NO response if background UDF
	if (call->def.type == AS_UDF_OP_BACKGROUND) {
		return 0;
	}
	// Note - this function quietly handles a null val. The response call will
	// be given a bin with a name but not 'in use', and it does the right thing.

	as_bin stack_bin;
	as_bin *bin = &stack_bin;

	uint32_t particle_size = as_particle_size_from_asval(val);

	static const size_t MAX_STACK_SIZE = 32 * 1024;
	uint8_t stack_particle[particle_size > MAX_STACK_SIZE ? 0 : particle_size];
	uint8_t *particle_buf = stack_particle;

	if (particle_size > MAX_STACK_SIZE) {
		particle_buf = (uint8_t *)cf_malloc(particle_size);

		if (! particle_buf) {
			cf_warning(AS_UDF, "failed alloc for particle size %u", particle_size);
			return -1;
		}
	}

	as_transaction *tr = call->tr;
	as_namespace *ns = tr->rsv.ns;

	as_bin_init(ns, bin, bin_name);
	as_bin_particle_stack_from_asval(bin, particle_buf, val);

	single_transaction_response(tr, ns, NULL, &bin, 1, tr->generation, tr->void_time, NULL, NULL);

	if (particle_buf != stack_particle) {
		cf_free(particle_buf);
	}

	return 0;
} // end send_response()
示例#2
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()
示例#3
0
/* Workhorse function to send response back to the client after UDF execution.
 *
 * Assumption: The call should be setup properly pointing to the tr.
 *
 * Special Handling: If it is background udf job do not send any
 * 					 response to client
 */
int
process_response(udf_call *call, const char *bin_name, const as_val *val, cf_dyn_buf *db)
{
	// NO response if background UDF
	if (call->def->type == AS_UDF_OP_BACKGROUND) {
		return 0;
	}
	// Note - this function quietly handles a null val. The response call will
	// be given a bin with a name but not 'in use', and it does the right thing.

	as_bin stack_bin;
	as_bin *bin = &stack_bin;

	uint32_t particle_size = as_particle_size_from_asval(val);

	static const size_t MAX_STACK_SIZE = 32 * 1024;
	uint8_t stack_particle[particle_size > MAX_STACK_SIZE ? 0 : particle_size];
	uint8_t *particle_buf = stack_particle;

	if (particle_size > MAX_STACK_SIZE) {
		particle_buf = (uint8_t *)cf_malloc(particle_size);

		if (! particle_buf) {
			cf_warning(AS_UDF, "failed alloc for particle size %u", particle_size);
			return -1;
		}
	}

	as_transaction *tr = call->tr;
	as_namespace *ns = tr->rsv.ns;

	as_bin_init(ns, bin, bin_name);
	as_bin_particle_stack_from_asval(bin, particle_buf, val);

	if (db) {
		size_t msg_sz = 0;
		uint8_t *msgp = (uint8_t *)as_msg_make_response_msg(tr->result_code,
				tr->generation, tr->void_time, NULL, &bin, 1, ns, NULL, &msg_sz,
				as_transaction_trid(tr), NULL);

		if (! msgp)	{
			cf_warning_digest(AS_RW, &tr->keyd, "{%s} UDF failed to make response msg ", ns->name);

			if (particle_buf != stack_particle) {
				cf_free(particle_buf);
			}

			return -1;
		}

		// Stash the message, to be sent later.
		db->buf = msgp;
		db->is_stack = false;
		db->alloc_sz = msg_sz;
		db->used_sz = msg_sz;
	}
	else {
		single_transaction_response(tr, ns, NULL, &bin, 1, tr->generation, tr->void_time, NULL, NULL);
	}

	if (particle_buf != stack_particle) {
		cf_free(particle_buf);
	}

	return 0;
}