int as_msg_swap_ops(as_msg *m, void *limit) { as_msg_op *op = 0; int *n = 0; // 0ing actually not necessary while ((op = as_msg_op_iterate(m, op, n))) { if ((void*)op >= limit) return(-1); as_msg_swap_op(op); } return(0); }
// Create bin name list from message. static cf_vector* as_binlist_from_op(as_msg* msg) { if (msg->n_ops == 0) { return 0; } cf_vector* binlist = cf_vector_create(AS_ID_BIN_SZ, 5, 0); as_msg_op* op = 0; int n = 0; int len; char name[AS_ID_BIN_SZ]; while ((op = as_msg_op_iterate(msg, op, &n))) { len = (op->name_sz <= AS_ID_BIN_SZ - 1)? op->name_sz : AS_ID_BIN_SZ - 1; memcpy(name, op->name, len); name[len] = 0; cf_vector_append(binlist, name); } return binlist; }
transaction_status read_local(as_transaction* tr) { as_msg* m = &tr->msgp->msg; as_namespace* ns = tr->rsv.ns; as_index_ref r_ref; if (as_record_get(tr->rsv.tree, &tr->keyd, &r_ref) != 0) { read_local_done(tr, NULL, NULL, AS_ERR_NOT_FOUND); return TRANS_DONE_ERROR; } as_record* r = r_ref.r; // Check if it's an expired or truncated record. if (as_record_is_doomed(r, ns)) { read_local_done(tr, &r_ref, NULL, AS_ERR_NOT_FOUND); return TRANS_DONE_ERROR; } int result = repl_state_check(r, tr); if (result != 0) { if (result == -3) { read_local_done(tr, &r_ref, NULL, AS_ERR_UNAVAILABLE); return TRANS_DONE_ERROR; } // No response sent to origin. as_record_done(&r_ref, ns); return result == 1 ? TRANS_IN_PROGRESS : TRANS_WAITING; } // Check if it's a tombstone. if (! as_record_is_live(r)) { read_local_done(tr, &r_ref, NULL, AS_ERR_NOT_FOUND); return TRANS_DONE_ERROR; } as_storage_rd rd; as_storage_record_open(ns, r, &rd); // If configuration permits, allow reads to use page cache. rd.read_page_cache = ns->storage_read_page_cache; // Check the key if required. // Note - for data-not-in-memory "exists" ops, key check is expensive! if (as_transaction_has_key(tr) && as_storage_record_get_key(&rd) && ! check_msg_key(m, &rd)) { read_local_done(tr, &r_ref, &rd, AS_ERR_KEY_MISMATCH); return TRANS_DONE_ERROR; } if ((m->info1 & AS_MSG_INFO1_GET_NO_BINS) != 0) { tr->generation = r->generation; tr->void_time = r->void_time; tr->last_update_time = r->last_update_time; read_local_done(tr, &r_ref, &rd, AS_OK); return TRANS_DONE_SUCCESS; } if ((result = as_storage_rd_load_n_bins(&rd)) < 0) { cf_warning_digest(AS_RW, &tr->keyd, "{%s} read_local: failed as_storage_rd_load_n_bins() ", ns->name); read_local_done(tr, &r_ref, &rd, -result); return TRANS_DONE_ERROR; } as_bin stack_bins[ns->storage_data_in_memory ? 0 : rd.n_bins]; if ((result = as_storage_rd_load_bins(&rd, stack_bins)) < 0) { cf_warning_digest(AS_RW, &tr->keyd, "{%s} read_local: failed as_storage_rd_load_bins() ", ns->name); read_local_done(tr, &r_ref, &rd, -result); return TRANS_DONE_ERROR; } if (! as_bin_inuse_has(&rd)) { cf_warning_digest(AS_RW, &tr->keyd, "{%s} read_local: found record with no bins ", ns->name); read_local_done(tr, &r_ref, &rd, AS_ERR_UNKNOWN); return TRANS_DONE_ERROR; } uint32_t bin_count = (m->info1 & AS_MSG_INFO1_GET_ALL) != 0 ? rd.n_bins : m->n_ops; as_msg_op* ops[bin_count]; as_msg_op** p_ops = ops; as_bin* response_bins[bin_count]; uint16_t n_bins = 0; as_bin result_bins[bin_count]; uint32_t n_result_bins = 0; if ((m->info1 & AS_MSG_INFO1_GET_ALL) != 0) { p_ops = NULL; n_bins = rd.n_bins; as_bin_get_all_p(&rd, response_bins); } else { if (m->n_ops == 0) { cf_warning_digest(AS_RW, &tr->keyd, "{%s} read_local: bin op(s) expected, none present ", ns->name); read_local_done(tr, &r_ref, &rd, AS_ERR_PARAMETER); return TRANS_DONE_ERROR; } bool respond_all_ops = (m->info2 & AS_MSG_INFO2_RESPOND_ALL_OPS) != 0; as_msg_op* op = 0; int n = 0; while ((op = as_msg_op_iterate(m, op, &n)) != NULL) { if (op->op == AS_MSG_OP_READ) { as_bin* b = as_bin_get_from_buf(&rd, op->name, op->name_sz); if (b || respond_all_ops) { ops[n_bins] = op; response_bins[n_bins++] = b; } } else if (op->op == AS_MSG_OP_CDT_READ) { as_bin* b = as_bin_get_from_buf(&rd, op->name, op->name_sz); if (b) { as_bin* rb = &result_bins[n_result_bins]; as_bin_set_empty(rb); if ((result = as_bin_cdt_read_from_client(b, op, rb)) < 0) { cf_warning_digest(AS_RW, &tr->keyd, "{%s} read_local: failed as_bin_cdt_read_from_client() ", ns->name); destroy_stack_bins(result_bins, n_result_bins); read_local_done(tr, &r_ref, &rd, -result); return TRANS_DONE_ERROR; } if (as_bin_inuse(rb)) { n_result_bins++; ops[n_bins] = op; response_bins[n_bins++] = rb; } else if (respond_all_ops) { ops[n_bins] = op; response_bins[n_bins++] = NULL; } } else if (respond_all_ops) { ops[n_bins] = op; response_bins[n_bins++] = NULL; } } else { cf_warning_digest(AS_RW, &tr->keyd, "{%s} read_local: unexpected bin op %u ", ns->name, op->op); destroy_stack_bins(result_bins, n_result_bins); read_local_done(tr, &r_ref, &rd, AS_ERR_PARAMETER); return TRANS_DONE_ERROR; } } } cf_dyn_buf_define_size(db, 16 * 1024); if (tr->origin != FROM_BATCH) { db.used_sz = db.alloc_sz; db.buf = (uint8_t*)as_msg_make_response_msg(tr->result_code, r->generation, r->void_time, p_ops, response_bins, n_bins, ns, (cl_msg*)dyn_bufdb, &db.used_sz, as_transaction_trid(tr)); db.is_stack = db.buf == dyn_bufdb; // Note - not bothering to correct alloc_sz if buf was allocated. } else { tr->generation = r->generation; tr->void_time = r->void_time; tr->last_update_time = r->last_update_time; // Since as_batch_add_result() constructs response directly in shared // buffer to avoid extra copies, can't use db. send_read_response(tr, p_ops, response_bins, n_bins, NULL); } destroy_stack_bins(result_bins, n_result_bins); as_storage_record_close(&rd); as_record_done(&r_ref, ns); // Now that we're not under the record lock, send the message we just built. if (db.used_sz != 0) { send_read_response(tr, NULL, NULL, 0, &db); cf_dyn_buf_free(&db); tr->from.proto_fd_h = NULL; } return TRANS_DONE_SUCCESS; }