예제 #1
0
/**
 * Send failure notification of general UDF execution, but check for special
 * LDT errors and return specific Wire Protocol error codes for these cases:
 * (1) Record not found (2)
 * (2) LDT Collection item not found (125)
 *
 * All other errors get the generic 100 (UDF FAIL) code.
 */
static inline int
send_udf_failure(udf_call *call, const as_string *s)
{
	char *val = as_string_tostring(s);
	size_t vlen = as_string_len((as_string *)s); // TODO - make as_string_len() take const
	long error_code = ldt_get_error_code(val, vlen);

	if (error_code) {

		if (error_code == AS_PROTO_RESULT_FAIL_NOTFOUND ||
			error_code == AS_PROTO_RESULT_FAIL_COLLECTION_ITEM_NOT_FOUND) {

			call->tr->result_code = error_code;
			// Send an "empty" response, with no failure bin.
			as_transaction *    tr          = call->tr;
			single_transaction_response(tr, tr->rsv.ns, NULL/*ops*/,
					NULL /*bin*/, 0 /*nbins*/, 0, 0, NULL, NULL);
			return 0;
		}
	}

	cf_debug(AS_UDF, "Non-special LDT or General UDF Error(%s)", (char *) val);

	call->tr->result_code = AS_PROTO_RESULT_FAIL_UDF_EXECUTION;
	return send_failure(call, as_string_toval(s));
}
예제 #2
0
/* Internal Function: Workhorse function to send response back to the client
 * 					  after UDF execution.
 *
 * caller:
 * 		send_success
 * 		send_failure
 *
 * Assumption: The call should be setup properly pointing to the tr.
 *
 * Special Handling: If it is background scan udf job do not sent any
 * 					 response to client
 * 					 If it is scan job ...do not cleanup the fd it will
 * 					 be done by the scan thread after scan is finished
 */
static int
send_response(udf_call *call, const char *key, size_t klen, int vtype, void *val,
			  size_t vlen)
{
	as_transaction *    tr          = call->transaction;
	as_namespace *      ns          = tr->rsv.ns;
	uint32_t            generation  = tr->generation;
	uint                sp_sz       = 1024 * 16;
	uint32_t            void_time   = 0;
	uint                written_sz  = 0;
	bool                keep_fd     = false;
	as_bin              stack_bin;
	as_bin            * bin         = &stack_bin;

	// space for the stack particles
	uint8_t             stack_particle_buf[sp_sz];
	uint8_t *           sp_p        = stack_particle_buf;

	if (call->udf_type == AS_SCAN_UDF_OP_BACKGROUND) {
		// If we are doing a background UDF scan, do not send any result back
		cf_detail(AS_UDF, "UDF: Background transaction, send no result back. "
				  "Parent job id [%"PRIu64"]", ((tscan_job*)(tr->udata.req_udata))->tid);
		if(strncmp(key, "FAILURE", 8) == 0)  {
			cf_atomic_int_incr(&((tscan_job*)(tr->udata.req_udata))->n_obj_udf_failed);
		} else if(strncmp(key, "SUCCESS", 8) == 0) {
			cf_atomic_int_incr(&((tscan_job*)(tr->udata.req_udata))->n_obj_udf_success);
		}
		return 0;
	} else if(call->udf_type == AS_SCAN_UDF_OP_UDF) {
		// Do not release fd now, scan will do it at the end of all internal
		// 	udf transactions
		cf_detail(AS_UDF, "UDF: Internal udf transaction, do not release fd");
		keep_fd = true;
	}

	if (0 != make_send_bin(ns, bin, &sp_p, sp_sz, key, klen, vtype, val, vlen)) {
		return(-1);
	}

	// this is going to release the file descriptor
	if (keep_fd && tr->proto_fd_h) cf_rc_reserve(tr->proto_fd_h);

	single_transaction_response(
		tr, ns, NULL/*ops*/, &bin, 1,
		generation, void_time, &written_sz, NULL);

	// clean up.
	// TODO: check: is bin_inuse valid only when data_in_memory?
	// There must be another way to determine if the particle is used?
	if ( as_bin_inuse(bin) ) {
		as_particle_destroy(&stack_bin, ns->storage_data_in_memory);
	}

	if (sp_p != stack_particle_buf) {
		cf_free(sp_p);
	}
	return 0;
} // end send_response()
예제 #3
0
/**
 * Send failure notification of general UDF execution, but check for special
 * LDT errors and return specific Wire Protocol error codes for these cases:
 * (1) Record not found (2)
 * (2) LDT Collection item not found (125)
 *
 * All other errors get the generic 100 (UDF FAIL) code.
 */
static inline int
process_udf_failure(udf_call *call, const as_string *s, cf_dyn_buf *db)
{
	char *val = as_string_tostring(s);
	size_t vlen = as_string_len((as_string *)s); // TODO - make as_string_len() take const
	long error_code = ldt_get_error_code(val, vlen);

	if (error_code) {

		if (error_code == AS_PROTO_RESULT_FAIL_NOTFOUND ||
			error_code == AS_PROTO_RESULT_FAIL_COLLECTION_ITEM_NOT_FOUND) {

			call->tr->result_code = (uint8_t)error_code;
			// Send an "empty" response, with no failure bin.
			as_transaction *    tr          = call->tr;

			if (db) {
				size_t msg_sz = 0;
				uint8_t *msgp = (uint8_t *)as_msg_make_response_msg(
						tr->result_code, 0, 0, NULL, NULL, 0, tr->rsv.ns, NULL,
						&msg_sz, as_transaction_trid(tr), NULL);

				if (! msgp)	{
					cf_warning_digest(AS_RW, &tr->keyd, "{%s} LDT UDF failed to make response msg ", tr->rsv.ns->name);
					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, tr->rsv.ns, NULL/*ops*/,
						NULL /*bin*/, 0 /*nbins*/, 0, 0, NULL, NULL);
			}
			return 0;
		}
	}

	cf_debug(AS_UDF, "Non-special LDT or General UDF Error(%s)", (char *) val);

	call->tr->result_code = AS_PROTO_RESULT_FAIL_UDF_EXECUTION;
	return process_failure(call, as_string_toval(s), db);
}
예제 #4
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()
예제 #5
0
/**
 * Send failure notification of general UDF execution, but check for special
 * LDT errors and return specific Wire Protocol error codes for these cases:
 * (1) Record not found (2)
 * (2) LDR Collection item not found (125)
 *
 * All other errors get the generic 100 (UDF FAIL) code.
 *
 * Parse (Actually, probe) the error string, and if we see this pattern:
 * FileName:Line# 4digits:LDT-<Error String>
 * For example:
 * .../aerospike-lua-core/src/ldt/lib_llist.lua:982: 0002:LDT-Top Record Not Found
 * All UDF errors (LDT included), have the "filename:line# " prefix, and then
 * LDT errors follow that with a known pattern:
 * (4 digits, colon, LDT-<Error String>).
 * We will check the error string by looking for specific markers after the
 * the space that follows the filename:line#.  If we see the markers, we will
 * parse the LDT error code and use that as the wire protocol error if it is
 * one of the special ones:
 * (1)  "0002:LDT-Top Record Not Found"
 * (2)  "0125:LDT-Item Not Found"
 */
static inline int
send_udf_failure(udf_call *call, int vtype, void *val, size_t vlen)
{
	// We need to do a quick look to see if this is an LDT error string.  If it
	// is, then we'll look deeper.  We start looking after the first space.
	char * charptr;
	char * valptr = (char *) val;
	long error_code;

	// Start with the space, if it exists, as the marker for where we start
	// looking for the LDT error contents.
	if ((charptr = strchr((const char *) val, ' ')) != NULL) {
		// We must be at least 10 chars from the end, so if we're less than that
		// we are obviously not looking at an LDT error.
		if (&charptr[9] < &valptr[vlen]) {
			if (memcmp(&charptr[5], ":LDT-", 5) == 0) {
				error_code = strtol(&charptr[1], NULL, 10);
				if (error_code == AS_PROTO_RESULT_FAIL_NOTFOUND ||
					error_code == AS_PROTO_RESULT_FAIL_COLLECTION_ITEM_NOT_FOUND)
				{
					call->transaction->result_code = error_code;
					cf_debug(AS_UDF, "LDT Error: Code(%ld) String(%s)",
							error_code, (char *) val);
					// Send an "empty" response, with no failure bin.
					as_transaction *    tr          = call->transaction;
					single_transaction_response(tr, tr->rsv.ns, NULL/*ops*/,
							NULL /*bin*/, 0 /*nbins*/, 0, 0, NULL, NULL);
					return 0;
				}
			}
		}
	}

	cf_debug(AS_UDF, "Non-special LDT or General UDF Error(%s)", (char *) val);

	call->transaction->result_code = AS_PROTO_RESULT_FAIL_UDF_EXECUTION;
	return send_response(call, "FAILURE", 7, vtype, val, vlen);
}
예제 #6
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;
}