示例#1
0
static void
H_get(mc_PIPELINE *pipeline, mc_PACKET *request, packet_info *response,
      lcb_error_t immerr)
{
    lcb_t o;
    lcb_RESPGET resp = { 0 };
    void *freeptr = NULL;

    o = pipeline->parent->cqdata;
    init_resp3(o, response, request, immerr, (lcb_RESPBASE *)&resp);

    if (resp.rc == LCB_SUCCESS) {
        const protocol_binary_response_getq *getq =
                PACKET_EPHEMERAL_START(response);
        resp.datatype = PACKET_DATATYPE(response);
        resp.itmflags = ntohl(getq->message.body.flags);
        resp.value = PACKET_VALUE(response);
        resp.nvalue = PACKET_NVALUE(response);
        resp.bufh = response->bufh;
    }

    maybe_decompress(o, response, &resp, &freeptr);
    TRACE_GET_END(response, &resp);
    INVOKE_CALLBACK3(request, &resp, o, LCB_CALLBACK_GET);
    free(freeptr);
}
示例#2
0
static void getq_response_handler(lcb_server_t *server,
                                  struct lcb_command_data_st *command_data,
                                  protocol_binary_response_header *res)
{
    lcb_t root = server->instance;
    protocol_binary_response_getq *getq = (void *)res;
    lcb_uint16_t status = ntohs(res->response.status);
    lcb_size_t nbytes = ntohl(res->response.bodylen);
    char *packet;
    lcb_uint16_t nkey;
    const char *key = get_key(server, &nkey, &packet);
    lcb_error_t rc = map_error(root, status);

    nbytes -= res->response.extlen;
    if (key == NULL) {
        lcb_error_handler(server->instance, LCB_EINTERNAL, NULL);
        return;
    } else if (status == PROTOCOL_BINARY_RESPONSE_SUCCESS) {
        const char *bytes = (const char *)res;
        lcb_get_resp_t resp;
        bytes += sizeof(getq->bytes);
        setup_lcb_get_resp_t(&resp, key, nkey, bytes, nbytes,
                             ntohl(getq->message.body.flags),
                             res->response.cas, res->response.datatype);
        TRACE_GET_END(res->response.opaque, command_data->vbucket,
                      res->response.opcode, rc, &resp);
        root->callbacks.get(root, command_data->cookie, rc, &resp);
    } else {
        lcb_get_resp_t resp;
        setup_lcb_get_resp_t(&resp, key, nkey, NULL, 0, 0,
                             0, res->response.datatype);
        TRACE_GET_END(res->response.opaque, command_data->vbucket,
                      res->response.opcode, rc, &resp);
        root->callbacks.get(root, command_data->cookie, rc, &resp);
    }
    release_key(server, packet);
}
示例#3
0
static void failout_single_request(lcb_server_t *server,
                                   protocol_binary_request_header *req,
                                   struct lcb_command_data_st *ct,
                                   lcb_error_t error,
                                   const void *keyptr,
                                   lcb_size_t nkey,
                                   const void *packet)
{
    lcb_t root = server->instance;
    union {
        lcb_get_resp_t get;
        lcb_store_resp_t store;
        lcb_remove_resp_t remove;
        lcb_touch_resp_t touch;
        lcb_unlock_resp_t unlock;
        lcb_arithmetic_resp_t arithmetic;
        lcb_observe_resp_t observe;
        lcb_server_stat_resp_t stats;
        lcb_server_version_resp_t versions;
        lcb_verbosity_resp_t verbosity;
        lcb_flush_resp_t flush;
    } resp;

    switch (req->request.opcode) {
    case PROTOCOL_BINARY_CMD_NOOP:
        break;
    case CMD_GET_LOCKED:
    case PROTOCOL_BINARY_CMD_GAT:
    case PROTOCOL_BINARY_CMD_GATQ:
    case PROTOCOL_BINARY_CMD_GET:
    case PROTOCOL_BINARY_CMD_GETQ:
        setup_lcb_get_resp_t(&resp.get, keyptr, nkey, NULL, 0, 0, 0, 0);
        TRACE_GET_END(req->request.opaque, ntohs(req->request.vbucket),
                      req->request.opcode, error, &resp.get);
        root->callbacks.get(root, ct->cookie, error, &resp.get);
        break;
    case CMD_UNLOCK_KEY:
        setup_lcb_unlock_resp_t(&resp.unlock, keyptr, nkey);
        TRACE_UNLOCK_END(req->request.opaque, ntohs(req->request.vbucket),
                         error, &resp.unlock);
        root->callbacks.unlock(root, ct->cookie, error, &resp.unlock);
        break;
    case PROTOCOL_BINARY_CMD_FLUSH:
        setup_lcb_flush_resp_t(&resp.flush, server->authority);
        TRACE_FLUSH_PROGRESS(req->request.opaque, ntohs(req->request.vbucket),
                             req->request.opcode, error, &resp.flush);
        root->callbacks.flush(root, ct->cookie, error, &resp.flush);
        if (lcb_lookup_server_with_command(root,
                                           PROTOCOL_BINARY_CMD_FLUSH,
                                           req->request.opaque,
                                           server) < 0) {
            setup_lcb_flush_resp_t(&resp.flush, NULL);
            TRACE_FLUSH_END(req->request.opaque, ntohs(req->request.vbucket),
                            req->request.opcode, error);
            root->callbacks.flush(root, ct->cookie, error, &resp.flush);
        }
        break;
    case PROTOCOL_BINARY_CMD_ADD:
        setup_lcb_store_resp_t(&resp.store, keyptr, nkey, 0);
        TRACE_STORE_END(req->request.opaque, ntohs(req->request.vbucket),
                        req->request.opcode, error, &resp.store);
        root->callbacks.store(root, ct->cookie, LCB_ADD, error, &resp.store);
        break;
    case PROTOCOL_BINARY_CMD_REPLACE:
        setup_lcb_store_resp_t(&resp.store, keyptr, nkey, 0);
        TRACE_STORE_END(req->request.opaque, ntohs(req->request.vbucket),
                        req->request.opcode, error, &resp.store);
        root->callbacks.store(root, ct->cookie, LCB_REPLACE, error,
                              &resp.store);
        break;
    case PROTOCOL_BINARY_CMD_SET:
        setup_lcb_store_resp_t(&resp.store, keyptr, nkey, 0);
        TRACE_STORE_END(req->request.opaque, ntohs(req->request.vbucket),
                        req->request.opcode, error, &resp.store);
        root->callbacks.store(root, ct->cookie, LCB_SET, error, &resp.store);
        break;
    case PROTOCOL_BINARY_CMD_APPEND:
        setup_lcb_store_resp_t(&resp.store, keyptr, nkey, 0);
        TRACE_STORE_END(req->request.opaque, ntohs(req->request.vbucket),
                        req->request.opcode, error, &resp.store);
        root->callbacks.store(root, ct->cookie, LCB_APPEND, error,
                              &resp.store);
        break;
    case PROTOCOL_BINARY_CMD_PREPEND:
        setup_lcb_store_resp_t(&resp.store, keyptr, nkey, 0);
        TRACE_STORE_END(req->request.opaque, ntohs(req->request.vbucket),
                        req->request.opcode, error, &resp.store);
        root->callbacks.store(root, ct->cookie, LCB_PREPEND, error,
                              &resp.store);
        break;
    case PROTOCOL_BINARY_CMD_DELETE:
        setup_lcb_remove_resp_t(&resp.remove, keyptr, nkey, 0);
        TRACE_REMOVE_END(req->request.opaque, ntohs(req->request.vbucket),
                         req->request.opcode, error, &resp.remove);
        root->callbacks.remove(root, ct->cookie, error, &resp.remove);
        break;

    case PROTOCOL_BINARY_CMD_INCREMENT:
    case PROTOCOL_BINARY_CMD_DECREMENT:
        setup_lcb_arithmetic_resp_t(&resp.arithmetic, keyptr, nkey, 0, 0);
        TRACE_ARITHMETIC_END(req->request.opaque, ntohs(req->request.vbucket),
                             req->request.opcode, error, &resp.arithmetic);
        root->callbacks.arithmetic(root, ct->cookie, error,
                                   &resp.arithmetic);
        break;
    case PROTOCOL_BINARY_CMD_SASL_LIST_MECHS:
    case PROTOCOL_BINARY_CMD_SASL_AUTH:
    case PROTOCOL_BINARY_CMD_SASL_STEP:
        /* no need to notify user about these commands */
        break;

    case PROTOCOL_BINARY_CMD_TOUCH:
        setup_lcb_touch_resp_t(&resp.touch, keyptr, nkey, 0);
        TRACE_TOUCH_END(req->request.opaque, ntohs(req->request.vbucket),
                        req->request.opcode, error, &resp.touch);
        root->callbacks.touch(root, ct->cookie, error, &resp.touch);
        break;

    case PROTOCOL_BINARY_CMD_STAT:
        setup_lcb_server_stat_resp_t(&resp.stats, server->authority,
                                     NULL, 0, NULL, 0);
        TRACE_STATS_PROGRESS(req->request.opaque, ntohs(req->request.vbucket),
                             req->request.opcode, error, &resp.stats);
        root->callbacks.stat(root, ct->cookie, error, &resp.stats);

        if (lcb_lookup_server_with_command(root,
                                           PROTOCOL_BINARY_CMD_STAT,
                                           req->request.opaque,
                                           server) < 0) {
            setup_lcb_server_stat_resp_t(&resp.stats,
                                         NULL, NULL, 0, NULL, 0);
            TRACE_STATS_END(req->request.opaque, ntohs(req->request.vbucket),
                            req->request.opcode, error);
            root->callbacks.stat(root, ct->cookie, error, &resp.stats);
        }
        break;

    case PROTOCOL_BINARY_CMD_VERBOSITY:
        setup_lcb_verbosity_resp_t(&resp.verbosity, server->authority);
        TRACE_VERBOSITY_END(req->request.opaque, ntohs(req->request.vbucket),
                            req->request.opcode, error, &resp.verbosity);
        root->callbacks.verbosity(root, ct->cookie, error, &resp.verbosity);

        if (lcb_lookup_server_with_command(root,
                                           PROTOCOL_BINARY_CMD_VERBOSITY,
                                           req->request.opaque,
                                           server) < 0) {
            setup_lcb_verbosity_resp_t(&resp.verbosity, NULL);
            TRACE_VERBOSITY_END(req->request.opaque, ntohs(req->request.vbucket),
                                req->request.opcode, error, &resp.verbosity);
            root->callbacks.verbosity(root, ct->cookie, error, &resp.verbosity);
        }
        break;

    case PROTOCOL_BINARY_CMD_VERSION:
        setup_lcb_server_version_resp_t(&resp.versions, server->authority,
                                        NULL, 0);
        TRACE_VERSIONS_PROGRESS(req->request.opaque, ntohs(req->request.vbucket),
                                req->request.opcode, error, &resp.versions);
        root->callbacks.version(root, ct->cookie, error, &resp.versions);
        if (lcb_lookup_server_with_command(root,
                                           PROTOCOL_BINARY_CMD_VERSION,
                                           req->request.opaque,
                                           server) < 0) {
            TRACE_VERSIONS_END(req->request.opaque, ntohs(req->request.vbucket),
                               req->request.opcode, error);
            setup_lcb_server_version_resp_t(&resp.versions, NULL, NULL, 0);
            root->callbacks.version(root, ct->cookie, error, &resp.versions);
        }
        break;

    case CMD_OBSERVE:
        lcb_failout_observe_request(server, ct, packet,
                                    sizeof(req->bytes) + ntohl(req->request.bodylen),
                                    error);
        break;

    case CMD_GET_CLUSTER_CONFIG:
        lcb_cccp_update2(ct->cookie, error, NULL, 0, NULL);
        break;
    
    case PROTOCOL_BINARY_CMD_HELLO:
        lcb_cccp_update2(ct->cookie, error, NULL, 0, NULL);
        break;

    case PROTOCOL_BINARY_CMD_COMPACTDB:
        lcb_cccp_update2(ct->cookie, error, NULL, 0, NULL);
        break;
    
    default:
        lcb_assert("unexpected opcode while purging the server" && 0);
    }

}
示例#4
0
/*
 * Drop all packets with sequence number less than specified.
 *
 * The packets are considered as stale and the caller will receive
 * appropriate error code in the operation callback.
 *
 * Returns 0 on success
 */
int lcb_server_purge_implicit_responses(lcb_server_t *c,
                                        lcb_uint32_t seqno,
                                        hrtime_t end,
                                        int all)
{
    protocol_binary_request_header req;

    /** Instance level allocated buffers */
    ringbuffer_t *cmdlog, *cookies;

    lcb_size_t nr = ringbuffer_peek(&c->cmd_log, req.bytes, sizeof(req));

    /* There should at _LEAST_ be _ONE_ message in here if we're not
     * trying to purge _ALL_ of the messages in the queue
     */
    if (all && nr == 0) {
        return 0;
    }


    /**
     * Reading the command log is not re-entrant safe, as an additional
     * command to the same server may result in the command log being modified.
     * To this end, we must first buffer all the commands in a separate
     * ringbuffer (or simple buffer) for that matter, and only *then*
     * invoke the callbacks
     */
    lcb_assert(nr == sizeof(req));

    if (req.request.opaque >= seqno) {
        return 0;
    }

    cmdlog = &c->instance->purged_buf;
    cookies = &c->instance->purged_cookies;
    ringbuffer_reset(cmdlog);
    ringbuffer_reset(cookies);

    /**
     * Move all the commands we want to purge into the relevant ("local") buffers.
     * We will later read from these local buffers
     */
    while (req.request.opaque < seqno) {
        lcb_size_t packetsize = ntohl(req.request.bodylen) + (lcb_uint32_t)sizeof(req);

        ringbuffer_memcpy(cmdlog, &c->cmd_log, packetsize);
        ringbuffer_consumed(&c->cmd_log, packetsize);


        ringbuffer_memcpy(cookies, &c->output_cookies, sizeof(struct lcb_command_data_st));
        ringbuffer_consumed(&c->output_cookies, sizeof(struct lcb_command_data_st));

        nr = ringbuffer_peek(&c->cmd_log, req.bytes, sizeof(req.bytes));

        if (!nr) {
            break;
        }

        lcb_assert(nr == sizeof(req));
    }

    nr = ringbuffer_peek(cmdlog, req.bytes, sizeof(req));
    lcb_assert(nr == sizeof(req));

    if (!all) {
        lcb_assert(c->cmd_log.nbytes);
    }

    do {
        struct lcb_command_data_st ct;
        char *packet = cmdlog->read_head;
        lcb_size_t packetsize = ntohl(req.request.bodylen) + (lcb_uint32_t)sizeof(req);
        char *keyptr;

        union {
            lcb_get_resp_t get;
            lcb_store_resp_t store;
            lcb_remove_resp_t remove;
            lcb_touch_resp_t touch;
            lcb_unlock_resp_t unlock;
            lcb_arithmetic_resp_t arithmetic;
            lcb_observe_resp_t observe;
        } resp;

        nr = ringbuffer_read(cookies, &ct, sizeof(ct));
        lcb_assert(nr == sizeof(ct));

        if (c->instance->histogram) {
            lcb_record_metrics(c->instance, end - ct.start, req.request.opcode);
        }

        if (!ringbuffer_is_continous(cmdlog, RINGBUFFER_READ, packetsize)) {
            packet = malloc(packetsize);
            if (packet == NULL) {
                lcb_error_handler(c->instance, LCB_CLIENT_ENOMEM, NULL);
                return -1;
            }

            nr = ringbuffer_peek(cmdlog, packet, packetsize);
            if (nr != packetsize) {
                lcb_error_handler(c->instance, LCB_EINTERNAL, NULL);
                free(packet);
                return -1;
            }
        }

        switch (req.request.opcode) {
        case PROTOCOL_BINARY_CMD_GATQ:
        case PROTOCOL_BINARY_CMD_GETQ:
            keyptr = packet + sizeof(req) + req.request.extlen;
            setup_lcb_get_resp_t(&resp.get, keyptr, ntohs(req.request.keylen),
                                 NULL, 0, 0, 0, 0);
            TRACE_GET_END(req.request.opaque, ntohs(req.request.vbucket),
                          req.request.opcode, LCB_KEY_ENOENT, &resp.get);
            c->instance->callbacks.get(c->instance, ct.cookie, LCB_KEY_ENOENT, &resp.get);
            break;
        case CMD_OBSERVE:
            lcb_failout_observe_request(c, &ct, packet,
                                        sizeof(req.bytes) + ntohl(req.request.bodylen),
                                        LCB_SERVER_BUG);
            break;
        case PROTOCOL_BINARY_CMD_NOOP:
            break;
        default: {
            char errinfo[128] = { '\0' };
            snprintf(errinfo, 128, "Unknown implicit send message op=%0x", req.request.opcode);
            lcb_error_handler(c->instance, LCB_EINTERNAL, errinfo);
            return -1;
        }
        }

        if (packet != cmdlog->read_head) {
            free(packet);
        }

        ringbuffer_consumed(cmdlog, packetsize);
        nr = ringbuffer_peek(cmdlog, req.bytes, sizeof(req));

        if (nr == 0) {
            return 0;
        }

        lcb_assert(nr == sizeof(req));
    } while (1); /* CONSTCOND */

    return 0;
}
示例#5
0
static void get_replica_response_handler(lcb_server_t *server,
                                         struct lcb_command_data_st *command_data,
                                         protocol_binary_response_header *res)
{
    lcb_t root = server->instance;
    protocol_binary_response_get *get = (void *)res;
    lcb_uint16_t status = ntohs(res->response.status);
    lcb_uint16_t nkey = ntohs(res->response.keylen);
    const char *key = (const char *)res;
    char *packet;

    lcb_error_t rc = map_error(root, status);

    key += sizeof(get->bytes);
    if (key == NULL) {
        lcb_error_handler(server->instance, LCB_EINTERNAL, NULL);
        return;
    }
    /**
     * Success? always perform the callback
     */
    if (status == PROTOCOL_BINARY_RESPONSE_SUCCESS) {
        const char *bytes = key + nkey;
        lcb_size_t nbytes = ntohl(res->response.bodylen) - nkey - res->response.extlen;
        lcb_get_resp_t resp;
        setup_lcb_get_resp_t(&resp, key, nkey, bytes, nbytes,
                             ntohl(get->message.body.flags),
                             res->response.cas,
                             res->response.datatype);
        TRACE_GET_END(res->response.opaque, command_data->vbucket,
                      res->response.opcode, rc, &resp);
        root->callbacks.get(root, command_data->cookie, rc, &resp);
        return;
    }

    key = get_key(server, &nkey, &packet);

    /**
     * Following code handles errors.
     */
    if (command_data->replica == -1) {
        /* Perform the callback. Either SELECT or ALL */
        lcb_get_resp_t resp;
        setup_lcb_get_resp_t(&resp, key, nkey, NULL, 0, 0, 0, 0);
        TRACE_GET_END(res->response.opaque, command_data->vbucket,
                      res->response.opcode, rc, &resp);
        root->callbacks.get(root, command_data->cookie, rc, &resp);
        release_key(server, packet);
        return;
    }

    /** LCB_REPLICA_FIRST */
    if (status == PROTOCOL_BINARY_RESPONSE_NOT_MY_VBUCKET) {
        /**
         * the config was updated, start from first replica.
         * Reset the iteration count
         */
        command_data->replica = 0;
    } else {
        command_data->replica++;
    }

    if (command_data->replica < root->nreplicas) {
        /* try next replica */
        protocol_binary_request_get req;
        lcb_server_t *new_server;
        int idx = vbucket_get_replica(root->vbucket_config,
                                      command_data->vbucket,
                                      command_data->replica);
        if (idx < 0 || idx > (int)root->nservers) {
            lcb_error_handler(root, LCB_NETWORK_ERROR,
                              "GET_REPLICA: missing server");
            release_key(server, packet);
            return;
        }
        new_server = root->servers + idx;
        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;
        req.message.header.request.keylen = ntohs((lcb_uint16_t)nkey);
        req.message.header.request.vbucket = ntohs(command_data->vbucket);
        req.message.header.request.bodylen = ntohl((lcb_uint32_t)nkey);
        req.message.header.request.opaque = ++root->seqno;
        TRACE_GET_BEGIN(&req, key, nkey, 0);
        lcb_server_retry_packet(new_server, command_data,
                                req.bytes, sizeof(req.bytes));
        lcb_server_write_packet(new_server, key, nkey);
        lcb_server_end_packet(new_server);
        lcb_server_send_packets(new_server);
    } else {
        /* give up and report the error */
        lcb_get_resp_t resp;
        setup_lcb_get_resp_t(&resp, key, nkey, NULL, 0, 0, 0,
                             res->response.datatype);
        TRACE_GET_END(res->response.opaque, command_data->vbucket,
                      res->response.opcode, rc, &resp);
        root->callbacks.get(root, command_data->cookie, rc, &resp);
    }

    release_key(server, packet);
}