/* * Code to init the fields in a transaction. Use this instead of memset. * * NB: DO NOT SHUFFLE INIT ORDER .. it is based on elements found in the * structure. */ void as_transaction_init(as_transaction *tr, cf_digest *keyd, cl_msg *msgp) { tr->msgp = msgp; if (keyd) { tr->keyd = *keyd; tr->preprocessed = true; } else { tr->keyd = cf_digest_zero; tr->preprocessed = false; } tr->flag = 0; tr->generation = 0; tr->result_code = AS_PROTO_RESULT_OK; tr->proto_fd_h = 0; tr->start_time = cf_getns(); tr->end_time = 0; AS_PARTITION_RESERVATION_INIT(tr->rsv); tr->microbenchmark_time = 0; tr->microbenchmark_is_resolve = false; tr->proxy_node = 0; tr->proxy_msg = 0; UREQ_DATA_INIT(&tr->udata); tr->batch_shared = 0; tr->batch_index = 0; tr->void_time = 0; }
// Build response to batch request. static void batch_build_response(batch_transaction* btr, cf_buf_builder** bb_r) { as_namespace* ns = btr->ns; batch_digests *bmds = btr->digests; bool get_data = btr->get_data; uint32_t yield_count = 0; for (int i = 0; i < bmds->n_digests; i++) { batch_digest *bmd = &bmds->digest[i]; if (bmd->done == false) { // try to get the key as_partition_reservation rsv; AS_PARTITION_RESERVATION_INIT(rsv); cf_node other_node = 0; uint64_t cluster_key; if (! *bb_r) { *bb_r = cf_buf_builder_create_size(1024 * 4); } int rv = as_partition_reserve_read(ns, as_partition_getid(bmd->keyd), &rsv, &other_node, &cluster_key); if (rv == 0) { cf_atomic_int_incr(&g_config.batch_tree_count); as_index_ref r_ref; r_ref.skip_lock = false; int rec_rv = as_record_get(rsv.tree, &bmd->keyd, &r_ref, ns); if (rec_rv == 0) { as_index *r = r_ref.r; // Check to see this isn't an expired record waiting to die. if (r->void_time && r->void_time < as_record_void_time_get()) { as_msg_make_error_response_bufbuilder(&bmd->keyd, AS_PROTO_RESULT_FAIL_NOTFOUND, bb_r, ns->name); } else { // Make sure it's brought in from storage if necessary. as_storage_rd rd; if (get_data) { as_storage_record_open(ns, r, &rd, &r->key); rd.n_bins = as_bin_get_n_bins(r, &rd); } // Note: this array must stay in scope until the // response for this record has been built, since in the // get data w/ record on device case, it's copied by // reference directly into the record descriptor. as_bin stack_bins[!get_data || rd.ns->storage_data_in_memory ? 0 : rd.n_bins]; if (get_data) { // Figure out which bins you want - for now, all. rd.bins = as_bin_get_all(r, &rd, stack_bins); rd.n_bins = as_bin_inuse_count(&rd); } as_msg_make_response_bufbuilder(r, (get_data ? &rd : NULL), bb_r, !get_data, (get_data ? NULL : ns->name), true, false, btr->binlist); if (get_data) { as_storage_record_close(r, &rd); } } as_record_done(&r_ref, ns); } else { // TODO - what about empty records? cf_debug(AS_BATCH, "batch_build_response: as_record_get returned %d : key %"PRIx64, rec_rv, *(uint64_t *)&bmd->keyd); as_msg_make_error_response_bufbuilder(&bmd->keyd, AS_PROTO_RESULT_FAIL_NOTFOUND, bb_r, ns->name); } bmd->done = true; as_partition_release(&rsv); cf_atomic_int_decr(&g_config.batch_tree_count); } else { cf_debug(AS_BATCH, "batch_build_response: partition reserve read failed: rv %d", rv); as_msg_make_error_response_bufbuilder(&bmd->keyd, AS_PROTO_RESULT_FAIL_NOTFOUND, bb_r, ns->name); if (other_node != 0) { bmd->node = other_node; cf_debug(AS_BATCH, "other_node is: %p.", other_node); } else { cf_debug(AS_BATCH, "other_node is NULL."); } } yield_count++; if (yield_count % g_config.batch_priority == 0) { usleep(1); } } } }
/* Create an internal transaction. * parameters: * tr_create_data : Details for creating transaction * tr : to be filled * * return : 0 on success * -1 on failure */ int as_transaction_create_internal(as_transaction *tr, tr_create_data * trc_data) { tr_create_data * d = (tr_create_data*) trc_data; // Get Defensive memset(tr, 0, sizeof(as_transaction)); if (d->fd_h) { cf_warning(AS_PROTO, "Foreground Internal Transation .. Ignoring"); return -1; } else { tr->proto_fd_h = NULL; } tr->start_time = cf_getns(); tr->flag = AS_TRANSACTION_FLAG_INTERNAL; tr->keyd = d->digest; tr->preprocessed = true; tr->result_code = AS_PROTO_RESULT_OK; AS_PARTITION_RESERVATION_INIT(tr->rsv); UREQ_DATA_INIT(&tr->udata); // Get namespace and set lengths. int ns_len = strlen(d->ns->name); int set_len = strlen(d->set); // Figure out the size of the message. size_t msg_sz = sizeof(cl_msg); msg_sz += sizeof(as_msg_field) + ns_len; if (set_len != 0) { msg_sz += sizeof(as_msg_field) + set_len; } msg_sz += sizeof(as_msg_field) + sizeof(cf_digest); msg_sz += sizeof(as_msg_field) + sizeof(d->trid); // Udf call structure will go as a part of the transaction udata. // Do not pack it in the message. cf_debug(AS_PROTO, "UDF : Msg size for internal transaction is %d", msg_sz); // Allocate space in the buffer. uint8_t * buf = cf_malloc(msg_sz); memset(buf, 0, msg_sz); if (!buf) { return -1; } uint8_t * buf_r = buf; // Calculation of number of fields: // n_fields = ( ns ? 1 : 0 ) + (set ? 1 : 0) + (digest ? 1 : 0) + (trid ? 1 : 0) + (call ? 3 : 0); // Write the header in case the request gets proxied. Is it enough ?? buf = as_msg_write_header(buf, msg_sz, 0, d->msg_type, 0, 0, 0, 0, 2 /*n_fields*/, 0); buf = as_msg_write_fields(buf, d->ns->name, ns_len, d->set, set_len, &(d->digest), 0, 0 , 0, 0); tr->msgp = (cl_msg *) buf_r; return 0; }