as_record * SourceRecord::record() { if (!record_) { record_ = as_record_new(11); as_record_set_int64(record_, "latest_time", time_); as_record_set_str(record_, "adv_id", advId_.c_str()); as_record_set_str(record_, "sid", sid_.c_str()); as_record_set_str(record_, "adx_id", adxId_.c_str()); as_record_set_str(record_, "mt_uid", mtUid_.c_str()); as_record_set_str(record_, "pid", pid_.c_str()); as_record_set_str(record_, "request_id", requestId_.c_str()); as_record_set_str(record_, "create_id", createId_.c_str()); as_record_set_str(record_, "geo_id", geoId_.c_str()); as_record_set_str(record_, "referer_url", refererUrl_.c_str()); as_record_set_str(record_, "bid_price", bidPrice_.c_str()); } return record_; }
/** * Look up a record by key, then return all bins. * * @param as The aerospike instance to use for this operation. * @param err The as_error to be populated if an error occurs. * @param policy The policy to use for this operation. If NULL, then the default policy will be used. * @param key The key of the record. * @param rec The record to be populated with the data from request. * * @return AEROSPIKE_OK if successful. Otherwise an error. */ as_status aerospike_key_get( aerospike * as, as_error * err, const as_policy_read * policy, const as_key * key, as_record ** rec) { // we want to reset the error so, we have a clean state as_error_reset(err); // resolve policies as_policy_read p; as_policy_read_resolve(&p, &as->config.policies, policy); uint32_t timeout = p.timeout == UINT32_MAX ? 0 : p.timeout; uint32_t gen = 0; uint32_t ttl = 0; int nvalues = 0; cl_bin * values = NULL; cl_rv rc = CITRUSLEAF_OK; switch ( p.key ) { case AS_POLICY_KEY_DIGEST: { as_digest * digest = as_key_digest((as_key *) key); rc = citrusleaf_get_all_digest_getsetname(as->cluster, key->ns, (cf_digest *) digest->value, &values, &nvalues, timeout, &gen, NULL, &ttl); break; } case AS_POLICY_KEY_SEND: { cl_object okey; asval_to_clobject((as_val *) key->valuep, &okey); as_digest * digest = as_key_digest((as_key *) key); rc = citrusleaf_get_all(as->cluster, key->ns, key->set, &okey, (cf_digest*)digest->value, &values, &nvalues, timeout, &gen, &ttl); break; } default: { // ERROR CASE break; } } if ( rc == CITRUSLEAF_OK && rec != NULL ) { as_record * r = *rec; if ( r == NULL ) { r = as_record_new(0); } if ( r->bins.entries == NULL ) { r->bins.capacity = nvalues; r->bins.size = 0; r->bins.entries = malloc(sizeof(as_bin) * nvalues); r->bins._free = true; } clbins_to_asrecord(values, nvalues, r); r->gen = (uint16_t) gen; r->ttl = ttl; *rec = r; } if ( values != NULL ) { // We are freeing the bins' objects, as opposed to bins themselves. citrusleaf_bins_free(values, nvalues); free(values); } return as_error_fromrc(err,rc); }
/** * Lookup a record by key, then perform specified operations. * * ~~~~~~~~~~{.c} * as_key key; * as_key_init(&key, "ns", "set", "key"); * * as_operations ops; * as_operations_inita(&ops,2); * as_operations_append_int64(&ops, AS_OPERATOR_INCR, "bin1", 456); * as_operations_append_str(&ops, AS_OPERATOR_APPEND, "bin1", "def"); * * if ( aerospike_key_remove(&as, &err, NULL, &key, &ops) != AEROSPIKE_OK ) { * fprintf(stderr, "error(%d) %s at [%s:%d]", err.code, err.message, err.file, err.line); * } * ~~~~~~~~~~ * * @param as The aerospike instance to use for this operation. * @param err The as_error to be populated if an error occurs. * @param policy The policy to use for this operation. If NULL, then the default policy will be used. * @param key The key of the record. * @param ops The operations to perform on the record. * @param rec The record to be populated with the data from AS_OPERATOR_READ operations. * * @return AEROSPIKE_OK if successful. Otherwise an error. */ as_status aerospike_key_operate( aerospike * as, as_error * err, const as_policy_operate * policy, const as_key * key, const as_operations * ops, as_record ** rec) { // we want to reset the error so, we have a clean state as_error_reset(err); // resolve policies as_policy_operate p; as_policy_operate_resolve(&p, &as->config.policies, policy); cl_write_parameters wp; aspolicyoperate_to_clwriteparameters(&p, ops, &wp); uint32_t gen = 0; uint32_t ttl = 0; int n_operations = ops->binops.size; cl_operation * operations = (cl_operation *) alloca(sizeof(cl_operation) * n_operations); int n_read_ops = 0; as_bin_name * read_op_bins = alloca(sizeof(as_bin_name) * n_operations); for(int i=0; i<n_operations; i++) { cl_operation * clop = &operations[i]; as_binop * op = &ops->binops.entries[i]; // Length check already done on as_bin name length. For performance we // we'll leave out this down-size check since this is a temporary shim // and we know the CL and AS limits are the same... // if ( strlen(op->bin.name) > CL_BINNAME_SIZE - 1 ) { // return as_error_update(err, AEROSPIKE_ERR_PARAM, "bin name too long: %s", op->bin.name); // } strcpy(clop->bin.bin_name, op->bin.name); clop->op = (cl_operator)op->op; // Collect bin names that are read. if (op->op == AS_OPERATOR_READ) { strcpy(read_op_bins[n_read_ops++], op->bin.name); } asbinvalue_to_clobject(op->bin.valuep, &clop->bin.object); } cl_rv rc = CITRUSLEAF_OK; switch ( p.key ) { case AS_POLICY_KEY_DIGEST: { as_digest * digest = as_key_digest((as_key *) key); rc = citrusleaf_operate_digest(as->cluster, key->ns, key->set, (cf_digest *) digest->value, operations, n_operations, &wp, &gen, &ttl); break; } case AS_POLICY_KEY_SEND: { cl_object okey; asval_to_clobject((as_val *) key->valuep, &okey); as_digest * digest = as_key_digest((as_key *) key); rc = citrusleaf_operate(as->cluster, key->ns, key->set, &okey, (cf_digest*)digest->value, operations, n_operations, &wp, &gen, &ttl); break; } default: { // ERROR CASE break; } } if ( n_read_ops != 0 && rc == CITRUSLEAF_OK && rec != NULL ) { as_record * r = *rec; if ( r == NULL ) { r = as_record_new(0); } if ( r->bins.entries == NULL ) { r->bins.capacity = n_read_ops; r->bins.size = 0; r->bins.entries = malloc(sizeof(as_bin) * n_read_ops); r->bins._free = true; } r->gen = (uint16_t) gen; r->ttl = ttl; // This works around an existing client bug where the data returned for // a read operation is stored in the first bin struct with that bin // name, not necessarily the bin struct corresponding to the read. for (int i = 0; i < n_read_ops; i++) { for (int j = 0; j < n_operations; j++) { if (strcmp(read_op_bins[i], operations[j].bin.bin_name) == 0) { clbin_to_asrecord(&operations[j].bin, r); citrusleaf_object_free(&operations[j].bin.object); break; } } } *rec = r; } return as_error_fromrc(err,rc); }
/** * Check if a record exists in the cluster via its key. * * @param as The aerospike instance to use for this operation. * @param err The as_error to be populated if an error occurs. * @param policy The policy to use for this operation. If NULL, then the default policy will be used. * @param key The key of the record. * @param record The record to populated with metadata if record exists, otherwise NULL * * @return AEROSPIKE_OK if successful. Otherwise an error. */ as_status aerospike_key_exists( aerospike * as, as_error * err, const as_policy_read * policy, const as_key * key, as_record ** rec) { // we want to reset the error so, we have a clean state as_error_reset(err); // resolve policies as_policy_read p; as_policy_read_resolve(&p, &as->config.policies, policy); uint32_t timeout = p.timeout == UINT32_MAX ? 0 : p.timeout; uint32_t gen = 0; uint32_t ttl = 0; // TODO - a version of 'exists' that returns all metadata int nvalues = 0; cl_bin * values = NULL; cl_rv rc = CITRUSLEAF_OK; switch ( p.key ) { case AS_POLICY_KEY_DIGEST: { as_digest * digest = as_key_digest((as_key *) key); rc = citrusleaf_exists_digest(as->cluster, key->ns, (cf_digest *) digest->value, values, nvalues, timeout, &gen, &ttl); break; } case AS_POLICY_KEY_SEND: { cl_object okey; asval_to_clobject((as_val *) key->valuep, &okey); as_digest * digest = as_key_digest((as_key *) key); rc = citrusleaf_exists_key(as->cluster, key->ns, key->set, &okey, (cf_digest*)digest->value, values, nvalues, timeout, &gen, &ttl); break; } default: { // ERROR CASE break; } } if ( values != NULL ) { // We are freeing the bins' objects, as opposed to bins themselves. citrusleaf_bins_free(values, nvalues); free(values); } switch(rc) { case CITRUSLEAF_OK: { as_record * r = *rec; if ( r == NULL ) { r = as_record_new(0); } r->gen = (uint16_t) gen; r->ttl = ttl; *rec = r; break; } default: *rec = NULL; break; } return as_error_fromrc(err,rc); }
/** * Lookup a record by key, then return specified bins. * * @param as The aerospike instance to use for this operation. * @param err The as_error to be populated if an error occurs. * @param policy The policy to use for this operation. If NULL, then the default policy will be used. * @param key The key of the record. * @param bins The bins to select. A NULL terminated array of NULL terminated strings. * @param rec The record to be populated with the data from request. * * @return AEROSPIKE_OK if successful. Otherwise an error. */ as_status aerospike_key_select( aerospike * as, as_error * err, const as_policy_read * policy, const as_key * key, const char * bins[], as_record ** rec) { // we want to reset the error so, we have a clean state as_error_reset(err); // resolve policies as_policy_read p; as_policy_read_resolve(&p, &as->config.policies, policy); uint32_t timeout = p.timeout == UINT32_MAX ? 0 : p.timeout; uint32_t gen = 0; uint32_t ttl = 0; int nvalues = 0; cl_bin * values = NULL; for (nvalues = 0; bins[nvalues] != NULL && bins[nvalues][0] != '\0'; nvalues++) ; values = (cl_bin *) alloca(sizeof(cl_bin) * nvalues); for ( int i = 0; i < nvalues; i++ ) { if ( strlen(bins[i]) > AS_BIN_NAME_MAX_LEN ) { return as_error_update(err, AEROSPIKE_ERR_PARAM, "bin name too long: %s", bins[i]); } strcpy(values[i].bin_name, bins[i]); citrusleaf_object_init(&values[i].object); } cl_rv rc = CITRUSLEAF_OK; switch ( p.key ) { case AS_POLICY_KEY_DIGEST: { as_digest * digest = as_key_digest((as_key *) key); rc = citrusleaf_get_digest(as->cluster, key->ns, (cf_digest *) digest->value, values, nvalues, timeout, &gen, &ttl); break; } case AS_POLICY_KEY_SEND: { cl_object okey; asval_to_clobject((as_val *) key->valuep, &okey); as_digest * digest = as_key_digest((as_key *) key); rc = citrusleaf_get(as->cluster, key->ns, key->set, &okey, (cf_digest*)digest->value, values, nvalues, timeout, &gen, &ttl); break; } default: { // ERROR CASE break; } } if ( rc == CITRUSLEAF_OK && rec != NULL ) { as_record * r = *rec; if ( r == NULL ) { r = as_record_new(0); } if ( r->bins.entries == NULL ) { r->bins.capacity = nvalues; r->bins.size = 0; r->bins.entries = malloc(sizeof(as_bin) * nvalues); r->bins._free = true; } clbins_to_asrecord(values, nvalues, r); r->gen = (uint16_t) gen; r->ttl = ttl; *rec = r; } if ( values != NULL ) { // We are freeing the bins' objects, as opposed to bins themselves. citrusleaf_bins_free(values, nvalues); } return as_error_fromrc(err,rc); }
as_status as_command_parse_result(as_error* err, int fd, uint64_t deadline_ms, void* user_data) { // Read header as_proto_msg msg; as_status status = as_socket_read_deadline(err, fd, (uint8_t*)&msg, sizeof(as_proto_msg), deadline_ms); if (status) { return status; } as_proto_swap_from_be(&msg.proto); as_msg_swap_header_from_be(&msg.m); size_t size = msg.proto.sz - msg.m.header_sz; uint8_t* buf = 0; if (size > 0) { // Read remaining message bytes. buf = as_command_init(size); status = as_socket_read_deadline(err, fd, buf, size, deadline_ms); if (status) { as_command_free(buf, size); return status; } } // Parse result code and record. status = msg.m.result_code; as_command_parse_result_data* data = user_data; switch (status) { case AEROSPIKE_OK: { if (data->record) { as_record* rec = *data->record; if (rec) { if (msg.m.n_ops > rec->bins.capacity) { if (rec->bins._free) { free(rec->bins.entries); } rec->bins.capacity = msg.m.n_ops; rec->bins.size = 0; rec->bins.entries = malloc(sizeof(as_bin) * msg.m.n_ops); rec->bins._free = true; } } else { rec = as_record_new(msg.m.n_ops); *data->record = rec; } rec->gen = msg.m.generation; rec->ttl = cf_server_void_time_to_ttl(msg.m.record_ttl); uint8_t* p = as_command_ignore_fields(buf, msg.m.n_fields); as_command_parse_bins(rec, p, msg.m.n_ops, data->deserialize); } break; } case AEROSPIKE_ERR_UDF: { status = as_command_parse_udf_failure(buf, err, &msg.m, status); break; } default: as_error_set_message(err, status, as_error_string(status)); break; } as_command_free(buf, size); return status; }