Ejemplo n.º 1
0
LIBCOUCHBASE_API
libcouchbase_error_t libcouchbase_get_replica_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)
{
    libcouchbase_server_t *server;
    protocol_binary_request_get req;
    int vb, idx;
    libcouchbase_size_t ii, *affected_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);
    }

    affected_servers = calloc(instance->nservers, sizeof(libcouchbase_size_t));
    if (affected_servers == NULL) {
        return libcouchbase_synchandler_return(instance, LIBCOUCHBASE_CLIENT_ENOMEM);
    }
    memset(&req, 0, sizeof(req));
    req.message.header.request.magic = PROTOCOL_BINARY_REQ;
    req.message.header.request.datatype = PROTOCOL_BINARY_RAW_BYTES;
    req.message.header.request.opcode = CMD_GET_REPLICA;
    for (ii = 0; ii < num_keys; ++ii) {
        if (nhashkey == 0) {
            nhashkey = nkey[ii];
            hashkey = keys[ii];
        }
        vb = vbucket_get_vbucket_by_key(instance->vbucket_config, hashkey, nhashkey);
        idx = vbucket_get_replica(instance->vbucket_config, vb, 0);
        if (idx < 0 || idx > (int)instance->nservers) {
            /* the config says that there is no server yet at that position (-1) */
            free(affected_servers);
            return libcouchbase_synchandler_return(instance, LIBCOUCHBASE_NETWORK_ERROR);
        }
        affected_servers[idx]++;
        server = instance->servers + idx;
        req.message.header.request.keylen = ntohs((libcouchbase_uint16_t)nkey[ii]);
        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;
        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);
    }

    for (ii = 0; ii < instance->nservers; ++ii) {
        if (affected_servers[ii]) {
            server = instance->servers + ii;
            libcouchbase_server_send_packets(server);
        }
    }

    free(affected_servers);
    return libcouchbase_synchandler_return(instance, LIBCOUCHBASE_SUCCESS);
}
Ejemplo n.º 2
0
LIBCOUCHBASE_API
libcouchbase_error_t libcouchbase_arithmetic_by_key(libcouchbase_t instance,
                                                    const void *hashkey,
                                                    size_t nhashkey,
                                                    const void *key, size_t nkey,
                                                    int64_t delta, time_t exp,
                                                    bool create, uint64_t initial)
{
    uint16_t vb;
    libcouchbase_server_t *server;
    protocol_binary_request_incr req;

    // we need a vbucket config before we can start getting data..
    libcouchbase_ensure_vbucket_config(instance);
    assert(instance->vbucket_config);

    if (nhashkey != 0) {
        vb = (uint16_t)vbucket_get_vbucket_by_key(instance->vbucket_config,
                                                  hashkey, nhashkey);
    } else {
        vb = (uint16_t)vbucket_get_vbucket_by_key(instance->vbucket_config,
                                                  key, nkey);
    }

    server = instance->servers + instance->vb_server_map[vb];
    memset(&req, 0, sizeof(req));
    req.message.header.request.magic = PROTOCOL_BINARY_REQ;
    req.message.header.request.opcode = PROTOCOL_BINARY_CMD_INCREMENT;
    req.message.header.request.keylen = ntohs((uint16_t)nkey);
    req.message.header.request.extlen = 20;
    req.message.header.request.datatype = PROTOCOL_BINARY_RAW_BYTES;
    req.message.header.request.vbucket = ntohs(vb);
    req.message.header.request.bodylen = ntohl((uint32_t)(nkey + 20));
    req.message.header.request.opaque = ++instance->seqno;
    req.message.body.delta = ntohll((uint64_t)(delta));
    req.message.body.initial = ntohll(initial);
    req.message.body.expiration = ntohl((uint32_t)exp);

    if (delta < 0) {
        req.message.header.request.opcode = PROTOCOL_BINARY_CMD_DECREMENT;
        req.message.body.delta = ntohll((uint64_t)(delta * -1));
    }

    if (create) {
        memset(&req.message.body.expiration, 0xff,
               sizeof(req.message.body.expiration));
    }

    libcouchbase_server_start_packet(server, req.bytes, sizeof(req.bytes));
    libcouchbase_server_write_packet(server, key, nkey);
    libcouchbase_server_end_packet(server);
    libcouchbase_server_send_packets(server);

    return LIBCOUCHBASE_SUCCESS;
}
Ejemplo n.º 3
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);
}
Ejemplo n.º 4
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);
}
Ejemplo n.º 5
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);
}
Ejemplo n.º 6
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);
}
Ejemplo n.º 7
0
LIBCOUCHBASE_API
libcouchbase_error_t libcouchbase_mget_by_key(libcouchbase_t instance,
                                              const void *hashkey,
                                              size_t nhashkey,
                                              size_t num_keys,
                                              const void * const *keys,
                                              const size_t *nkey,
                                              const time_t *exp)
{
    uint16_t vb;
    libcouchbase_server_t *server;
    protocol_binary_request_noop noop;
    size_t ii;

    // we need a vbucket config before we can start getting data..
    libcouchbase_ensure_vbucket_config(instance);
    assert(instance->vbucket_config);

    if (nhashkey != 0) {
        vb = (uint16_t)vbucket_get_vbucket_by_key(instance->vbucket_config,
                                                  hashkey, nhashkey);
        server = instance->servers + instance->vb_server_map[vb];
    }

    for (ii = 0; ii < num_keys; ++ii) {
        protocol_binary_request_gat req;
        if (nhashkey == 0) {
            vb = (uint16_t)vbucket_get_vbucket_by_key(instance->vbucket_config,
                                                      keys[ii], nkey[ii]);
            server = instance->servers + instance->vb_server_map[vb];
        }

        memset(&req, 0, sizeof(req));
        req.message.header.request.magic = PROTOCOL_BINARY_REQ;
        req.message.header.request.keylen = ntohs((uint16_t)nkey[ii]);
        req.message.header.request.datatype = PROTOCOL_BINARY_RAW_BYTES;
        req.message.header.request.vbucket = ntohs(vb);
        req.message.header.request.bodylen = ntohl((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, 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((uint32_t)exp[ii]);
            libcouchbase_server_start_packet(server, req.bytes,
                                             sizeof(req.bytes));
        }
        libcouchbase_server_write_packet(server, keys[ii], nkey[ii]);
        libcouchbase_server_end_packet(server);
    }

    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;

    if (nhashkey == 0) {
        // 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) {
            server = instance->servers + ii;
            if (server->output.avail > 0 || server->pending.avail > 0) {
                noop.message.header.request.opaque = ++instance->seqno;
                libcouchbase_server_complete_packet(server, noop.bytes,
                                                    sizeof(noop.bytes));
                libcouchbase_server_send_packets(server);
            }
        }
    } else {
        noop.message.header.request.opaque = ++instance->seqno;
        libcouchbase_server_complete_packet(server, noop.bytes,
                                            sizeof(noop.bytes));
        libcouchbase_server_send_packets(server);
    }

    return LIBCOUCHBASE_SUCCESS;
}
Ejemplo n.º 8
0
static int parse_single(libcouchbase_server_t *c, hrtime_t stop)
{
    protocol_binary_request_header req;
    protocol_binary_response_header header;
    libcouchbase_size_t nr;
    char *packet;
    libcouchbase_size_t packetsize;
    struct libcouchbase_command_data_st ct;

    nr = ringbuffer_peek(&c->input, header.bytes, sizeof(header));
    if (nr < sizeof(header)) {
        return 0;
    }

    packetsize = ntohl(header.response.bodylen) + (libcouchbase_uint32_t)sizeof(header);
    if (c->input.nbytes < packetsize) {
        return 0;
    }

    /* Is it already timed out? */
    nr = ringbuffer_peek(&c->cmd_log, req.bytes, sizeof(req));
    if (nr < sizeof(req) || /* the command log doesn't know about it */
            (header.response.opaque < req.request.opaque &&
             header.response.opaque > 0)) { /* sasl comes with zero opaque */
        /* already processed. */
        ringbuffer_consumed(&c->input, packetsize);
        return 1;
    }

    packet = c->input.read_head;
    /* we have everything! */

    if (!ringbuffer_is_continous(&c->input, RINGBUFFER_READ,
                                 packetsize)) {
        /* The buffer isn't continous.. for now just copy it out and
        ** operate on the copy ;)
        */
        if ((packet = malloc(packetsize)) == NULL) {
            libcouchbase_error_handler(c->instance, LIBCOUCHBASE_CLIENT_ENOMEM, NULL);
            return -1;
        }
        nr = ringbuffer_read(&c->input, packet, packetsize);
        if (nr != packetsize) {
            libcouchbase_error_handler(c->instance, LIBCOUCHBASE_EINTERNAL,
                                       NULL);
            free(packet);
            return -1;
        }
    }

    nr = ringbuffer_peek(&c->output_cookies, &ct, sizeof(ct));
    if (nr != sizeof(ct)) {
        libcouchbase_error_handler(c->instance, LIBCOUCHBASE_EINTERNAL,
                                   NULL);
        if (packet != c->input.read_head) {
            free(packet);
        }
        return -1;
    }
    ct.vbucket = ntohs(req.request.vbucket);

    switch (header.response.magic) {
    case PROTOCOL_BINARY_REQ:
        c->instance->request_handler[header.response.opcode](c, &ct, (void *)packet);
        break;
    case PROTOCOL_BINARY_RES: {
        int was_connected = c->connected;
        if (libcouchbase_server_purge_implicit_responses(c, header.response.opaque, stop) != 0) {
            if (packet != c->input.read_head) {
                free(packet);
            }
            return -1;
        }

        if (c->instance->histogram) {
            libcouchbase_record_metrics(c->instance, stop - ct.start,
                                        header.response.opcode);
        }

        if (ntohs(header.response.status) != PROTOCOL_BINARY_RESPONSE_NOT_MY_VBUCKET
            || header.response.opcode == CMD_GET_REPLICA) {
            c->instance->response_handler[header.response.opcode](c, &ct, (void *)packet);
            /* keep command and cookie until we get complete STAT response */
            if (was_connected &&
                    (header.response.opcode != PROTOCOL_BINARY_CMD_STAT || header.response.keylen == 0)) {
                nr = ringbuffer_read(&c->cmd_log, req.bytes, sizeof(req));
                assert(nr == sizeof(req));
                ringbuffer_consumed(&c->cmd_log, ntohl(req.request.bodylen));
                ringbuffer_consumed(&c->output_cookies, sizeof(ct));
            }
        } else {
            int idx;
            char *body;
            libcouchbase_size_t nbody;
            libcouchbase_server_t *new_srv;
            /* re-schedule command to new server */
            nr = ringbuffer_read(&c->cmd_log, req.bytes, sizeof(req));
            assert(nr == sizeof(req));
            idx = vbucket_found_incorrect_master(c->instance->vbucket_config,
                                                 ntohs(req.request.vbucket),
                                                 (int)c->index);
            assert((libcouchbase_size_t)idx < c->instance->nservers);
            new_srv = c->instance->servers + idx;
            req.request.opaque = ++c->instance->seqno;
            nbody = ntohl(req.request.bodylen);
            body = malloc(nbody);
            if (body == NULL) {
                libcouchbase_error_handler(c->instance, LIBCOUCHBASE_CLIENT_ENOMEM, NULL);
                return -1;
            }
            nr = ringbuffer_read(&c->cmd_log, body, nbody);
            assert(nr == nbody);
            nr = ringbuffer_read(&c->output_cookies, &ct, sizeof(ct));
            assert(nr == sizeof(ct));
            /* Preserve the cookie and timestamp for the command. This means
             * that the library will retry the command until its time will
             * out and the client will get LIBCOUCHBASE_ETIMEDOUT error in
             * command callback */
            libcouchbase_server_retry_packet(new_srv, &ct, &req, sizeof(req));
            libcouchbase_server_write_packet(new_srv, body, nbody);
            libcouchbase_server_end_packet(new_srv);
            libcouchbase_server_send_packets(new_srv);
            free(body);
        }
        break;
    }

    default:
        libcouchbase_error_handler(c->instance,
                                   LIBCOUCHBASE_PROTOCOL_ERROR,
                                   NULL);
        if (packet != c->input.read_head) {
            free(packet);
        }
        return -1;
    }

    if (packet != c->input.read_head) {
        free(packet);
    } else {
        ringbuffer_consumed(&c->input, packetsize);
    }
    return 1;
}
Ejemplo n.º 9
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);
}
Ejemplo n.º 10
0
LIBCOUCHBASE_API
libcouchbase_error_t libcouchbase_observe(libcouchbase_t instance,
                                          const void *command_cookie,
                                          libcouchbase_size_t num_keys,
                                          const void *const *keys,
                                          const libcouchbase_size_t *nkey)
{
    int vbid, idx, jj;
    libcouchbase_size_t ii;
    libcouchbase_uint32_t opaque;
    struct observe_st *requests;

    /* we need a vbucket config before we can start getting data.. */
    if (instance->vbucket_config == NULL) {
        return libcouchbase_synchandler_return(instance, LIBCOUCHBASE_ETMPFAIL);
    }

    if (instance->dist_type != VBUCKET_DISTRIBUTION_VBUCKET) {
        return libcouchbase_synchandler_return(instance, LIBCOUCHBASE_NOT_SUPPORTED);
    }

    /* the list of pointers to body buffers for each server */
    requests = calloc(instance->nservers, sizeof(struct observe_st));
    opaque = ++instance->seqno;
    for (ii = 0; ii < num_keys; ++ii) {
        vbid = vbucket_get_vbucket_by_key(instance->vbucket_config, keys[ii], nkey[ii]);
        for (jj = -1; jj < instance->nreplicas; ++jj) {
            struct observe_st *rr;
            /* it will increment jj to get server index, so (-1 + 1) = 0 (master) */
            idx = vbucket_get_replica(instance->vbucket_config, vbid, jj);
            if ((idx < 0 || idx > (int)instance->nservers)) {
                /* the config says that there is no server yet at that position (-1) */
                if (jj == -1) {
                    /* master node must be available */
                    destroy_requests(requests, instance->nservers);
                    return libcouchbase_synchandler_return(instance, LIBCOUCHBASE_NETWORK_ERROR);
                } else {
                    continue;
                }
            }
            rr = requests + idx;
            if (!rr->allocated) {
                if (!init_request(rr)) {
                    destroy_requests(requests, instance->nservers);
                    return libcouchbase_synchandler_return(instance, LIBCOUCHBASE_CLIENT_ENOMEM);
                }
                rr->req.message.header.request.magic = PROTOCOL_BINARY_REQ;
                rr->req.message.header.request.opcode = CMD_OBSERVE;
                rr->req.message.header.request.datatype = PROTOCOL_BINARY_RAW_BYTES;
                rr->req.message.header.request.opaque = opaque;
            }

            {
                libcouchbase_uint16_t vb = htons(vbid);
                libcouchbase_uint16_t len = htons((libcouchbase_uint16_t)nkey[ii]);
                ringbuffer_ensure_capacity(&rr->body, sizeof(vb) + sizeof(len) + nkey[ii]);
                rr->nbody += ringbuffer_write(&rr->body, &vb, sizeof(vb));
                rr->nbody += ringbuffer_write(&rr->body, &len, sizeof(len));
                rr->nbody += ringbuffer_write(&rr->body, keys[ii], nkey[ii]);
            }
        }
    }

    for (ii = 0; ii < instance->nservers; ++ii) {
        struct observe_st *rr = requests + ii;
        libcouchbase_server_t *server = instance->servers + ii;

        if (rr->allocated) {
            rr->req.message.header.request.bodylen = ntohl((libcouchbase_uint32_t)rr->nbody);
            libcouchbase_server_start_packet(server, command_cookie, rr->req.bytes, sizeof(rr->req.bytes));
            if (ringbuffer_is_continous(&rr->body, RINGBUFFER_READ, rr->nbody)) {
                libcouchbase_server_write_packet(server, ringbuffer_get_read_head(&rr->body), rr->nbody);
            } else {
                char *tmp = malloc(ringbuffer_get_nbytes(&rr->body));
                if (!tmp) {
                    /* FIXME by this time some of requests might be scheduled */
                    destroy_requests(requests, instance->nservers);
                    return libcouchbase_synchandler_return(instance, LIBCOUCHBASE_CLIENT_ENOMEM);
                } else {
                    ringbuffer_read(&rr->body, tmp, rr->nbody);
                    libcouchbase_server_write_packet(server, tmp, rr->nbody);
                }
            }
            libcouchbase_server_end_packet(server);
            libcouchbase_server_send_packets(server);
        }
    }

    destroy_requests(requests, instance->nservers);
    return libcouchbase_synchandler_return(instance, LIBCOUCHBASE_SUCCESS);
}