/** * Set specified bin's value to an as_map. * as_stringmap map; * as_stringmap_init(&map); * as_stringmap_set_int64(&map, "a", 1); * as_stringmap_set_int64(&map, "b", 2); * as_stringmap_set_int64(&map, "c", 3); * as_record_set_map(rec, "bin", &map); * @param rec - the record containing the bin * @param name - the name of the bin * @param value - the value of the bin * @return true on success, false on failure. */ bool as_record_set_map(as_record * rec, const as_bin_name name, as_map * value) { as_bin * bin = as_record_bin_forupdate(rec, name); if ( !bin ) return false; as_bin_init(bin, name, (as_bin_value *) value); return true; }
// Does not check bin name length. as_bin * as_bin_create(as_storage_rd *rd, const char *name) { if (rd->ns->single_bin) { if (as_bin_inuse(rd->bins)) { cf_crash(AS_BIN, "single bin create found bin in use"); } as_bin_init_nameless(rd->bins); return rd->bins; } as_bin *b = NULL; for (uint16_t i = 0; i < rd->n_bins; i++) { if (! as_bin_inuse(&rd->bins[i])) { b = &rd->bins[i]; break; } } if (b) { as_bin_init(rd->ns, b, name); } return b; }
/** * Add a AS_OPERATOR_WRITE bin operation. * * @param ops The `as_operations` to append the operation to. * @param name The name of the bin to perform the operation on. * @param value The value to be used in the operation. * * @return true on success. Otherwise an error occurred. */ bool as_operations_add_write(as_operations * ops, const as_bin_name name, as_bin_value * value) { as_binop * binop = as_binop_forappend(ops, AS_OPERATOR_WRITE, name); if ( !binop ) return false; as_bin_init(&binop->bin, name, value); return true; }
static bool as_operations_add_cdt_read(as_operations *ops, const as_bin_name name, as_bin_value *value) { as_binop *binop = as_binop_forappend(ops, AS_OPERATOR_CDT_READ, name); if (! binop) { return false; } as_bin_init(&binop->bin, name, value); return true; }
// Does not check bin name length. // Checks bin name quota - use appropriately. as_bin * as_bin_get_or_create(as_storage_rd *rd, const char *name) { if (rd->ns->single_bin) { if (! as_bin_inuse_has(rd)) { as_bin_init_nameless(rd->bins); } return rd->bins; } uint32_t id = (uint32_t)-1; uint16_t i; as_bin *b; if (cf_vmapx_get_index(rd->ns->p_bin_name_vmap, name, &id) == CF_VMAPX_OK) { for (i = 0; i < rd->n_bins; i++) { b = &rd->bins[i]; if (! as_bin_inuse(b)) { break; } if ((uint32_t)b->id == id) { return b; } } } else { if (cf_vmapx_count(rd->ns->p_bin_name_vmap) >= BIN_NAMES_QUOTA) { cf_warning(AS_BIN, "{%s} bin-name quota full - can't add new bin-name %s", rd->ns->name, name); return NULL; } i = as_bin_inuse_count(rd); } if (i >= rd->n_bins) { cf_crash(AS_BIN, "ran out of allocated bins in rd"); } b = &rd->bins[i]; if (id == (uint32_t)-1) { as_bin_init(rd->ns, b, name); } else { as_bin_init_nameless(b); b->id = (uint16_t)id; } return b; }
/* Internal Function: Packs up passed in data into as_bin which is * used to send result after the UDF execution. */ static bool make_send_bin(as_namespace *ns, as_bin *bin, uint8_t **sp_pp, uint sp_sz, const char *key, size_t klen, int vtype, void *val, size_t vlen) { uint sz = 0; int tsz = sz + vlen + as_particle_get_base_size(vtype); uint8_t * v = NULL; int64_t swapped_int = 0; uint8_t *sp_p = *sp_pp; if (tsz > sp_sz) { sp_p = cf_malloc(tsz); if (!sp_p) { cf_warning(AS_UDF, "data too much. malloc failed. going down. bin %s not sent back", key); return(-1); } } as_bin_init(ns, bin, (byte *) key/*name*/, klen/*namelen*/, 0/*version*/); switch (vtype) { case AS_PARTICLE_TYPE_NULL: { v = NULL; break; } case AS_PARTICLE_TYPE_INTEGER: { if (vlen != 8) { cf_crash(AS_UDF, "unexpected int %d", vlen); } swapped_int = __be64_to_cpup(val); v = (uint8_t *) &swapped_int; break; } case AS_PARTICLE_TYPE_BLOB: case AS_PARTICLE_TYPE_STRING: case AS_PARTICLE_TYPE_LIST: case AS_PARTICLE_TYPE_MAP: v = val; break; default: { cf_warning(AS_UDF, "unrecognized object type %d ignored", vtype); return -1; } } as_particle_frombuf(bin, vtype, v, vlen, sp_p, ns->storage_data_in_memory); *sp_pp = sp_p; return 0; }
/* as_bin_create * Create a new bin with the specified name in a record * NB: You must be holding the value lock for the record! */ as_bin * as_bin_create(as_record *r, as_storage_rd *rd, byte *name, size_t namesz, uint version) { cf_detail(AS_BIN, "as_bin_create: %s %zu", name, namesz); // what policy should we make for too-large bins passed in? if (namesz > (AS_ID_BIN_SZ - 1)) { cf_warning(AS_RW, "WARNING: too large bin name %d passed in, internal error", namesz); return(NULL); } as_bin *b = 0; if (rd->ns->single_bin) { if (as_bin_inuse(rd->bins)) { cf_warning(AS_RW, "WARNING: cannot allocate more than 1 bin in a single bin namespace"); return (NULL); } // do not store bin name byte c = 0; as_bin_init(rd->ns, rd->bins, &c, 0, version); return (rd->bins); } // seek for an empty one for (uint16_t i = 0; i < rd->n_bins; i++) { if (! as_bin_inuse(&rd->bins[i])) { b = &rd->bins[i]; break; } } if (b) { as_bin_init(rd->ns, b, name, namesz, version); } return (b); }
/* 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()
/* 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; }