Beispiel #1
0
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);
}
Beispiel #2
0
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;
}
Beispiel #3
0
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);
}
Beispiel #4
0
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;
}
Beispiel #5
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);
}
Beispiel #6
0
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);
}
Beispiel #7
0
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);
}
Beispiel #8
0
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);
}
Beispiel #9
0
/**
 * 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);
}
Beispiel #10
0
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);
}
Beispiel #11
0
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);
}
Beispiel #12
0
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);
}