static bool udf_arglist_foreach(const as_list * l, as_list_foreach_callback callback, void * context) {
	as_msg_field * field = (as_msg_field *) l->data;

	if ( field != NULL ) {
		as_unpacker unpacker;
		unpacker.buffer = (const unsigned char*)field->data;
		unpacker.length = as_msg_field_get_value_sz(field);
		unpacker.offset = 0;
		if ( unpacker.length == 0 )
			return true;

		as_val* val = 0;
		int ret = as_unpack_val(&unpacker, &val);

		if (ret == 0 && as_val_type(val) == AS_LIST) {
			as_list_iterator list_iter;
			as_iterator* iter = (as_iterator*) &list_iter;
			as_list_iterator_init(&list_iter, (as_list*)val);

			while (as_iterator_has_next(iter)) {
				const as_val* v = as_iterator_next(iter);
				callback((as_val *) v, context);
			}
			as_iterator_destroy(iter);
		}
		as_val_destroy(val);
		return ret == 0;
	}
	return true;
}
bool
get_msg_key(as_transaction* tr, as_storage_rd* rd)
{
	if (! as_transaction_has_key(tr)) {
		return true;
	}

	if (rd->ns->single_bin && rd->ns->storage_data_in_memory) {
		cf_warning(AS_RW, "{%s} can't store key if data-in-memory & single-bin",
				tr->rsv.ns->name);
		return false;
	}

	as_msg_field* f = as_msg_field_get(&tr->msgp->msg, AS_MSG_FIELD_TYPE_KEY);

	if ((rd->key_size = as_msg_field_get_value_sz(f)) == 0) {
		cf_warning(AS_RW, "msg flat key size is 0");
		return false;
	}

	rd->key = f->data;

	if (*rd->key == AS_PARTICLE_TYPE_INTEGER &&
			rd->key_size != 1 + sizeof(uint64_t)) {
		cf_warning(AS_RW, "bad msg integer key flat size %u", rd->key_size);
		return false;
	}

	return true;
}
as_namespace_id
as_namespace_getid_bymsgfield(as_msg_field *fp)
{
	if (as_msg_field_get_value_sz(fp) >= AS_ID_NAMESPACE_SZ) {
		return -1;
	}

	as_namespace_id		ns_id = -1;
	uint lim = g_config.n_namespaces;
	uint i;
	for (i = 0; i < lim; i++) {
		as_namespace *ns = g_config.namespaces[i];
		if (strncmp((char *)fp->data, ns->name, as_msg_field_get_value_sz(fp)) == 0) {
			ns_id = ns->id;
			break;
		}
	}

	return ns_id;
}
int
set_set_from_msg(as_record* r, as_namespace* ns, as_msg* m)
{
	as_msg_field* f = as_msg_field_get(m, AS_MSG_FIELD_TYPE_SET);
	size_t name_len = (size_t)as_msg_field_get_value_sz(f);

	if (name_len == 0) {
		return 0;
	}

	// Given the name, find/assign the set-ID and write it in the as_index.
	return as_index_set_set_w_len(r, ns, (const char*)f->data, name_len, true);
}
// Caller must have checked that key is present in message.
bool
check_msg_key(as_msg* m, as_storage_rd* rd)
{
	as_msg_field* f = as_msg_field_get(m, AS_MSG_FIELD_TYPE_KEY);
	uint32_t key_size = as_msg_field_get_value_sz(f);
	uint8_t* key = f->data;

	if (key_size != rd->key_size || memcmp(key, rd->key, key_size) != 0) {
		cf_warning(AS_RW, "key mismatch - end of universe?");
		return false;
	}

	return true;
}
int
as_transaction_digest_validate(as_transaction *tr)
{
	cl_msg *msgp = tr->msgp;
	as_msg *m = &msgp->msg;

	cf_info(AS_PROTO, "digest compare succeeded");

	// Can only validate if we have two things to compare.
	as_msg_field *dfp = as_msg_field_get(m, AS_MSG_FIELD_TYPE_DIGEST_RIPE);
	if (dfp == 0) {
		cf_info(AS_PROTO, "no incoming protocol digest to validate");
		return(0);
	}
	if (as_msg_field_get_value_sz(dfp) != sizeof(cf_digest)) {
		cf_info(AS_PROTO, "sent bad digest size %d, can't validate",as_msg_field_get_value_sz(dfp));
		return(-1);
	}

	// Pull out the key and do the computation the same way as above.
	cf_digest computed;
	memset(&computed, 0, sizeof(cf_digest) );

	as_msg_field *kfp = as_msg_field_get(m, AS_MSG_FIELD_TYPE_KEY);
	if (!kfp) {
		cf_info(AS_PROTO, "received request with no key and no digest, validation failed");
		return(-1);
	}

	as_msg_field *sfp = as_msg_field_get(m, AS_MSG_FIELD_TYPE_SET);
	if (sfp == 0 || as_msg_field_get_value_sz(sfp) == 0) {
		cf_digest_compute(kfp->data, as_msg_field_get_value_sz(kfp), &tr->keyd);
	}
	else {
		cf_digest_compute2(sfp->data, as_msg_field_get_value_sz(sfp),
					kfp->data, as_msg_field_get_value_sz(kfp),
					&computed);
	}

	if (0 == memcmp(&computed, &tr->keyd, sizeof(computed))) {
		cf_info(AS_PROTO, "digest compare failed. wire: %"PRIx64" computed: %"PRIx64,
			*(uint64_t *)&tr->keyd, *(uint64_t *) &computed );
		return(-1);
	}

	cf_info(AS_PROTO, "digest compare succeeded");

	return(0);
}
static as_val *udf_arglist_get(const as_list * l, const uint32_t idx) {
	as_msg_field * field = (as_msg_field *) l->data;

	if ( field != NULL ) {
		as_unpacker unpacker;
		unpacker.buffer = (const unsigned char*)field->data;
		unpacker.length = as_msg_field_get_value_sz(field);
		unpacker.offset = 0;
		if ( unpacker.length == 0 )
			return NULL;

		as_val* item = 0;
		as_val* val = 0;
		int ret = as_unpack_val(&unpacker, &val);

		if (ret == 0 && as_val_type(val) == AS_LIST) {
			item = as_list_get((as_list*)val, idx);
		}
		as_val_destroy(val);
		return item;
	}
	return NULL;
}
as_namespace *
as_namespace_get_bymsgfield(as_msg_field *fp)
{
	return as_namespace_get_bybuf((byte *)fp->data, as_msg_field_get_value_sz(fp));
}
Exemple #9
0
void
as_msg_peek( cl_msg *msgp, proto_peek *peek )
{
	memset(peek, 0, sizeof(proto_peek));

	if (msgp == 0) return;

	if (msgp->proto.version != PROTO_VERSION ||
			msgp->proto.type != PROTO_TYPE_AS_MSG) {
		return;
	}

	as_msg *m = &msgp->msg;
	peek->info1 = m->info1;
	peek->info2 = m->info2;

	if (m->n_fields == 0) {
		return;
	}

	int n_fields = m->n_fields;
	bool swap = n_fields < 10 ? false : true;
	if (swap) n_fields = ntohs(n_fields);

	as_msg_field *kdfp = 0;
	as_msg_field *sfp = 0;
	as_msg_field *kfp = 0;
	as_msg_field *nfp = 0;

	// over all the fields
	as_msg_field *mf = (as_msg_field *) m->data;
	uint i = 0;
	for (; i < n_fields ; i++) {
		switch (mf->type) {
			case AS_MSG_FIELD_TYPE_DIGEST_RIPE:
				kdfp = mf;
				break;
			case AS_MSG_FIELD_TYPE_SET:
				sfp = mf;
				break;
			case AS_MSG_FIELD_TYPE_KEY:
				kfp = mf;
				break;
			case AS_MSG_FIELD_TYPE_NAMESPACE:
				nfp = mf;
				break;
		}
		if (swap)
			mf = as_msg_field_get_next_unswap(mf);
		else
			mf = as_msg_field_get_next(mf);
	}

	// find the key
	if (kdfp) {
		peek->keyd = *(cf_digest *)kdfp->data;
	}
	else {
		if (kfp) {
			if (sfp == 0 || as_msg_field_get_value_sz(sfp) == 0) {
				int ksz = swap ? as_msg_field_get_value_sz_unswap(kfp) : as_msg_field_get_value_sz(kfp);
				cf_digest_compute(kfp->data, ksz, &peek->keyd);
			}
			else {
				int ksz = swap ? as_msg_field_get_value_sz_unswap(kfp) : as_msg_field_get_value_sz(kfp);
				int ssz = swap ? as_msg_field_get_value_sz_unswap(sfp) : as_msg_field_get_value_sz(sfp);
				cf_digest_compute2(sfp->data, ssz, kfp->data, ksz, &peek->keyd);
			}
		}
	}

	// find the namespace
	if (nfp) {
		int nsz = swap ? as_msg_field_get_value_sz_unswap(nfp) : as_msg_field_get_value_sz(nfp);
		if (nsz > AS_ID_NAMESPACE_SZ) goto no_ns; // this should be illegal
		for (int i = 0; i < g_config.namespaces; i++) {
			tsvc_namespace_devices *ndev = &g_tsvc_devices_a[i];
			if (ndev->n_sz != nsz) continue;
			if (0 == memcmp(ndev->n_name, nfp->data, nsz)) {
				peek->ns_queue_offset = ndev->queue_offset;
				peek->ns_n_devices = ndev->n_devices;
				/*
				if (peek->info1 & AS_MSG_INFO1_READ) {
					cf_info(AS_PROTO, "read peek %s gives ofst %d n_dev %d",ndev->n_name,peek->ns_queue_offset,peek->ns_n_devices);
				} else {
					cf_info(AS_PROTO, "write peek %s gives ofst %d n_dev %d",ndev->n_name,peek->ns_queue_offset,peek->ns_n_devices);
				}
				*/
				break;
			}
		}
	}
no_ns:

	return;
}
/**
 * aerospike::create(record)
 * Function: udf_aerospike_rec_create
 *
 * Parameters:
 * 		as - as_aerospike
 *		rec - as_rec
 *
 * Return Values:
 * 		1 if record is being read or on a create, it already exists
 * 		o/w return value of udf_aerospike__execute_updates
 *
 * Description:
 * 		Create a new record in local storage.
 * 		The record will only be created if it does not exist.
 * 		This assumes the record has a digest that is valid for local 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:
 * 		lua interfacing function, mod_lua_aerospike_rec_create
 * 		The return value of udf_aerospike_rec_create is pushed on to the lua stack
 *
 * 		Notes:
 * 		The 'read' and 'exists' flag of udf_record are set to true.
*/
static int
udf_aerospike_rec_create(const as_aerospike * as, const as_rec * rec)
{
	int ret = udf_aerospike_param_check(as, rec, __FILE__, __LINE__);
	if (ret) {
		return ret;
	}

	udf_record * urecord  = (udf_record *) as_rec_source(rec);

	// make sure record isn't already successfully read
	if (urecord->flag & UDF_RECORD_FLAG_OPEN) {
		cf_detail(AS_UDF, "udf_aerospike_rec_create: Record Already Exists");
		return 1;
	}
	as_transaction *tr    = urecord->tr;
	as_index_ref   *r_ref = urecord->r_ref;
	as_storage_rd  *rd    = urecord->rd;
	as_index_tree  *tree  = tr->rsv.tree;

	if (urecord->flag & UDF_RECORD_FLAG_IS_SUBRECORD) {
		tree      = tr->rsv.sub_tree;
	}

	// make sure we got the record as a create
	int rv = as_record_get_create(tree, &tr->keyd, r_ref, tr->rsv.ns);
	cf_detail_digest(AS_UDF, &tr->keyd, "Creating %sRecord",
			(urecord->flag & UDF_RECORD_FLAG_IS_SUBRECORD) ? "Sub" : "");

	// rv 0 means record exists, 1 means create, < 0 means fail
	// TODO: Verify correct result codes.
	if (rv == 0) {
		cf_warning(AS_UDF, "udf_aerospike_rec_create: Record Already Exists 2");
		as_record_done(r_ref, tr->rsv.ns);
		bzero(r_ref, sizeof(as_index_ref));
		return 1;
	} else if (rv < 0) {
		cf_warning(AS_UDF, "udf_aerospike_rec_create: Record Open Failed with rv=%d", rv);
		return rv;
	}

	// Associates the set name with the storage rec and index
	if(tr->msgp) {
		// Set the set name to index and close record if the setting the set name
		// is not successful
		int rv_set = as_record_set_set_from_msg(r_ref->r, tr->rsv.ns, &tr->msgp->msg);
		if (rv_set != 0) {
			cf_warning(AS_UDF, "udf_aerospike_rec_create: Failed to set setname");
			as_record_done(r_ref, tr->rsv.ns);
			// TODO bzero is expensive. Switch to use flag.
			bzero(r_ref, sizeof(as_index_ref));
			return 4;
		}
	}

	urecord->flag |= UDF_RECORD_FLAG_OPEN;
	cf_detail(AS_UDF, "Open %p %x %"PRIx64"", urecord, urecord->flag, *(uint64_t *)&tr->keyd);

	as_index *r    = r_ref->r;
	// open up storage
	as_storage_record_create(urecord->tr->rsv.ns, urecord->r_ref->r,
		urecord->rd, &urecord->tr->keyd);

	cf_detail(AS_UDF, "as_storage_record_create: udf_aerospike_rec_create: r %p rd %p",
		urecord->r_ref->r, urecord->rd);

	// if multibin storage, we will use urecord->stack_bins, so set the size appropriately
	if ( ! rd->ns->storage_data_in_memory && ! rd->ns->single_bin ) {
		rd->n_bins = sizeof(urecord->stack_bins) / sizeof(as_bin);
	}

	// side effect: will set the unused bins to properly unused
	rd->bins       = as_bin_get_all(r, rd, urecord->stack_bins);
	urecord->flag |= UDF_RECORD_FLAG_STORAGE_OPEN;

	// If the message has a key, apply it to the record.
	as_msg_field* f = as_msg_field_get(&tr->msgp->msg, AS_MSG_FIELD_TYPE_KEY);
	if (f) {
		rd->key_size = as_msg_field_get_value_sz(f);
		rd->key = f->data;
	}

	cf_detail(AS_UDF, "Storage Open %p %x %"PRIx64"", urecord, urecord->flag, *(uint64_t *)&tr->keyd);
	cf_detail(AS_UDF, "udf_aerospike_rec_create: Record created %d", urecord->flag);

	int rc         = udf_aerospike__execute_updates(urecord);
	if(rc) {
		//  Creating the udf record failed, destroy the as_record
		if (!as_bin_inuse_has(urecord->rd)) {
			udf_aerospike_rec_remove(as, rec);
		}
	}
	return rc;
}
/*
  The transaction prepare function fills out the fields of the tr structure,
  using the information in the msg structure. It also swaps the fields in the
  message header (which are originally in network byte order).

  Once the prepare function has been called on the transaction, the
  'preprocessed' flag is set and the transaction cannot be prepared again.
  Returns:
  0:  OK
  -1: General Error
  -2: Request received with no key
  -3: Request received with digest array
*/
int as_transaction_prepare(as_transaction *tr) {
	cl_msg *msgp = tr->msgp;
	as_msg *m = &msgp->msg;

#if defined(USE_SYSTEMTAP)
	uint64_t nodeid = g_config.self_node;
#endif

//	cf_assert(tr, AS_PROTO, CF_CRITICAL, "invalid transaction");

	void *limit = ((void *)m) + msgp->proto.sz;

	// Check processed flag.  It's a non-fatal error to call this function again.
	if( tr->preprocessed )
		return(0);

	if (0 != cf_digest_compare(&tr->keyd, &cf_digest_zero)) {
		cf_warning(AS_RW, "Internal inconsistency: transaction has keyd, but marked not swizzled");
	}

	as_msg_swap_header(m);
	if (0 != as_msg_swap_fields_and_ops(m, limit)) {
		cf_info(AS_PROTO, "msg swap field and ops returned error");
		return(-1);
	}

	if (m->n_fields>PROTO_NFIELDS_MAX_WARNING) {
		cf_info(AS_PROTO, "received too many n_fields! %d",m->n_fields);
    }

	// Set the transaction end time if available.
	if (m->transaction_ttl) {
//		cf_debug(AS_PROTO, "received non-zero transaction ttl: %d",m->transaction_ttl);
		tr->end_time = tr->start_time + ((uint64_t)m->transaction_ttl * 1000000);
	}

	// Set the preprocessed flag. All exits from here on out are considered
	// processed since the msg header has been swapped and the transaction
	// end time has been set.
	tr->preprocessed = true;
	tr->flag         = 0;
	UREQ_DATA_INIT(&tr->udata);
	as_msg_field *sfp = as_msg_field_get(m, AS_MSG_FIELD_TYPE_DIGEST_RIPE_ARRAY);
	if (sfp) {
		cf_debug(AS_PROTO, "received request with digest array, batch");
		return(-3);
	}

	// It's tempting to move this to the final return, but queries
	// actually escape in the if clause below ...
	ASD_TRANS_PREPARE(nodeid, (uint64_t) msgp, tr->trid);

	// Sent digest? Use!
	as_msg_field *dfp = as_msg_field_get(m, AS_MSG_FIELD_TYPE_DIGEST_RIPE);
	if (dfp) {
//		cf_detail(AS_PROTO, "transaction prepare: received sent digest\n");
		if (as_msg_field_get_value_sz(dfp) != sizeof(cf_digest)) {
			cf_info(AS_PROTO, "sent bad digest size %d, recomputing digest",as_msg_field_get_value_sz(dfp));
			goto Compute;
		}
		memcpy(&tr->keyd, dfp->data, sizeof(cf_digest));
	}
	// Not sent, so compute.
	else {
Compute:		;
		as_msg_field *kfp = as_msg_field_get(m, AS_MSG_FIELD_TYPE_KEY);
		if (!kfp) {
			cf_detail(AS_PROTO, "received request with no key, scan");
			return(-2);
		}
        if (as_msg_field_get_value_sz(kfp)> PROTO_FIELD_LENGTH_MAX) {
	        cf_info(AS_PROTO, "key field too big %d. Is it for real?",as_msg_field_get_value_sz(kfp));
        }

		as_msg_field *sfp = as_msg_field_get(m, AS_MSG_FIELD_TYPE_SET);
		if (sfp == 0 || as_msg_field_get_value_sz(sfp) == 0) {
			cf_digest_compute(kfp->data, as_msg_field_get_value_sz(kfp), &tr->keyd);
			// cf_info(AS_PROTO, "computing key for sz %d %"PRIx64" bytes %d %d %d %d",as_msg_field_get_value_sz(kfp),*(uint64_t *)&tr->keyd,kfp->data[0],kfp->data[1],kfp->data[2],kfp->data[3]);
		}
		else {
            if (as_msg_field_get_value_sz(sfp)> PROTO_FIELD_LENGTH_MAX) {
		        cf_info(AS_PROTO, "set field too big %d. Is this for real?",as_msg_field_get_value_sz(sfp));
            }
			cf_digest_compute2(sfp->data, as_msg_field_get_value_sz(sfp),
						kfp->data, as_msg_field_get_value_sz(kfp),
						&tr->keyd);
			// cf_info(AS_PROTO, "computing set with key for sz %d %"PRIx64" bytes %d %d",as_msg_field_get_value_sz(kfp),*(uint64_t *)&tr->keyd,kfp->data[0],kfp->data[1],kfp->data[2],kfp->data[3]);
		}
	}

	return(0);
}