Esempio n. 1
0
static void observe_response_handler(lcb_server_t *server,
                                     packet_info *info)
{
    lcb_t root = server->instance;
    lcb_error_t rc = map_error(root, PACKET_STATUS(info));
    lcb_uint32_t ttp;
    lcb_uint32_t ttr;
    lcb_size_t pos;

    VBUCKET_CONFIG_HANDLE config;
    const char *end, *ptr;

    /**
     * If we have an error we must decode the request instead
     */
    if (rc != LCB_SUCCESS) {
        protocol_binary_request_header req;
        lcb_size_t nr;

        nr = ringbuffer_peek(&server->cmd_log, req.bytes, sizeof(req.bytes));
        if (nr != sizeof(req.bytes)) {
            lcb_error_handler(server->instance, LCB_EINTERNAL, NULL);
            abort();
        }

        if (req.request.bodylen) {
            lcb_size_t npacket = sizeof(req.bytes) + ntohl(req.request.bodylen);
            char *packet = server->cmd_log.read_head;
            int allocated = 0;

            if (!ringbuffer_is_continous(&server->cmd_log, RINGBUFFER_READ, npacket)) {
                packet = malloc(npacket);
                if (packet == NULL) {
                    lcb_error_handler(root, LCB_CLIENT_ENOMEM, NULL);
                    abort();
                }
                nr = ringbuffer_peek(&server->cmd_log, packet, npacket);
                if (nr != npacket) {
                    lcb_error_handler(root, LCB_EINTERNAL, NULL);
                    free(packet);
                    abort();
                }
                allocated = 1;
            }
            lcb_failout_observe_request(server, &info->ct, packet, npacket, rc);
            if (allocated) {
                free(packet);
            }
        }
        return;
    }

    /** The CAS field is split into TTP/TTR values */
    ptr = (char *)&info->res.response.cas;
    memcpy(&ttp, ptr, sizeof(ttp));
    memcpy(&ttr, ptr + sizeof(ttp), sizeof(ttp));

    ttp = ntohl(ttp);
    ttr = ntohl(ttr);

    /** Actual payload sequence of (vb, nkey, key). Repeats multiple times */
    ptr = info->payload;
    end = (char *)ptr + PACKET_NBODY(info);
    config = root->vbucket_config;

    for (pos = 0; ptr < end; pos++) {
        lcb_cas_t cas;
        lcb_uint8_t obs;
        lcb_uint16_t nkey, vb;
        const char *key;
        lcb_observe_resp_t resp;

        memcpy(&vb, ptr, sizeof(vb));
        vb = ntohs(vb);
        ptr += sizeof(vb);
        memcpy(&nkey, ptr, sizeof(nkey));
        nkey = ntohs(nkey);
        ptr += sizeof(nkey);
        key = (const char *)ptr;
        ptr += nkey;
        obs = *((lcb_uint8_t *)ptr);
        ptr += sizeof(obs);
        memcpy(&cas, ptr, sizeof(cas));
        ptr += sizeof(cas);

        setup_lcb_observe_resp_t(&resp, key, nkey, cas, obs,
                                 server->index == vbucket_get_master(config, vb),
                                 ttp, ttr);
        PACKET_TRACE(TRACE_OBSERVE_PROGRESS, info, rc, &resp);
        lcb_observe_invoke_callback(root, &info->ct, rc, &resp);
    }

    /* run callback with null-null-null to signal the end of transfer */
    if ((info->ct.flags & LCB_CMD_F_OBS_BCAST) &&
            lcb_lookup_server_with_command(root, CMD_OBSERVE,
                                           PACKET_OPAQUE(info), server) < 0) {

        lcb_observe_resp_t resp;
        memset(&resp, 0, sizeof(resp));
        PACKET_TRACE_NORES(TRACE_OBSERVE_END, info, rc);
        lcb_observe_invoke_callback(root, &info->ct, LCB_SUCCESS, &resp);
    }
}
Esempio n. 2
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;
}
Esempio n. 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);
    }

}
Esempio n. 4
0
static void observe_response_handler(lcb_server_t *server,
                                     struct lcb_command_data_st *command_data,
                                     protocol_binary_response_header *res)
{
    lcb_t root = server->instance;
    lcb_uint16_t status = ntohs(res->response.status);
    lcb_error_t rc = map_error(root, status);
    lcb_uint32_t ttp;
    lcb_uint32_t ttr;
    lcb_size_t pos;

    VBUCKET_CONFIG_HANDLE config;
    const char *end, *ptr = (const char *)&res->response.cas;

    /**
     * If we have an error we must decode the request instead
     */
    if (rc != LCB_SUCCESS) {
        protocol_binary_request_header req;
        lcb_size_t nr;

        nr = ringbuffer_peek(&server->cmd_log, req.bytes, sizeof(req.bytes));
        if (nr != sizeof(req.bytes)) {
            lcb_error_handler(server->instance, LCB_EINTERNAL, NULL);
            abort();
        }
        if (req.request.bodylen) {
            lcb_size_t npacket = sizeof(req.bytes) + ntohl(req.request.bodylen);
            char *packet = server->cmd_log.read_head;
            int allocated = 0;

            if (!ringbuffer_is_continous(&server->cmd_log, RINGBUFFER_READ, npacket)) {
                packet = malloc(npacket);
                if (packet == NULL) {
                    lcb_error_handler(root, LCB_CLIENT_ENOMEM, NULL);
                    abort();
                }
                nr = ringbuffer_peek(&server->cmd_log, packet, npacket);
                if (nr != npacket) {
                    lcb_error_handler(root, LCB_EINTERNAL, NULL);
                    free(packet);
                    abort();
                }
                allocated = 1;
            }
            lcb_failout_observe_request(server, command_data, packet, npacket, rc);
            if (allocated) {
                free(packet);
            }
        }
        return;
    }


    memcpy(&ttp, ptr, sizeof(ttp));
    ttp = ntohl(ttp);
    memcpy(&ttr, ptr + sizeof(ttp), sizeof(ttr));
    ttr = ntohl(ttr);


    ptr = (const char *)res + sizeof(res->bytes);
    end = ptr + ntohl(res->response.bodylen);
    config = root->vbucket_config;
    for (pos = 0; ptr < end; pos++) {
        lcb_cas_t cas;
        lcb_uint8_t obs;
        lcb_uint16_t nkey, vb;
        const char *key;
        lcb_observe_resp_t resp;

        memcpy(&vb, ptr, sizeof(vb));
        vb = ntohs(vb);
        ptr += sizeof(vb);
        memcpy(&nkey, ptr, sizeof(nkey));
        nkey = ntohs(nkey);
        ptr += sizeof(nkey);
        key = (const char *)ptr;
        ptr += nkey;
        obs = *((lcb_uint8_t *)ptr);
        ptr += sizeof(obs);
        memcpy(&cas, ptr, sizeof(cas));
        ptr += sizeof(cas);

        setup_lcb_observe_resp_t(&resp, key, nkey, cas, obs,
                                 server->index == vbucket_get_master(config, vb),
                                 ttp, ttr);
        TRACE_OBSERVE_PROGRESS(res->response.opaque, command_data->vbucket,
                               res->response.opcode, rc, &resp);
        lcb_observe_invoke_callback(root, command_data, rc, &resp);
    }

    /* run callback with null-null-null to signal the end of transfer */
    if ((command_data->flags & LCB_CMD_F_OBS_BCAST) &&
            lcb_lookup_server_with_command(root, CMD_OBSERVE,
                                           res->response.opaque, server) < 0) {

        lcb_observe_resp_t resp;
        memset(&resp, 0, sizeof(resp));
        TRACE_OBSERVE_END(res->response.opaque, command_data->vbucket,
                          res->response.opcode, rc);
        lcb_observe_invoke_callback(root, command_data, LCB_SUCCESS, &resp);
    }
}