LIBCOUCHBASE_API libcouchbase_error_t libcouchbase_mtouch_by_key(libcouchbase_t instance, const void *command_cookie, const void *hashkey, libcouchbase_size_t nhashkey, libcouchbase_size_t num_keys, const void * const *keys, const libcouchbase_size_t *nkey, const libcouchbase_time_t *exp) { libcouchbase_server_t *server = NULL; libcouchbase_size_t ii; int vb, idx; /* we need a vbucket config before we can start getting data.. */ if (instance->vbucket_config == NULL) { return libcouchbase_synchandler_return(instance, LIBCOUCHBASE_ETMPFAIL); } if (nhashkey != 0) { (void)vbucket_map(instance->vbucket_config, hashkey, nhashkey, &vb, &idx); server = instance->servers + (libcouchbase_size_t)idx; } for (ii = 0; ii < num_keys; ++ii) { protocol_binary_request_touch req; if (nhashkey == 0) { (void)vbucket_map(instance->vbucket_config, keys[ii], nkey[ii], &vb, &idx); server = instance->servers + (libcouchbase_size_t)idx; } memset(&req, 0, sizeof(req)); req.message.header.request.magic = PROTOCOL_BINARY_REQ; req.message.header.request.opcode = PROTOCOL_BINARY_CMD_TOUCH; req.message.header.request.extlen = 4; req.message.header.request.keylen = ntohs((libcouchbase_uint16_t)nkey[ii]); req.message.header.request.datatype = PROTOCOL_BINARY_RAW_BYTES; req.message.header.request.vbucket = ntohs((libcouchbase_uint16_t)vb); req.message.header.request.bodylen = ntohl((libcouchbase_uint32_t)(nkey[ii]) + 4); req.message.header.request.opaque = ++instance->seqno; /* @todo fix the relative time! */ req.message.body.expiration = htonl((libcouchbase_uint32_t)exp[ii]); libcouchbase_server_start_packet(server, command_cookie, req.bytes, sizeof(req.bytes)); libcouchbase_server_write_packet(server, keys[ii], nkey[ii]); libcouchbase_server_end_packet(server); } libcouchbase_server_send_packets(server); return libcouchbase_synchandler_return(instance, LIBCOUCHBASE_SUCCESS); }
static lcb_error_t get_kvb(int mode, lcb_t instance, int cmd, void *arg) { struct lcb_cntl_vbinfo_st *vbi = arg; if (mode != LCB_CNTL_GET) { return LCB_NOT_SUPPORTED; } if (!instance->vbucket_config) { return LCB_CLIENT_ETMPFAIL; } if (vbi->version != 0) { return LCB_EINVAL; } vbucket_map(instance->vbucket_config, vbi->v.v0.key, vbi->v.v0.nkey, &vbi->v.v0.vbucket, &vbi->v.v0.server_index); (void)cmd; return LCB_SUCCESS; }
LIBCOUCHBASE_API lcb_error_t lcb_unlock(lcb_t instance, const void *command_cookie, lcb_size_t num, const lcb_unlock_cmd_t *const *items) { lcb_size_t ii; /* we need a vbucket config before we can start getting data.. */ if (instance->vbucket_config == NULL) { switch (instance->type) { case LCB_TYPE_CLUSTER: return lcb_synchandler_return(instance, LCB_EBADHANDLE); case LCB_TYPE_BUCKET: default: return lcb_synchandler_return(instance, LCB_CLIENT_ETMPFAIL); } } for (ii = 0; ii < num; ++ii) { lcb_server_t *server; protocol_binary_request_no_extras req; int vb, idx; const void *hashkey = items[ii]->v.v0.hashkey; lcb_size_t nhashkey = items[ii]->v.v0.nhashkey; const void *key = items[ii]->v.v0.key; lcb_size_t nkey = items[ii]->v.v0.nkey; lcb_cas_t cas = items[ii]->v.v0.cas; if (nhashkey == 0) { hashkey = key; nhashkey = nkey; } (void)vbucket_map(instance->vbucket_config, hashkey, nhashkey, &vb, &idx); if (idx < 0 || idx > (int)instance->nservers) { return lcb_synchandler_return(instance, LCB_NO_MATCHING_SERVER); } server = instance->servers + idx; memset(&req, 0, sizeof(req)); req.message.header.request.magic = PROTOCOL_BINARY_REQ; req.message.header.request.keylen = ntohs((lcb_uint16_t)nkey); req.message.header.request.datatype = PROTOCOL_BINARY_RAW_BYTES; req.message.header.request.vbucket = ntohs((lcb_uint16_t)vb); req.message.header.request.bodylen = ntohl((lcb_uint32_t)(nkey)); req.message.header.request.cas = cas; req.message.header.request.opaque = ++instance->seqno; req.message.header.request.opcode = CMD_UNLOCK_KEY; lcb_server_start_packet(server, command_cookie, req.bytes, sizeof(req.bytes)); lcb_server_write_packet(server, key, nkey); lcb_server_end_packet(server); lcb_server_send_packets(server); } return lcb_synchandler_return(instance, LCB_SUCCESS); }
int main(void) { char *root = getenv("srcdir"); DIR *dp; const char *host; char buffer[PATH_MAX]; char key[NKEY]; int idx, i, len; struct dirent *de; VBUCKET_CONFIG_HANDLE vb; unsigned char checksum[16]; unsigned char expected[16]; void *ctx; if (root != NULL) { sprintf(buffer, "%s/tests/config", root); dp = opendir(buffer); if (dp == NULL) { fprintf(stderr, "Skipping ketama check\nFailed to open %s: %s\n", buffer, strerror(errno)); return 0; } while ((de = readdir(dp)) != NULL) { if (strncmp(de->d_name, "ketama", 6) == 0 && strchr(de->d_name, '.') == NULL) { sprintf(buffer, "%s/tests/config/%s", root, de->d_name); fprintf(stderr, "Running ketama test for: %s\n", de->d_name); vb = vbucket_config_parse_file(buffer); assert(vb != NULL); /* check if it conforms to libketama results */ sprintf(buffer, "%s/tests/config/%s.md5sum", root, de->d_name); read_checksum(buffer, expected); memset(checksum, 0, 16); ctx = NULL; for (i = 0; i < 1000000; i++) { len = sprintf(key, "%d", i); vbucket_map(vb, key, len, NULL, &idx); host = vbucket_config_get_server(vb, idx); ctx = hash_md5_update(ctx, host, strlen(host)); } hash_md5_final(ctx, checksum); for (i = 0; i < 16; i++) { assert(checksum[i] == expected[i]); } vbucket_config_destroy(vb); } } closedir(dp); } return 0; }
static libcouchbase_error_t libcouchbase_single_get(libcouchbase_t instance, const void *command_cookie, const void *hashkey, libcouchbase_size_t nhashkey, const void *key, const libcouchbase_size_t nkey, const libcouchbase_time_t *exp, int lock) { libcouchbase_server_t *server; protocol_binary_request_gat req; int vb, idx; libcouchbase_size_t nbytes; if (nhashkey == 0) { nhashkey = nkey; hashkey = key; } (void)vbucket_map(instance->vbucket_config, hashkey, nhashkey, &vb, &idx); if (idx < 0 || idx > (int)instance->nservers) { /* the config says that there is no server yet at that position (-1) */ return libcouchbase_synchandler_return(instance, LIBCOUCHBASE_NETWORK_ERROR); } server = instance->servers + idx; memset(&req, 0, sizeof(req)); req.message.header.request.magic = PROTOCOL_BINARY_REQ; req.message.header.request.keylen = ntohs((libcouchbase_uint16_t)nkey); req.message.header.request.datatype = PROTOCOL_BINARY_RAW_BYTES; req.message.header.request.vbucket = ntohs((libcouchbase_uint16_t)vb); req.message.header.request.bodylen = ntohl((libcouchbase_uint32_t)(nkey)); req.message.header.request.opaque = ++instance->seqno; if (!exp) { req.message.header.request.opcode = PROTOCOL_BINARY_CMD_GET; nbytes = sizeof(req.bytes) - 4; } else { req.message.header.request.opcode = PROTOCOL_BINARY_CMD_GAT; req.message.header.request.extlen = 4; req.message.body.expiration = ntohl((libcouchbase_uint32_t)exp[0]); req.message.header.request.bodylen = ntohl((libcouchbase_uint32_t)(nkey) + 4); nbytes = sizeof(req.bytes); } if (lock) { /* the expiration is optional for GETL command */ req.message.header.request.opcode = CMD_GET_LOCKED; } libcouchbase_server_start_packet(server, command_cookie, req.bytes, nbytes); libcouchbase_server_write_packet(server, key, nkey); libcouchbase_server_end_packet(server); libcouchbase_server_send_packets(server); return libcouchbase_synchandler_return(instance, LIBCOUCHBASE_SUCCESS); }
LIBCOUCHBASE_API libcouchbase_error_t libcouchbase_remove_by_key(libcouchbase_t instance, const void *command_cookie, const void *hashkey, libcouchbase_size_t nhashkey, const void *key, libcouchbase_size_t nkey, libcouchbase_cas_t cas) { libcouchbase_server_t *server; protocol_binary_request_delete req; int vb, idx; /* we need a vbucket config before we can start removing the item.. */ if (instance->vbucket_config == NULL) { return libcouchbase_synchandler_return(instance, LIBCOUCHBASE_ETMPFAIL); } if (nhashkey == 0) { nhashkey = nkey; hashkey = key; } (void)vbucket_map(instance->vbucket_config, hashkey, nhashkey, &vb, &idx); if (idx < 0 || idx > (int)instance->nservers) { /* the config says that there is no server yet at that position (-1) */ return libcouchbase_synchandler_return(instance, LIBCOUCHBASE_NETWORK_ERROR); } server = instance->servers + idx; memset(&req, 0, sizeof(req)); req.message.header.request.magic = PROTOCOL_BINARY_REQ; req.message.header.request.opcode = PROTOCOL_BINARY_CMD_DELETE; req.message.header.request.keylen = ntohs((libcouchbase_uint16_t)nkey); req.message.header.request.extlen = 0; req.message.header.request.datatype = PROTOCOL_BINARY_RAW_BYTES; req.message.header.request.vbucket = ntohs((libcouchbase_uint16_t)vb); req.message.header.request.bodylen = ntohl((libcouchbase_uint32_t)nkey); req.message.header.request.opaque = ++instance->seqno; req.message.header.request.cas = cas; libcouchbase_server_start_packet(server, command_cookie, req.bytes, sizeof(req.bytes)); libcouchbase_server_write_packet(server, key, nkey); libcouchbase_server_end_packet(server); libcouchbase_server_send_packets(server); return libcouchbase_synchandler_return(instance, LIBCOUCHBASE_SUCCESS); }
int main(void) { char *root = getenv("srcdir"); const char *host; char buffer[FILENAME_MAX]; char key[NKEY]; int idx, i, len, ff; VBUCKET_CONFIG_HANDLE vb; unsigned char checksum[16]; unsigned char expected[16]; void *ctx; if (root != NULL) { for (ff = 0; test_cases[ff] != NULL; ++ff) { snprintf(buffer, FILENAME_MAX, "%s/tests/config/%s", root, test_cases[ff]); fprintf(stderr, "Running ketama test for: %s\n", test_cases[ff]); vb = vbucket_config_create(); assert(vbucket_config_parse(vb, LIBVBUCKET_SOURCE_FILE, buffer) == 0); /* check if it conforms to libketama results */ snprintf(buffer, FILENAME_MAX,"%s/tests/config/%s.md5sum", root, test_cases[ff]); read_checksum(buffer, expected); memset(checksum, 0, 16); ctx = NULL; for (i = 0; i < 1000000; i++) { len = snprintf(key, NKEY, "%d", i); vbucket_map(vb, key, len, NULL, &idx); host = vbucket_config_get_server(vb, idx); ctx = hash_md5_update(ctx, host, strlen(host)); } hash_md5_final(ctx, checksum); for (i = 0; i < 16; i++) { assert(checksum[i] == expected[i]); } vbucket_config_destroy(vb); } } exit(EXIT_SUCCESS); }
LIBCOUCHBASE_API libcouchbase_error_t libcouchbase_mget_by_key(libcouchbase_t instance, const void *command_cookie, const void *hashkey, libcouchbase_size_t nhashkey, libcouchbase_size_t num_keys, const void * const *keys, const libcouchbase_size_t *nkey, const libcouchbase_time_t *exp) { libcouchbase_server_t *server = NULL; protocol_binary_request_noop noop; libcouchbase_size_t ii, *affected_servers = NULL; int vb, idx; struct server_info_st *servers = NULL; /* we need a vbucket config before we can start getting data.. */ if (instance->vbucket_config == NULL) { return libcouchbase_synchandler_return(instance, LIBCOUCHBASE_ETMPFAIL); } if (num_keys == 1) { return libcouchbase_single_get(instance, command_cookie, hashkey, nhashkey, keys[0], nkey[0], exp); } affected_servers = calloc(instance->nservers, sizeof(libcouchbase_size_t)); if (affected_servers == NULL) { return libcouchbase_synchandler_return(instance, LIBCOUCHBASE_ENOMEM); } if (nhashkey != 0) { (void)vbucket_map(instance->vbucket_config, hashkey, nhashkey, &vb, &idx); if (idx < 0 || (libcouchbase_size_t)idx > instance->nservers) { /* the config says that there is no server yet at that position (-1) */ return libcouchbase_synchandler_return(instance, LIBCOUCHBASE_NETWORK_ERROR); } server = instance->servers + (libcouchbase_size_t)idx; affected_servers[idx]++; } else { servers = malloc(num_keys * sizeof(struct server_info_st)); if (servers == NULL) { return libcouchbase_synchandler_return(instance, LIBCOUCHBASE_ENOMEM); } for (ii = 0; ii < num_keys; ++ii) { (void)vbucket_map(instance->vbucket_config, keys[ii], nkey[ii], &servers[ii].vb, &servers[ii].idx); if (servers[ii].idx < 0 || (libcouchbase_size_t)servers[ii].idx > instance->nservers) { /* the config says that there is no server yet at that position (-1) */ free(servers); return libcouchbase_synchandler_return(instance, LIBCOUCHBASE_NETWORK_ERROR); } affected_servers[servers[ii].idx]++; } } for (ii = 0; ii < num_keys; ++ii) { protocol_binary_request_gat req; if (nhashkey == 0) { server = instance->servers + (libcouchbase_size_t)servers[ii].idx; vb = servers[ii].vb; } memset(&req, 0, sizeof(req)); req.message.header.request.magic = PROTOCOL_BINARY_REQ; req.message.header.request.keylen = ntohs((libcouchbase_uint16_t)nkey[ii]); req.message.header.request.datatype = PROTOCOL_BINARY_RAW_BYTES; req.message.header.request.vbucket = ntohs((libcouchbase_uint16_t)vb); req.message.header.request.bodylen = ntohl((libcouchbase_uint32_t)(nkey[ii])); req.message.header.request.opaque = ++instance->seqno; if (!exp) { req.message.header.request.opcode = PROTOCOL_BINARY_CMD_GETQ; libcouchbase_server_start_packet(server, command_cookie, req.bytes, sizeof(req.bytes) - 4); } else { req.message.header.request.opcode = PROTOCOL_BINARY_CMD_GATQ; req.message.header.request.extlen = 4; req.message.body.expiration = ntohl((libcouchbase_uint32_t)exp[ii]); req.message.header.request.bodylen = ntohl((libcouchbase_uint32_t)(nkey[ii]) + 4); libcouchbase_server_start_packet(server, command_cookie, req.bytes, sizeof(req.bytes)); } libcouchbase_server_write_packet(server, keys[ii], nkey[ii]); libcouchbase_server_end_packet(server); } free(servers); memset(&noop, 0, sizeof(noop)); noop.message.header.request.magic = PROTOCOL_BINARY_REQ; noop.message.header.request.opcode = PROTOCOL_BINARY_CMD_NOOP; noop.message.header.request.datatype = PROTOCOL_BINARY_RAW_BYTES; /* ** We don't know which server we sent the data to, so examine ** where to send the noop */ for (ii = 0; ii < instance->nservers; ++ii) { if (affected_servers[ii]) { server = instance->servers + ii; noop.message.header.request.opaque = ++instance->seqno; libcouchbase_server_complete_packet(server, command_cookie, noop.bytes, sizeof(noop.bytes)); libcouchbase_server_send_packets(server); } } free(affected_servers); return libcouchbase_synchandler_return(instance, LIBCOUCHBASE_SUCCESS); }
/** * Spool a store request * * @author Trond Norbye * @todo add documentation * @todo fix the expiration so that it works relative/absolute etc.. * @todo we might want to wait to write the data to the sockets if the * user want to run a batch of store requests? */ LIBCOUCHBASE_API lcb_error_t lcb_store(lcb_t instance, const void *command_cookie, lcb_size_t num, const lcb_store_cmd_t *const *items) { lcb_size_t ii; /* we need a vbucket config before we can start getting data.. */ if (instance->vbucket_config == NULL) { switch (instance->type) { case LCB_TYPE_CLUSTER: return lcb_synchandler_return(instance, LCB_EBADHANDLE); case LCB_TYPE_BUCKET: default: return lcb_synchandler_return(instance, LCB_CLIENT_ETMPFAIL); } } for (ii = 0; ii < num; ++ii) { lcb_server_t *server; protocol_binary_request_set req; lcb_size_t headersize; lcb_size_t bodylen; int vb, idx; lcb_storage_t operation = items[ii]->v.v0.operation; const void *key = items[ii]->v.v0.key; lcb_size_t nkey = items[ii]->v.v0.nkey; lcb_cas_t cas = items[ii]->v.v0.cas; lcb_uint32_t flags = items[ii]->v.v0.flags; lcb_time_t exp = items[ii]->v.v0.exptime; const void *bytes = items[ii]->v.v0.bytes; lcb_size_t nbytes = items[ii]->v.v0.nbytes; const void *hashkey = items[ii]->v.v0.hashkey; lcb_size_t nhashkey = items[ii]->v.v0.nhashkey; if (nhashkey == 0) { hashkey = key; nhashkey = nkey; } (void)vbucket_map(instance->vbucket_config, hashkey, nhashkey, &vb, &idx); if (idx < 0 || idx > (int)instance->nservers) { return lcb_synchandler_return(instance, LCB_NO_MATCHING_SERVER); } server = instance->servers + idx; memset(&req, 0, sizeof(req)); req.message.header.request.magic = PROTOCOL_BINARY_REQ; req.message.header.request.keylen = ntohs((lcb_uint16_t)nkey); req.message.header.request.extlen = 8; req.message.header.request.datatype = PROTOCOL_BINARY_RAW_BYTES; req.message.header.request.vbucket = ntohs((lcb_uint16_t)vb); req.message.header.request.opaque = ++instance->seqno; req.message.header.request.cas = cas; req.message.body.flags = htonl(flags); req.message.body.expiration = htonl((lcb_uint32_t)exp); headersize = sizeof(req.bytes); switch (operation) { case LCB_ADD: req.message.header.request.opcode = PROTOCOL_BINARY_CMD_ADD; break; case LCB_REPLACE: req.message.header.request.opcode = PROTOCOL_BINARY_CMD_REPLACE; break; case LCB_SET: req.message.header.request.opcode = PROTOCOL_BINARY_CMD_SET; break; case LCB_APPEND: req.message.header.request.opcode = PROTOCOL_BINARY_CMD_APPEND; req.message.header.request.extlen = 0; headersize -= 8; break; case LCB_PREPEND: req.message.header.request.opcode = PROTOCOL_BINARY_CMD_PREPEND; req.message.header.request.extlen = 0; headersize -= 8; break; default: /* We were given an unknown storage operation. */ return lcb_synchandler_return(instance, lcb_error_handler(instance, LCB_EINVAL, "Invalid value passed as storage operation")); } /* Make it known that this was a success. */ lcb_error_handler(instance, LCB_SUCCESS, NULL); bodylen = nkey + nbytes + req.message.header.request.extlen; req.message.header.request.bodylen = htonl((lcb_uint32_t)bodylen); TRACE_STORE_BEGIN(&req, key, nkey, bytes, nbytes, flags, exp); lcb_server_start_packet(server, command_cookie, &req, headersize); lcb_server_write_packet(server, key, nkey); lcb_server_write_packet(server, bytes, nbytes); lcb_server_end_packet(server); lcb_server_send_packets(server); } return lcb_synchandler_return(instance, LCB_SUCCESS); }
static lcb_error_t multi_get(lcb_t instance, const void *command_cookie, lcb_size_t num, const lcb_get_cmd_t *const *items) { lcb_server_t *server = NULL; protocol_binary_request_noop noop; lcb_size_t ii, *affected_servers = NULL; struct server_info_st *servers = NULL; /* we need a vbucket config before we can start getting data.. */ if (instance->vbucket_config == NULL) { switch (instance->type) { case LCB_TYPE_CLUSTER: return lcb_synchandler_return(instance, LCB_EBADHANDLE); case LCB_TYPE_BUCKET: default: return lcb_synchandler_return(instance, LCB_CLIENT_ETMPFAIL); } } affected_servers = calloc(instance->nservers, sizeof(lcb_size_t)); if (affected_servers == NULL) { return lcb_synchandler_return(instance, LCB_CLIENT_ENOMEM); } servers = malloc(num * sizeof(struct server_info_st)); if (servers == NULL) { free(affected_servers); return lcb_synchandler_return(instance, LCB_CLIENT_ENOMEM); } for (ii = 0; ii < num; ++ii) { const void *key = items[ii]->v.v0.key; lcb_size_t nkey = items[ii]->v.v0.nkey; const void *hashkey = items[ii]->v.v0.hashkey; lcb_size_t nhashkey = items[ii]->v.v0.nhashkey; if (nhashkey == 0) { hashkey = key; nhashkey = nkey; } (void)vbucket_map(instance->vbucket_config, hashkey, nhashkey, &servers[ii].vb, &servers[ii].idx); if (servers[ii].idx < 0 || servers[ii].idx > (int)instance->nservers) { free(servers); free(affected_servers); return lcb_synchandler_return(instance, LCB_NO_MATCHING_SERVER); } affected_servers[servers[ii].idx]++; } for (ii = 0; ii < num; ++ii) { protocol_binary_request_gat req; const void *key = items[ii]->v.v0.key; lcb_size_t nkey = items[ii]->v.v0.nkey; lcb_time_t exp = items[ii]->v.v0.exptime; lcb_size_t nreq = sizeof(req.bytes); int vb; server = instance->servers + servers[ii].idx; vb = servers[ii].vb; memset(&req, 0, sizeof(req)); req.message.header.request.magic = PROTOCOL_BINARY_REQ; req.message.header.request.keylen = ntohs((lcb_uint16_t)nkey); req.message.header.request.datatype = PROTOCOL_BINARY_RAW_BYTES; req.message.header.request.vbucket = ntohs((lcb_uint16_t)vb); req.message.header.request.bodylen = ntohl((lcb_uint32_t)(nkey)); req.message.header.request.opaque = ++instance->seqno; if (!exp) { req.message.header.request.opcode = PROTOCOL_BINARY_CMD_GETQ; nreq -= 4; } else { req.message.header.request.opcode = PROTOCOL_BINARY_CMD_GATQ; req.message.header.request.extlen = 4; req.message.body.expiration = ntohl((lcb_uint32_t)exp); req.message.header.request.bodylen = ntohl((lcb_uint32_t)(nkey) + 4); } if (items[ii]->v.v0.lock) { /* the expiration is optional for GETL command */ req.message.header.request.opcode = CMD_GET_LOCKED; } lcb_server_start_packet(server, command_cookie, req.bytes, nreq); lcb_server_write_packet(server, key, nkey); lcb_server_end_packet(server); } free(servers); memset(&noop, 0, sizeof(noop)); noop.message.header.request.magic = PROTOCOL_BINARY_REQ; noop.message.header.request.opcode = PROTOCOL_BINARY_CMD_NOOP; noop.message.header.request.datatype = PROTOCOL_BINARY_RAW_BYTES; /* ** We don't know which server we sent the data to, so examine ** where to send the noop */ for (ii = 0; ii < instance->nservers; ++ii) { if (affected_servers[ii]) { server = instance->servers + ii; noop.message.header.request.opaque = ++instance->seqno; lcb_server_complete_packet(server, command_cookie, noop.bytes, sizeof(noop.bytes)); lcb_server_send_packets(server); } } free(affected_servers); return lcb_synchandler_return(instance, LCB_SUCCESS); }
static lcb_error_t single_get(lcb_t instance, const void *command_cookie, const lcb_get_cmd_t *item) { lcb_server_t *server; protocol_binary_request_gat req; int vb, idx; lcb_size_t nbytes; const void *hashkey = item->v.v0.hashkey; lcb_size_t nhashkey = item->v.v0.nhashkey; const void *key = item->v.v0.key; lcb_size_t nkey = item->v.v0.nkey; lcb_time_t exp = item->v.v0.exptime; /* we need a vbucket config before we can start getting data.. */ if (instance->vbucket_config == NULL) { switch (instance->type) { case LCB_TYPE_CLUSTER: return lcb_synchandler_return(instance, LCB_EBADHANDLE); case LCB_TYPE_BUCKET: default: return lcb_synchandler_return(instance, LCB_CLIENT_ETMPFAIL); } } if (nhashkey == 0) { hashkey = key; nhashkey = nkey; } (void)vbucket_map(instance->vbucket_config, hashkey, nhashkey, &vb, &idx); if (idx < 0 || idx > (int)instance->nservers) { return lcb_synchandler_return(instance, LCB_NO_MATCHING_SERVER); } server = instance->servers + idx; memset(&req, 0, sizeof(req)); req.message.header.request.magic = PROTOCOL_BINARY_REQ; req.message.header.request.keylen = ntohs((lcb_uint16_t)nkey); req.message.header.request.datatype = PROTOCOL_BINARY_RAW_BYTES; req.message.header.request.vbucket = ntohs((lcb_uint16_t)vb); req.message.header.request.bodylen = ntohl((lcb_uint32_t)(nkey)); req.message.header.request.opaque = ++instance->seqno; if (!exp) { req.message.header.request.opcode = PROTOCOL_BINARY_CMD_GET; nbytes = sizeof(req.bytes) - 4; } else { req.message.header.request.opcode = PROTOCOL_BINARY_CMD_GAT; req.message.header.request.extlen = 4; req.message.body.expiration = ntohl((lcb_uint32_t)exp); req.message.header.request.bodylen = ntohl((lcb_uint32_t)(nkey) + 4); nbytes = sizeof(req.bytes); } if (item->v.v0.lock) { /* the expiration is optional for GETL command */ req.message.header.request.opcode = CMD_GET_LOCKED; } lcb_server_start_packet(server, command_cookie, req.bytes, nbytes); lcb_server_write_packet(server, key, nkey); lcb_server_end_packet(server); lcb_server_send_packets(server); return lcb_synchandler_return(instance, LCB_SUCCESS); }
libcouchbase_error_t libcouchbase_store_by_key(libcouchbase_t instance, const void *command_cookie, libcouchbase_storage_t operation, const void *hashkey, libcouchbase_size_t nhashkey, const void *key, libcouchbase_size_t nkey, const void *bytes, libcouchbase_size_t nbytes, libcouchbase_uint32_t flags, libcouchbase_time_t exp, libcouchbase_cas_t cas) { libcouchbase_server_t *server; protocol_binary_request_set req; libcouchbase_size_t headersize; libcouchbase_size_t bodylen; int vb, idx; /* we need a vbucket config before we can start getting data.. */ if (instance->vbucket_config == NULL) { return libcouchbase_synchandler_return(instance, LIBCOUCHBASE_ETMPFAIL); } if (nhashkey == 0) { nhashkey = nkey; hashkey = key; } (void)vbucket_map(instance->vbucket_config, hashkey, nhashkey, &vb, &idx); if (idx < 0 || idx > (int)instance->nservers) { /* the config says that there is no server yet at that position (-1) */ return libcouchbase_synchandler_return(instance, LIBCOUCHBASE_NETWORK_ERROR); } server = instance->servers + idx; memset(&req, 0, sizeof(req)); req.message.header.request.magic = PROTOCOL_BINARY_REQ; req.message.header.request.keylen = ntohs((libcouchbase_uint16_t)nkey); req.message.header.request.extlen = 8; req.message.header.request.datatype = PROTOCOL_BINARY_RAW_BYTES; req.message.header.request.vbucket = ntohs((libcouchbase_uint16_t)vb); req.message.header.request.opaque = ++instance->seqno; req.message.header.request.cas = cas; req.message.body.flags = htonl(flags); req.message.body.expiration = htonl((libcouchbase_uint32_t)exp); headersize = sizeof(req.bytes); switch (operation) { case LIBCOUCHBASE_ADD: req.message.header.request.opcode = PROTOCOL_BINARY_CMD_ADD; break; case LIBCOUCHBASE_REPLACE: req.message.header.request.opcode = PROTOCOL_BINARY_CMD_REPLACE; break; case LIBCOUCHBASE_SET: req.message.header.request.opcode = PROTOCOL_BINARY_CMD_SET; break; case LIBCOUCHBASE_APPEND: req.message.header.request.opcode = PROTOCOL_BINARY_CMD_APPEND; req.message.header.request.extlen = 0; headersize -= 8; break; case LIBCOUCHBASE_PREPEND: req.message.header.request.opcode = PROTOCOL_BINARY_CMD_PREPEND; req.message.header.request.extlen = 0; headersize -= 8; break; default: /* We were given an unknown storage operation. */ return libcouchbase_synchandler_return(instance, libcouchbase_error_handler(instance, LIBCOUCHBASE_EINVAL, "Invalid value passed as storage operation")); } /* Make it known that this was a success. */ libcouchbase_error_handler(instance, LIBCOUCHBASE_SUCCESS, NULL); bodylen = nkey + nbytes + req.message.header.request.extlen; req.message.header.request.bodylen = htonl((libcouchbase_uint32_t)bodylen); libcouchbase_server_start_packet(server, command_cookie, &req, headersize); libcouchbase_server_write_packet(server, key, nkey); libcouchbase_server_write_packet(server, bytes, nbytes); libcouchbase_server_end_packet(server); libcouchbase_server_send_packets(server); return libcouchbase_synchandler_return(instance, LIBCOUCHBASE_SUCCESS); }