// ---------------------------------------------------------------------------------- // // def touch(key, options = {}) // // params: // key - AeropsikeC::Key object // options - hash of options: // ttl: time to live record (default: 0) // policy: AerospikeC::Policy for operate // // ------ // RETURN: // 1. hash representing record header // 2. nil when AEROSPIKE_ERR_RECORD_NOT_FOUND // // @TODO options policy // static VALUE touch(int argc, VALUE * argv, VALUE self) { rb_aero_TIMED(tm); as_error err; as_status status; aerospike * as = rb_aero_CLIENT; VALUE key; VALUE options; rb_scan_args(argc, argv, "11", &key, &options); // default values for optional arguments if ( NIL_P(options) ) { options = rb_hash_new(); rb_hash_aset(options, ttl_sym, rb_zero); } else { if ( TYPE(rb_hash_aref(options, ttl_sym)) != T_FIXNUM ) { // check ttl option rb_raise(rb_aero_OptionError, "[AerospikeC::Client][put] ttl must be an integer"); } } as_key * k = rb_aero_KEY; as_record * rec = NULL; as_operations ops; as_operations_inita(&ops, 1); as_operations_add_touch(&ops); ops.ttl = FIX2INT( rb_hash_aref(options, ttl_sym) ); as_policy_operate * policy = get_policy(options); if ( ( status = aerospike_key_operate(as, &err, policy, k, &ops, &rec) ) != AEROSPIKE_OK ) { as_operations_destroy(&ops); if ( status == AEROSPIKE_ERR_RECORD_NOT_FOUND ) { rb_aero_logger(AS_LOG_LEVEL_WARN, &tm, 2, rb_str_new2("[Client][touch] AEROSPIKE_ERR_RECORD_NOT_FOUND"), rb_aero_KEY_INFO); return Qnil; } raise_as_error(err); } VALUE header = rb_hash_new(); rb_hash_aset(header, rb_str_new2("gen"), INT2FIX(rec->gen)); rb_hash_aset(header, rb_str_new2("expire_in"), INT2FIX(rec->ttl)); as_record_destroy(rec); as_operations_destroy(&ops); rb_aero_logger(AS_LOG_LEVEL_DEBUG, &tm, 2, rb_str_new2("[Client][touch] success"), rb_aero_KEY_INFO); return header; }
/** ******************************************************************************************************* * This function invokes csdk's API's. * * @param self AerospikeClient object * @param err The as_error to be populated by the function * with the encountered error if any. * @param key The C client's as_key that identifies the record. * @param py_list The list containing op, bin and value. * @param py_meta The metadata for the operation. * @param operate_policy_p The value for operate policy. ******************************************************************************************************* */ static PyObject * AerospikeClient_Operate_Invoke( AerospikeClient * self, as_error *err, as_key * key, PyObject * py_list, PyObject * py_meta, as_policy_operate * operate_policy_p) { as_val* put_val = NULL; char* bin = NULL; char* val = NULL; long offset = 0; double double_offset = 0.0; uint32_t ttl = 0; long operation = 0; int i = 0; PyObject * py_rec = NULL; PyObject * py_ustr = NULL; PyObject * py_ustr1 = NULL; PyObject * py_bin = NULL; as_record * rec = NULL; as_static_pool static_pool; memset(&static_pool, 0, sizeof(static_pool)); as_operations ops; Py_ssize_t size = PyList_Size(py_list); as_operations_inita(&ops, size); if (!self || !self->as) { as_error_update(err, AEROSPIKE_ERR_PARAM, "Invalid aerospike object"); goto CLEANUP; } if(py_meta) { AerospikeClient_CheckForMeta(py_meta, &ops, err); } if (err->code != AEROSPIKE_OK) { goto CLEANUP; } for ( i = 0; i < size; i++) { PyObject * py_val = PyList_GetItem(py_list, i); operation = -1; offset = 0; double_offset = 0.0; if ( PyDict_Check(py_val) ) { PyObject *key_op = NULL, *value = NULL; PyObject * py_value = NULL; Py_ssize_t pos = 0; while (PyDict_Next(py_val, &pos, &key_op, &value)) { if ( ! PyString_Check(key_op) ) { as_error_update(err, AEROSPIKE_ERR_CLIENT, "A operation key must be a string."); goto CLEANUP; } else { char * name = PyString_AsString(key_op); if(!strcmp(name,"op") && (PyInt_Check(value) || PyLong_Check(value))) { operation = PyInt_AsLong(value); } else if (!strcmp(name, "bin")) { py_bin = value; } else if(!strcmp(name, "val")) { py_value = value; } else { as_error_update(err, AEROSPIKE_ERR_PARAM, "operation can contain only op, bin and val keys"); goto CLEANUP; } } } if (py_bin) { if (PyUnicode_Check(py_bin)) { py_ustr = PyUnicode_AsUTF8String(py_bin); bin = PyString_AsString(py_ustr); } else if (PyString_Check(py_bin)) { bin = PyString_AsString(py_bin); } else { as_error_update(err, AEROSPIKE_ERR_PARAM, "Bin name should be of type string"); goto CLEANUP; } } else if (!py_bin && operation != AS_OPERATOR_TOUCH) { as_error_update(err, AEROSPIKE_ERR_PARAM, "Bin is not given"); goto CLEANUP; } if (py_value) { if (check_type(self, py_value, operation, err)) { goto CLEANUP; } else if (PyString_Check(py_value) && (operation == AS_OPERATOR_INCR)) { char * incr_string = PyString_AsString(py_value); int incr_value = 0, sign = 1; if (strlen(incr_string) > 15) { as_error_update(err, AEROSPIKE_ERR_PARAM, "Unsupported string length for increment operation"); goto CLEANUP; } if (*incr_string == '-') { incr_string = incr_string + 1; sign = -1; } else if (*incr_string == '+') { incr_string = incr_string + 1; sign = 1; } while (*incr_string != '\0') { if (*incr_string >= 48 && *incr_string <= 57) { incr_value = (incr_value * 10) + (*incr_string ^ 0x30); } else { as_error_update(err, AEROSPIKE_ERR_PARAM, "Unsupported operand type(s) for +: 'int' and 'str'"); goto CLEANUP; } incr_string = incr_string + 1; } incr_value = incr_value * sign; py_value = PyInt_FromLong(incr_value); } } else if ((!py_value) && (operation != AS_OPERATOR_READ)) { as_error_update(err, AEROSPIKE_ERR_PARAM, "Value should be given"); goto CLEANUP; } switch(operation) { case AS_OPERATOR_APPEND: if (PyUnicode_Check(py_value)) { py_ustr1 = PyUnicode_AsUTF8String(py_value); val = PyString_AsString(py_ustr1); } else { val = PyString_AsString(py_value); } as_operations_add_append_str(&ops, bin, val); break; case AS_OPERATOR_PREPEND: if (PyUnicode_Check(py_value)) { py_ustr1 = PyUnicode_AsUTF8String(py_value); val = PyString_AsString(py_ustr1); } else { val = PyString_AsString(py_value); } as_operations_add_prepend_str(&ops, bin, val); break; case AS_OPERATOR_INCR: if (PyInt_Check(py_value)) { offset = PyInt_AsLong(py_value); as_operations_add_incr(&ops, bin, offset); } else if ( PyLong_Check(py_value) ) { offset = PyLong_AsLong(py_value); if(-1 == offset) { as_error_update(err, AEROSPIKE_ERR_PARAM, "integer value exceeds sys.maxsize"); goto CLEANUP; } as_operations_add_incr(&ops, bin, offset); } else if (PyFloat_Check(py_value)) { double_offset = PyFloat_AsDouble(py_value); as_operations_add_incr_double(&ops, bin, double_offset); } break; case AS_OPERATOR_TOUCH: if (PyInt_Check(py_value)) { ops.ttl = PyInt_AsLong(py_value); } else if ( PyLong_Check(py_value) ) { ttl = PyLong_AsLong(py_value); if((uint32_t)-1 == ttl) { as_error_update(err, AEROSPIKE_ERR_PARAM, "integer value for ttl exceeds sys.maxsize"); goto CLEANUP; } ops.ttl = ttl; } as_operations_add_touch(&ops); break; case AS_OPERATOR_READ: as_operations_add_read(&ops, bin); break; case AS_OPERATOR_WRITE: pyobject_to_astype_write(self, err, bin, py_value, &put_val, &ops, &static_pool, SERIALIZER_PYTHON); if (err->code != AEROSPIKE_OK) { goto CLEANUP; } as_operations_add_write(&ops, bin, (as_bin_value *) put_val); break; default: as_error_update(err, AEROSPIKE_ERR_PARAM, "Invalid operation given"); } } } // Initialize record as_record_init(rec, 0); aerospike_key_operate(self->as, err, operate_policy_p, key, &ops, &rec); if (err->code != AEROSPIKE_OK) { as_error_update(err, err->code, NULL); goto CLEANUP; } if(rec) { record_to_pyobject(err, rec, key, &py_rec); } CLEANUP: if (py_ustr) { Py_DECREF(py_ustr); } if (py_ustr1) { Py_DECREF(py_ustr1); } if (rec) { as_record_destroy(rec); } if (key->valuep) { as_key_destroy(key); } if (put_val) { as_val_destroy(put_val); } if ( err->code != AEROSPIKE_OK ) { PyObject * py_err = NULL; error_to_pyobject(err, &py_err); PyObject *exception_type = raise_exception(err); PyErr_SetObject(exception_type, py_err); Py_DECREF(py_err); return NULL; } if (py_rec) { return py_rec; } else { return PyLong_FromLong(0); } }
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; // Create an as_record object with one (integer value) bin. By using // as_record_inita(), we won't need to destroy the record if we only set // bins using as_record_set_int64(). as_record rec; as_record_inita(&rec, 1); as_record_set_int64(&rec, "test-bin", 1234); // Set the TTL of the record so it will last a minute. rec.ttl = 60; // Log its contents. LOG("as_record object to write to database:"); example_dump_record(&rec); // Write the record to the database. if (aerospike_key_put(&as, &err, NULL, &g_key, &rec) != AEROSPIKE_OK) { LOG("aerospike_key_put() returned %d - %s", err.code, err.message); example_cleanup(&as); exit(-1); } LOG("write succeeded"); if (! example_read_test_record(&as)) { example_cleanup(&as); exit(-1); } // Create an as_operations object with a touch operation. Generally, if // using as_operations_inita(), we won't need to destroy the object unless // we call as_operations_add_write() with an externally allocated // as_bin_value. as_operations ops; as_operations_inita(&ops, 1); as_operations_add_touch(&ops); // Set the TTL of the record so it will last two minutes. ops.ttl = 120; // Log the operation. LOG("as_operations object to apply to database:"); example_dump_operations(&ops); // Apply the operation. Note that it does increment the record generation. 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); } LOG("operation succeeded"); if (! example_read_test_record(&as)) { example_cleanup(&as); exit(-1); } // Cleanup and disconnect from the database cluster. example_cleanup(&as); LOG("touch example successfully completed"); return 0; }
/** ******************************************************************************************************* * This function invokes csdk's API's. * * @param self AerospikeClient object * @param err The as_error to be populated by the function * with the encountered error if any. * @param key The C client's as_key that identifies the record. * @param py_list The list containing op, bin and value. * @param py_meta The metadata for the operation. * @param operate_policy_p The value for operate policy. ******************************************************************************************************* */ static PyObject * AerospikeClient_Operate_Invoke( AerospikeClient * self, as_error *err, as_key * key, PyObject * py_list, PyObject * py_meta, as_policy_operate * operate_policy_p) { as_val* put_val = NULL; char* bin = NULL; char* val = NULL; long offset = 0; double double_offset = 0.0; uint32_t ttl = 0; long operation = 0; int i = 0; PyObject * py_rec = NULL; PyObject * py_ustr = NULL; PyObject * py_ustr1 = NULL; PyObject * py_bin = NULL; as_record * rec = NULL; as_static_pool static_pool; memset(&static_pool, 0, sizeof(static_pool)); as_operations ops; Py_ssize_t size = PyList_Size(py_list); as_operations_inita(&ops, size); if (!self || !self->as) { as_error_update(err, AEROSPIKE_ERR_PARAM, "Invalid aerospike object"); goto CLEANUP; } if(py_meta) { AerospikeClient_CheckForMeta(py_meta, &ops, err); } if (err->code != AEROSPIKE_OK) { goto CLEANUP; } for ( i = 0; i < size; i++) { PyObject * py_val = PyList_GetItem(py_list, i); operation = -1; offset = 0; double_offset = 0.0; if ( PyDict_Check(py_val) ) { PyObject *key_op = NULL, *value = NULL; PyObject * py_value = NULL; Py_ssize_t pos = 0; while (PyDict_Next(py_val, &pos, &key_op, &value)) { if ( ! PyString_Check(key_op) ) { as_error_update(err, AEROSPIKE_ERR_CLIENT, "A operation key must be a string."); goto CLEANUP; } else { char * name = PyString_AsString(key_op); if(!strcmp(name,"op") && (PyInt_Check(value) || PyLong_Check(value))) { operation = PyInt_AsLong(value); } else if (!strcmp(name, "bin")) { py_bin = value; } else if(!strcmp(name, "val")) { py_value = value; } else { as_error_update(err, AEROSPIKE_ERR_PARAM, "operation can contain only op, bin and val keys"); goto CLEANUP; } } } if (py_bin) { if (PyUnicode_Check(py_bin)) { py_ustr = PyUnicode_AsUTF8String(py_bin); bin = PyString_AsString(py_ustr); } else if (PyString_Check(py_bin)) { bin = PyString_AsString(py_bin); } else if (PyByteArray_Check(py_bin)) { bin = PyByteArray_AsString(py_bin); } else { as_error_update(err, AEROSPIKE_ERR_PARAM, "Bin name should be of type string"); goto CLEANUP; } if (self->strict_types) { if (strlen(bin) > AS_BIN_NAME_MAX_LEN) { if (py_ustr) { Py_DECREF(py_ustr); py_ustr = NULL; } as_error_update(err, AEROSPIKE_ERR_BIN_NAME, "A bin name should not exceed 14 characters limit"); goto CLEANUP; } } } else if (!py_bin && operation != AS_OPERATOR_TOUCH) { as_error_update(err, AEROSPIKE_ERR_PARAM, "Bin is not given"); goto CLEANUP; } if (py_value) { if (self->strict_types) { if (check_type(self, py_value, operation, err)) { goto CLEANUP; } } } else if ((!py_value) && (operation != AS_OPERATOR_READ && operation != AS_OPERATOR_TOUCH)) { as_error_update(err, AEROSPIKE_ERR_PARAM, "Value should be given"); goto CLEANUP; } switch(operation) { case AS_OPERATOR_APPEND: if (PyUnicode_Check(py_value)) { py_ustr1 = PyUnicode_AsUTF8String(py_value); val = PyString_AsString(py_ustr1); as_operations_add_append_str(&ops, bin, val); } else if (PyString_Check(py_value)) { val = PyString_AsString(py_value); as_operations_add_append_str(&ops, bin, val); } else if (PyByteArray_Check(py_value)) { as_bytes *bytes; GET_BYTES_POOL(bytes, &static_pool, err); serialize_based_on_serializer_policy(self, SERIALIZER_PYTHON, &bytes, py_value, err); as_operations_add_append_raw(&ops, bin, bytes->value, bytes->size); } else { if (!self->strict_types || !strcmp(py_value->ob_type->tp_name, "aerospike.null")) { as_operations *pointer_ops = &ops; as_binop *binop = &pointer_ops->binops.entries[pointer_ops->binops.size++]; binop->op = AS_OPERATOR_APPEND; initialize_bin_for_strictypes(self, err, py_value, binop, bin, &static_pool); } } break; case AS_OPERATOR_PREPEND: if (PyUnicode_Check(py_value)) { py_ustr1 = PyUnicode_AsUTF8String(py_value); val = PyString_AsString(py_ustr1); as_operations_add_prepend_str(&ops, bin, val); } else if (PyString_Check(py_value)) { val = PyString_AsString(py_value); as_operations_add_prepend_str(&ops, bin, val); } else if (PyByteArray_Check(py_value)) { as_bytes *bytes; GET_BYTES_POOL(bytes, &static_pool, err); serialize_based_on_serializer_policy(self, SERIALIZER_PYTHON, &bytes, py_value, err); as_operations_add_prepend_raw(&ops, bin, bytes->value, bytes->size); } else { if (!self->strict_types || !strcmp(py_value->ob_type->tp_name, "aerospike.null")) { as_operations *pointer_ops = &ops; as_binop *binop = &pointer_ops->binops.entries[pointer_ops->binops.size++]; binop->op = AS_OPERATOR_PREPEND; initialize_bin_for_strictypes(self, err, py_value, binop, bin, &static_pool); } } break; case AS_OPERATOR_INCR: if (PyInt_Check(py_value)) { offset = PyInt_AsLong(py_value); as_operations_add_incr(&ops, bin, offset); } else if ( PyLong_Check(py_value) ) { offset = PyLong_AsLong(py_value); if (offset == -1 && PyErr_Occurred()) { if (PyErr_ExceptionMatches(PyExc_OverflowError)) { as_error_update(err, AEROSPIKE_ERR_PARAM, "integer value exceeds sys.maxsize"); goto CLEANUP; } } as_operations_add_incr(&ops, bin, offset); } else if (PyFloat_Check(py_value)) { double_offset = PyFloat_AsDouble(py_value); as_operations_add_incr_double(&ops, bin, double_offset); } else { if (!self->strict_types || !strcmp(py_value->ob_type->tp_name, "aerospike.null")) { as_operations *pointer_ops = &ops; as_binop *binop = &pointer_ops->binops.entries[pointer_ops->binops.size++]; binop->op = AS_OPERATOR_INCR; initialize_bin_for_strictypes(self, err, py_value, binop, bin, &static_pool); } } break; case AS_OPERATOR_TOUCH: ops.ttl = 0; if (py_value && PyInt_Check(py_value)) { ops.ttl = PyInt_AsLong(py_value); } else if (py_value && PyLong_Check(py_value)) { ttl = PyLong_AsLong(py_value); if((uint32_t)-1 == ttl) { as_error_update(err, AEROSPIKE_ERR_PARAM, "integer value for ttl exceeds sys.maxsize"); goto CLEANUP; } ops.ttl = ttl; } as_operations_add_touch(&ops); break; case AS_OPERATOR_READ: as_operations_add_read(&ops, bin); break; case AS_OPERATOR_WRITE: pyobject_to_astype_write(self, err, bin, py_value, &put_val, &ops, &static_pool, SERIALIZER_PYTHON); if (err->code != AEROSPIKE_OK) { goto CLEANUP; } as_operations_add_write(&ops, bin, (as_bin_value *) put_val); break; default: if (self->strict_types) { as_error_update(err, AEROSPIKE_ERR_PARAM, "Invalid operation given"); goto CLEANUP; } } } } // Initialize record as_record_init(rec, 0); Py_BEGIN_ALLOW_THREADS aerospike_key_operate(self->as, err, operate_policy_p, key, &ops, &rec); Py_END_ALLOW_THREADS if (err->code != AEROSPIKE_OK) { as_error_update(err, err->code, NULL); goto CLEANUP; } if(rec) { record_to_pyobject(self, err, rec, key, &py_rec); } CLEANUP: if (py_ustr) { Py_DECREF(py_ustr); } if (py_ustr1) { Py_DECREF(py_ustr1); } if (rec) { as_record_destroy(rec); } if (key->valuep) { as_key_destroy(key); } if (put_val) { as_val_destroy(put_val); } if ( err->code != AEROSPIKE_OK ) { PyObject * py_err = NULL; error_to_pyobject(err, &py_err); PyObject *exception_type = raise_exception(err); PyErr_SetObject(exception_type, py_err); Py_DECREF(py_err); return NULL; } if (py_rec) { return py_rec; } else { return PyLong_FromLong(0); } }
/* ******************************************************************************************************* * 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; }