int main(int argc, char* argv[]) { // Parse command line arguments. if (! example_get_opts(argc, argv, EXAMPLE_BASIC_OPTS)) { exit(-1); } // Connect to the aerospike database cluster. aerospike as; example_connect_to_aerospike(&as); // Start clean. example_remove_test_record(&as); as_error err; as_operations ops; LOG("append 10 values from 0 to 9"); // The first append will create the record and bin. for (int i = 0; i < 10; i++) { as_operations_inita(&ops, 1); as_operations_add_list_append_int64(&ops, "test-bin-1", i); if (aerospike_key_operate(&as, &err, NULL, &g_key, &ops, NULL) != AEROSPIKE_OK) { LOG("aerospike_key_operate() returned %d - %s", err.code, err.message); example_cleanup(&as); exit(-1); } as_operations_destroy(&ops); } if (! example_read_test_record(&as)) { example_cleanup(&as); exit(-1); } LOG("append operations succeeded"); LOG("pop from the tail (index -1)"); as_operations_inita(&ops, 1); as_operations_add_list_pop(&ops, "test-bin-1", -1); as_record *p_rec = NULL; if (aerospike_key_operate(&as, &err, NULL, &g_key, &ops, &p_rec) != AEROSPIKE_OK) { LOG("aerospike_key_operate() returned %d - %s", err.code, err.message); as_operations_destroy(&ops); example_cleanup(&as); exit(-1); } as_operations_destroy(&ops); LOG("pop operation succeeded"); LOG("insert popped value at the head (index 0)"); as_val *val = (as_val *)as_record_get(p_rec, "test-bin-1"); as_operations_inita(&ops, 1); as_operations_add_list_insert(&ops, "test-bin-1", 0, val); if (aerospike_key_operate(&as, &err, NULL, &g_key, &ops, NULL) != AEROSPIKE_OK) { LOG("aerospike_key_operate() returned %d - %s", err.code, err.message); as_operations_destroy(&ops); example_cleanup(&as); exit(-1); } as_record_destroy(p_rec); as_operations_destroy(&ops); LOG("insert operation succeeded"); if (! example_read_test_record(&as)) { example_cleanup(&as); exit(-1); } // Cleanup and disconnect from the database cluster. example_cleanup(&as); LOG("list example successfully completed"); return 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 (as_record_is_expired(r)) { 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), false, false, 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); } } } }
/* ******************************************************************************************************* * Wrapper function to perform an aerospike_key_oeprate within the C client. * * @param as_object_p The C client's aerospike object. * @param as_key_p The C client's as_key that identifies the record. * @param options_p The user's optional policy options to be used if set, else defaults. * @param error_p The as_error to be populated by the function * with the encountered error if any. * @param bin_name_p The bin name to perform operation upon. * @param str The string to be appended in case of operation: append. * @param offset The offset to be incremented by in case of operation: increment. * @param initial_value The initial value to be set if record is absent * in case of operation: increment. * @param time_to_live The ttl for the record in case of operation: touch. * @param operation The operation type. * ******************************************************************************************************* */ extern as_status aerospike_record_operations_ops(aerospike* as_object_p, as_key* as_key_p, zval* options_p, as_error* error_p, int8_t* bin_name_p, int8_t* str, u_int64_t offset, u_int64_t initial_value, u_int64_t time_to_live, u_int64_t operation) { as_status status = AEROSPIKE_OK; as_policy_operate operate_policy; uint32_t serializer_policy; as_record* get_rec = NULL; as_operations ops; as_val* value_p = NULL; as_integer initial_int_val; int16_t initialize_int = 0; const char *select[] = {bin_name_p, NULL}; as_operations_inita(&ops, 1); as_policy_operate_init(&operate_policy); if ((!as_object_p) || (!error_p) || (!as_key_p)) { status = AEROSPIKE_ERR; goto exit; } set_policy(NULL, NULL, &operate_policy, NULL, NULL, &serializer_policy, options_p, error_p); if (AEROSPIKE_OK != (status = (error_p->code))) { DEBUG_PHP_EXT_DEBUG("Unable to set policy"); goto exit; } switch(operation) { case AS_OPERATOR_APPEND: as_operations_add_append_str(&ops, bin_name_p, str); break; case AS_OPERATOR_PREPEND: as_operations_add_prepend_str(&ops, bin_name_p, str); break; case AS_OPERATOR_INCR: if (AEROSPIKE_OK != (status = aerospike_key_select(as_object_p, error_p, NULL, as_key_p, select, &get_rec))) { goto exit; } else { if (NULL != (value_p = (as_val *) as_record_get (get_rec, bin_name_p))) { if (AS_NIL == value_p->type) { as_integer_init(&initial_int_val, initial_value); initialize_int = 1; if (!as_operations_add_write(&ops, bin_name_p, (as_bin_value*) &initial_int_val)) { status = AEROSPIKE_ERR; goto exit; } } else { as_operations_add_incr(&ops, bin_name_p, offset); } } else { status = AEROSPIKE_ERR; goto exit; } } break; case AS_OPERATOR_TOUCH: ops.ttl = time_to_live; as_operations_add_touch(&ops); break; default: status = AEROSPIKE_ERR; goto exit; break; } if (AEROSPIKE_OK != (status = aerospike_key_operate(as_object_p, error_p, &operate_policy, as_key_p, &ops, &get_rec))) { goto exit; } exit: as_operations_destroy(&ops); if (get_rec) { as_record_destroy(get_rec); } if (initialize_int) { as_integer_destroy(&initial_int_val); } return status; }