Esempio n. 1
0
/**
 * Release all allocated resources for this server instance
 * @param server the server to destroy
 */
void lcb_server_destroy(lcb_server_t *server)
{
    lcb_server_release_connection(server, LCB_SUCCESS);

    /* Cancel all pending commands */
    if (server->cmd_log.nbytes) {
        lcb_server_purge_implicit_responses(server,
                                            server->instance->seqno,
                                            gethrtime(),
                                            1);
    }

    if (server->io_timer) {
        lcb_timer_destroy(NULL, server->io_timer);
    }


    lcb_connection_cleanup(&server->connection);

    free(server->rest_api_server);
    free(server->couch_api_base);
    free(server->authority);
    ringbuffer_destruct(&server->output_cookies);
    ringbuffer_destruct(&server->cmd_log);
    ringbuffer_destruct(&server->pending);
    ringbuffer_destruct(&server->pending_cookies);
    memset(server, 0xff, sizeof(*server));
}
Esempio n. 2
0
static void
Cw_handler(lcb_sockdata_t *sd, int status, void *arg)
{
    lcbio__EASYRB *erb = arg;
    lcbio_CTX *ctx = erb->parent;
    (void)sd;

    ctx->npending--;

    if (!ctx->output) {
        ctx->output = erb;
        ringbuffer_reset(&erb->rb);

    } else {
        ringbuffer_destruct(&erb->rb);
        free(erb);
    }

    if (ctx->state == ES_ACTIVE && status) {
        invoke_entered_errcb(ctx, convert_lcberr(ctx, LCBIO_IOERR));
    }

    if (ctx->state != ES_ACTIVE && ctx->npending == 0) {
        free_ctx(ctx);
    }
}
Esempio n. 3
0
static void destroy_request(struct observe_st *req)
{
    if (req->allocated) {
        ringbuffer_destruct(&req->body);
        req->allocated = 0;
    }
}
Esempio n. 4
0
void
lcbio_ctx_close_ex(lcbio_CTX *ctx, lcbio_CTXCLOSE_cb cb, void *arg,
                   lcbio_CTXDTOR_cb dtor, void *dtor_arg)
{
    unsigned oldrc;
    ctx->state = ES_DETACHED;
    assert(ctx->sock);

    if (ctx->event) {
        deactivate_watcher(ctx);
        IOT_V0EV(CTX_IOT(ctx)).destroy(IOT_ARG(CTX_IOT(ctx)), ctx->event);
        ctx->event = NULL;
    }

    if (ctx->as_err) {
        lcbio_timer_destroy(ctx->as_err);
        ctx->as_err = NULL;
    }

    oldrc = ctx->sock->refcount;
    lcb_log(LOGARGS(ctx, DEBUG), CTX_LOGFMT "Destroying. PND=%d,ENT=%d,SORC=%d", CTX_LOGID(ctx), (int)ctx->npending, (int)ctx->entered, oldrc);

    if (cb) {
        int reusable =
                ctx->npending == 0 && /* no pending events */
                ctx->err == LCB_SUCCESS && /* no socket errors */
                ctx->rdwant == 0 && /* no expected input */
                ctx->wwant == 0 && /* no expected output */
                (ctx->output == NULL || ctx->output->rb.nbytes == 0);
        cb(ctx->sock, reusable, arg);
    }

    if (oldrc == ctx->sock->refcount) {
        lcbio_shutdown(ctx->sock);
    }

    if (ctx->output) {
        ringbuffer_destruct(&ctx->output->rb);
        free(ctx->output);
        ctx->output = NULL;
    }

    ctx->fd = INVALID_SOCKET;
    ctx->sd = NULL;

    if (dtor) {
        ctx->data = dtor_arg;
        ctx->procs.cb_flush_ready = dtor;

    } else {
        ctx->procs.cb_flush_ready = NULL;
    }

    if (ctx->npending == 0 && ctx->entered == 0) {
        free_ctx(ctx);
    }
}
Esempio n. 5
0
static void destroy_requests(OBSERVECTX *reqs)
{
    lcb_size_t ii;
    for (ii = 0; ii < reqs->nrequests; ii++) {
        struct observe_st *rr = reqs->requests + ii;

        if (!rr->allocated) {
            continue;
        }

        ringbuffer_destruct(&rr->body);
        rr->allocated = 0;
    }
}
Esempio n. 6
0
void lcb_connection_cleanup(lcb_connection_t conn)
{
    if (conn->ai) {
        freeaddrinfo(conn->ai);
        conn->ai = NULL;
    }

    if (conn->input) {
        ringbuffer_destruct(conn->input);
        free(conn->input);
        conn->input = NULL;
    }

    if (conn->output) {
        ringbuffer_destruct(conn->output);
        free(conn->output);
        conn->output = NULL;
    }

    lcb_connection_close(conn);

    if (conn->evinfo.ptr) {
        conn->instance->io->v.v0.destroy_event(conn->instance->io,
                                               conn->evinfo.ptr);
        conn->evinfo.ptr = NULL;
    }

    lcb_connection_cancel_timer(conn);

    if (conn->timeout.timer) {
        conn->instance->io->v.v0.destroy_timer(conn->instance->io,
                                               conn->timeout.timer);
    }

    memset(conn, 0, sizeof(*conn));
}
Esempio n. 7
0
static void
free_ctx(lcbio_CTX *ctx)
{
    rdb_cleanup(&ctx->ior);
    lcbio_unref(ctx->sock);
    if (ctx->output) {
        ringbuffer_destruct(&ctx->output->rb);
        free(ctx->output);
    }
    if (ctx->procs.cb_flush_ready) {
        /* dtor */
        ctx->procs.cb_flush_ready(ctx);
    }
    free(ctx);
}
Esempio n. 8
0
int ringbuffer_ensure_alignment(ringbuffer_t *c)
{
#if defined(__hpux__) || defined(__hpux) || defined(__sparc__) || defined(__sparc)
    intptr_t addr = (intptr_t)c->read_head;

    if (addr % 8 != 0) {
        ringbuffer_t copy;
        if (ringbuffer_initialize(&copy, c->size) == 0 || ringbuffer_memcpy(&copy, c, ringbuffer_get_nbytes(c)) == -1) {
            return -1;
        }
        ringbuffer_destruct(c);
        *c = copy;
    }
#else
    (void)c;
#endif
    return 0;
}
Esempio n. 9
0
LIBCOUCHBASE_API
void lcb_destroy(lcb_t instance)
{
    lcb_size_t ii;
    lcb_settings *settings = &instance->settings;

    if (instance->cur_configinfo) {
        lcb_clconfig_decref(instance->cur_configinfo);
        instance->cur_configinfo = NULL;
    }
    instance->vbucket_config = NULL;

    lcb_bootstrap_destroy(instance);
    lcb_confmon_destroy(instance->confmon);
    hostlist_destroy(instance->usernodes);

    if (instance->timers != NULL) {
        for (ii = 0; ii < instance->timers->capacity; ++ii) {
            if (instance->timers->items[ii] > 1) {
                lcb_timer_destroy(instance,
                                  (lcb_timer_t)instance->timers->items[ii]);
            }
        }
        hashset_destroy(instance->timers);
    }

    if (instance->durability_polls) {
        struct lcb_durability_set_st **dset_list;
        lcb_size_t nitems = hashset_num_items(instance->durability_polls);
        dset_list = (struct lcb_durability_set_st **)
                    hashset_get_items(instance->durability_polls, NULL);
        if (dset_list) {
            for (ii = 0; ii < nitems; ii++) {
                lcb_durability_dset_destroy(dset_list[ii]);
            }
            free(dset_list);
        }
        hashset_destroy(instance->durability_polls);
    }

    for (ii = 0; ii < instance->nservers; ++ii) {
        lcb_server_destroy(instance->servers + ii);
    }

    if (instance->http_requests) {
        for (ii = 0; ii < instance->http_requests->capacity; ++ii) {
            if (instance->http_requests->items[ii] > 1) {
                lcb_http_request_t htreq =
                    (lcb_http_request_t)instance->http_requests->items[ii];

                /**
                 * We don't want to invoke callbacks *or* remove it from our
                 * hash table
                 */
                htreq->status |= LCB_HTREQ_S_CBINVOKED | LCB_HTREQ_S_HTREMOVED;

                /* we should figure out a better error code for this.. */
                lcb_http_request_finish(instance, htreq, LCB_ERROR);
            }
        }
    }

    hashset_destroy(instance->http_requests);

    free(instance->servers);

    connmgr_destroy(instance->memd_sockpool);

    if (settings->io && settings->io->v.v0.need_cleanup) {
        lcb_destroy_io_ops(settings->io);
    }

    ringbuffer_destruct(&instance->purged_buf);
    ringbuffer_destruct(&instance->purged_cookies);

    free(instance->histogram);
    free(instance->scratch);
    free(settings->username);
    free(settings->password);
    free(settings->bucket);
    free(settings->sasl_mech_force);
    if (instance->cmdht) {
        genhash_free(instance->cmdht);
        instance->cmdht = NULL;
    }

    memset(instance, 0xff, sizeof(*instance));
    free(instance);
}
Esempio n. 10
0
static void purge_single_server(lcb_server_t *server, lcb_error_t error,
                                hrtime_t min_nonstale,
                                hrtime_t *tmo_next)
{
    protocol_binary_request_header req;
    struct lcb_command_data_st ct;
    lcb_size_t nr;
    char *packet;
    lcb_size_t packetsize;
    char *keyptr;
    ringbuffer_t rest;
    ringbuffer_t *stream = &server->cmd_log;
    ringbuffer_t *cookies;
    ringbuffer_t *mirror = NULL; /* mirror buffer should be purged with main stream */
    lcb_connection_t conn = &server->connection;
    lcb_size_t send_size = 0;
    lcb_size_t stream_size = ringbuffer_get_nbytes(stream);
    hrtime_t now = gethrtime();

    if (server->connection_ready) {
        cookies = &server->output_cookies;
    } else {
        cookies = &server->pending_cookies;
        mirror = &server->pending;
    }

    if (conn->output) {
        /* This will usually be false for v1 */
        send_size = ringbuffer_get_nbytes(conn->output);
    }

    lcb_assert(ringbuffer_initialize(&rest, 1024));


    do {
        int allocated = 0;
        lcb_uint32_t headersize;
        lcb_uint16_t nkey;

        nr = ringbuffer_peek(cookies, &ct, sizeof(ct));
        if (nr != sizeof(ct)) {
            break;
        }
        nr = ringbuffer_peek(stream, req.bytes, sizeof(req));
        if (nr != sizeof(req)) {
            break;
        }
        packetsize = (lcb_uint32_t)sizeof(req) + ntohl(req.request.bodylen);
        if (stream->nbytes < packetsize) {
            break;
        }
        if (min_nonstale && ct.start >= min_nonstale) {
            lcb_log(LOGARGS(server, INFO),
                    "Still have %d ms remaining for command",
                    (ct.start - min_nonstale) / 1000000);

            if (tmo_next) {
                *tmo_next = (ct.start - min_nonstale) + 1;
            }
            break;
        }

        lcb_log(LOGARGS(server, INFO),
                "Command with cookie=%p timed out from server %s:%s",
                ct.cookie,
                server->curhost.host,
                server->curhost.port);

        ringbuffer_consumed(cookies, sizeof(ct));

        lcb_assert(nr == sizeof(req));
        packet = stream->read_head;

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

        if (server->connection_ready &&
                stream_size > send_size && (stream_size - packetsize) < send_size) {
            /* Copy the rest of the current packet into the
               temporary stream */

            /* I do believe I have some IOV functions to do that? */
            lcb_size_t nbytes = packetsize - (stream_size - send_size);
            lcb_assert(ringbuffer_memcpy(&rest,
                                         conn->output,
                                         nbytes) == 0);
            ringbuffer_consumed(conn->output, nbytes);
            send_size -= nbytes;
        }
        stream_size -= packetsize;
        headersize = (lcb_uint32_t)sizeof(req) + req.request.extlen + htons(req.request.keylen);
        if (!ringbuffer_is_continous(stream, RINGBUFFER_READ, headersize)) {
            packet = malloc(headersize);
            if (packet == NULL) {
                lcb_error_handler(server->instance, LCB_CLIENT_ENOMEM, NULL);
                abort();
            }

            nr = ringbuffer_peek(stream, packet, headersize);
            if (nr != headersize) {
                lcb_error_handler(server->instance, LCB_EINTERNAL, NULL);
                free(packet);
                abort();
            }
            allocated = 1;
        }

        keyptr = packet + sizeof(req) + req.request.extlen;
        nkey = ntohs(req.request.keylen);

        failout_single_request(server, &req, &ct, error, keyptr, nkey, packet);

        if (allocated) {
            free(packet);
        }
        ringbuffer_consumed(stream, packetsize);
        if (mirror) {
            ringbuffer_consumed(mirror, packetsize);
        }
    } while (1); /* CONSTCOND */

    if (server->connection_ready && conn->output) {
        /* Preserve the rest of the stream */
        lcb_size_t nbytes = ringbuffer_get_nbytes(stream);
        send_size = ringbuffer_get_nbytes(conn->output);

        if (send_size >= nbytes) {
            ringbuffer_consumed(conn->output, send_size - nbytes);
            lcb_assert(ringbuffer_memcpy(&rest, conn->output, nbytes) == 0);
        }
        ringbuffer_reset(conn->output);
        ringbuffer_append(&rest, conn->output);
    }

    ringbuffer_destruct(&rest);
    lcb_maybe_breakout(server->instance);
}
Esempio n. 11
0
static libcouchbase_error_t create_memcached(const struct libcouchbase_memcached_st *user,
                                             VBUCKET_CONFIG_HANDLE vbconfig)
{
    ringbuffer_t buffer;
    char *copy = strdup(user->serverlist);
    char head[1024];
    int first;
    char *ptr = copy;
    int fail;
    libcouchbase_ssize_t offset = 0;

    if (copy == NULL) {
        return LIBCOUCHBASE_CLIENT_ENOMEM;
    }

    if (ringbuffer_initialize(&buffer, 1024) == -1) {
        free(copy);
        return LIBCOUCHBASE_CLIENT_ENOMEM;
    }

    head[0] = '\0';
    offset += snprintf(head + offset, sizeof(head) - offset, "%s", "{");
    offset += snprintf(head + offset, sizeof(head) - offset, "%s",
                       "\"bucketType\":\"memcached\",");
    offset += snprintf(head + offset, sizeof(head) - offset, "%s",
                       "\"nodeLocator\":\"ketama\",");
    if (user->username != NULL) {
        offset += snprintf(head + offset, sizeof(head) - offset, "%s",
                           "\"authType\":\"sasl\",");
        offset += snprintf(head + offset, sizeof(head) - offset, "%s",
                           "\"name\":\"");
        offset += snprintf(head + offset, sizeof(head) - offset, "%s",
                           user->username);
        offset += snprintf(head + offset, sizeof(head) - offset, "%s", "\",");
        if (user->password != NULL) {
            offset += snprintf(head + offset, sizeof(head) - offset, "%s",
                               "\"saslPassword\":\"");
            offset += snprintf(head + offset, sizeof(head) - offset, "%s",
                               user->password);
            offset += snprintf(head + offset, sizeof(head) - offset, "%s",
                               "\",");
        }
    }

    offset += snprintf(head + offset, sizeof(head) - offset, "%s",
                       "\"nodes\": [");
    ringbuffer_write(&buffer, head, strlen(head));

    /* Let's add the hosts... */
    first = 1;
    do {
        char *tok;
        char *next = strchr(ptr, ';');
        const char *port = "11211";
        libcouchbase_ssize_t length;

        if (next != NULL) {
            *next = '\0';
        }

        tok = strchr(ptr, ':');
        if (tok != NULL) {
            *tok = '\0';
            port = tok + 1;
            if ((tok = strchr(ptr, ':')) != NULL) {
                *tok = '\0'; /* Remove weight for now */
            }
        }

        length = snprintf(head, sizeof(head),
                          "%c{\"hostname\":\"%s\",\"ports\":{\"direct\":%s}}",
                          first ? ' ' : ',', ptr, port);
        first = 0;

        if (ringbuffer_ensure_capacity(&buffer, length) == -1) {
            free(copy);
            return LIBCOUCHBASE_CLIENT_ENOMEM;
        }

        ringbuffer_write(&buffer, head, length);

        if (next != NULL) {
            ptr = next + 1;
        } else {
            ptr = NULL;
        }
    } while (ptr != NULL);

    if (ringbuffer_ensure_capacity(&buffer, 3) == -1) {
        free(copy);
        return LIBCOUCHBASE_CLIENT_ENOMEM;
    }

    ringbuffer_write(&buffer, "]}", 3); /* Include '\0' */

    /* Now let's parse the config! */
    fail = vbucket_config_parse(vbconfig, LIBVBUCKET_SOURCE_MEMORY,
                                (char *)ringbuffer_get_read_head(&buffer));
    free(copy);
    ringbuffer_destruct(&buffer);

    if (fail) {
        /* Hmm... internal error! */
        return LIBCOUCHBASE_EINTERNAL;
    }

    return LIBCOUCHBASE_SUCCESS;
}