Пример #1
0
clconfig_provider * lcb_clconfig_create_http(lcb_confmon *parent)
{
    lcb_error_t status;
    struct lcb_io_use_st use;
    http_provider *http = calloc(1, sizeof(*http));
    if (!http) {
        return NULL;
    }

    status = lcb_connection_init(&http->connection,
                                 parent->settings->io,
                                 parent->settings);

    if (status != LCB_SUCCESS) {
        free(http);
        return NULL;
    }

    if (! (http->nodes = hostlist_create())) {
        lcb_connection_cleanup(&http->connection);
        free(http);
        return NULL;
    }

    http->base.type = LCB_CLCONFIG_HTTP;
    http->base.refresh = get_refresh;
    http->base.pause = pause_http;
    http->base.get_cached = http_get_cached;
    http->base.shutdown = shutdown_http;
    http->base.nodes_updated = refresh_nodes;
    http->base.enabled = 0;
    http->io_timer = lcb_timer_create_simple(parent->settings->io,
                                             http,
                                             parent->settings->config_node_timeout,
                                             timeout_handler);
    lcb_timer_disarm(http->io_timer);

    http->disconn_timer = lcb_timer_create_simple(parent->settings->io,
                                                  http,
                                                  parent->settings->bc_http_stream_time,
                                                  delayed_disconn);
    lcb_timer_disarm(http->disconn_timer);

    lcb_connuse_easy(&use, http, io_read_handler, io_error_handler);
    lcb_connection_use(&http->connection, &use);

    lcb_string_init(&http->stream.chunk);
    lcb_string_init(&http->stream.header);
    lcb_string_init(&http->stream.input);

    return &http->base;
}
Пример #2
0
static void timer_callback(lcb_socket_t sock, short which, void *arg)
{
    lcb_timer_t timer = arg;
    lcb_t instance = timer->instance;

    lcb_assert(TMR_IS_ARMED(timer));
    lcb_assert(!TMR_IS_DESTROYED(timer));

    timer->state |= LCB_TIMER_S_ENTERED;

    lcb_timer_disarm(timer);
    timer->callback(timer, instance, timer->cookie);

    if (TMR_IS_DESTROYED(timer) == 0 && TMR_IS_PERIODIC(timer) != 0) {
        lcb_timer_rearm(timer, timer->usec_);
        return;
    }

    if (! TMR_IS_STANDALONE(timer)) {
        lcb_aspend_del(&instance->pendops, LCB_PENDTYPE_TIMER, timer);
        lcb_maybe_breakout(instance);
    }

    if (TMR_IS_DESTROYED(timer)) {
        destroy_timer(timer);
    } else {
        timer->state &= ~LCB_TIMER_S_ENTERED;
    }

    (void)sock;
    (void)which;
}
Пример #3
0
static lcb_error_t get_refresh(clconfig_provider *provider)
{
    http_provider *http = (http_provider *)provider;

    /**
     * We want a grace interval here because we might already be fetching a
     * connection. HOWEVER we don't want to indefinitely wait on a socket
     * so we issue a timer indicating how long we expect to wait for a
     * streaming update until we get something.
     */

    /** If we need a new socket, we do connect_next. */
    if (http->connection.state == LCB_CONNSTATE_UNINIT) {
        lcb_error_t rc = connect_next(http);
        if (rc != LCB_SUCCESS) {
            http->as_errcode = rc;
            lcb_async_signal(http->as_schederr);
        }
        return rc;
    }

    lcb_timer_disarm(http->disconn_timer);
    if (http->connection.state == LCB_CONNSTATE_CONNECTED) {
        lcb_timer_rearm(http->io_timer,
                        PROVIDER_SETTING(provider, config_node_timeout));
    }
    return LCB_SUCCESS;
}
Пример #4
0
clconfig_provider * lcb_clconfig_create_cccp(lcb_confmon *mon)
{
    cccp_provider *cccp = calloc(1, sizeof(*cccp));
    cccp->nodes = hostlist_create();
    cccp->base.type = LCB_CLCONFIG_CCCP;
    cccp->base.refresh = cccp_get;
    cccp->base.get_cached = cccp_get_cached;
    cccp->base.pause = cccp_pause;
    cccp->base.shutdown = cccp_cleanup;
    cccp->base.nodes_updated = nodes_updated;
    cccp->base.parent = mon;
    cccp->base.enabled = 0;
    cccp->timer = lcb_timer_create_simple(mon->settings->io,
                                          cccp,
                                          mon->settings->config_timeout,
                                          socket_timeout);
    lcb_timer_disarm(cccp->timer);

    if (!cccp->nodes) {
        free(cccp);
        return NULL;
    }

    if (lcb_connection_init(&cccp->connection,
                            cccp->base.parent->settings->io,
                            cccp->base.parent->settings) != LCB_SUCCESS) {
        free(cccp);
        return NULL;
    }

    return &cccp->base;
}
Пример #5
0
void lcb_clconfig_set_http_always_on(clconfig_provider *pb)
{
    http_provider *http = (http_provider *)pb;
    if (!pb->enabled) {
        return;
    }
    lcb_timer_disarm(http->disconn_timer);
    http->always_on = 1;
}
Пример #6
0
/**
 * Call this if the configuration generation has changed.
 */
static void set_new_config(http_provider *http)
{
    if (http->current_config) {
        lcb_clconfig_decref(http->current_config);
    }

    http->current_config = http->stream.config;
    lcb_clconfig_incref(http->current_config);
    lcb_confmon_provider_success(&http->base, http->current_config);
    lcb_timer_disarm(http->io_timer);
}
Пример #7
0
static lcb_error_t schedule_next_request(cccp_provider *cccp,
        lcb_error_t err,
        int can_rollover)
{
    lcb_server_t *server = NULL;
    lcb_size_t ii;

    lcb_host_t *next_host = hostlist_shift_next(cccp->nodes, can_rollover);

    if (!next_host) {
        lcb_timer_disarm(cccp->timer);
        lcb_confmon_provider_failed(&cccp->base, err);
        cccp->server_active = 0;
        return err;
    }

    /** See if we can find a server */
    for (ii = 0; ii < cccp->instance->nservers; ii++) {
        lcb_server_t *cur = cccp->instance->servers + ii;
        if (lcb_host_equals(&cur->curhost, next_host)) {
            server = cur;
            break;
        }
    }

    if (server) {
        protocol_binary_request_get_cluster_config req;
        cccp_cookie *cookie = calloc(1, sizeof(*cookie));

        lcb_log(LOGARGS(cccp, INFO),
                "Re-Issuing CCCP Command on server struct %p", server);

        cookie->parent = cccp;
        memset(&req, 0, sizeof(req));
        req.message.header.request.magic = PROTOCOL_BINARY_REQ;
        req.message.header.request.opcode = CMD_GET_CLUSTER_CONFIG;
        req.message.header.request.opaque = ++cccp->instance->seqno;
        lcb_server_start_packet(server, cookie, &req, sizeof(req.bytes));
        lcb_server_end_packet(server);
        lcb_server_send_packets(server);
        lcb_timer_rearm(cccp->timer, PROVIDER_SETTING(&cccp->base,
                        config_node_timeout));
    } else {
        cccp->cur_connreq = calloc(1, sizeof(*cccp->cur_connreq));
        connmgr_req_init(cccp->cur_connreq, next_host->host, next_host->port,
                         socket_connected);
        cccp->cur_connreq->data = cccp;
        connmgr_get(cccp->instance->memd_sockpool, cccp->cur_connreq,
                    PROVIDER_SETTING(&cccp->base, config_node_timeout));
    }

    cccp->server_active = 1;
    return LCB_SUCCESS;
}
Пример #8
0
static lcb_error_t cccp_pause(clconfig_provider *pb)
{
    cccp_provider *cccp = (cccp_provider *)pb;
    if (!cccp->server_active) {
        return LCB_SUCCESS;
    }

    cccp->server_active = 0;
    release_socket(cccp, 0);
    lcb_timer_disarm(cccp->timer);
    return LCB_SUCCESS;
}
Пример #9
0
LCB_INTERNAL_API
void lcb_timer_rearm(lcb_timer_t timer, lcb_uint32_t usec)
{
    if (TMR_IS_ARMED(timer)) {
        lcb_timer_disarm(timer);
    }

    timer->usec_ = usec;
    timer->io->timer.schedule(timer->io->p, timer->event,
                              usec, timer, timer_callback);
    timer->state |= LCB_TIMER_S_ARMED;
}
Пример #10
0
static void delayed_disconn(lcb_timer_t tm, lcb_t instance, const void *cookie)
{
    http_provider *http = (http_provider *)cookie;
    lcb_log(LOGARGS(http, DEBUG), "Stopping HTTP provider %p", http);

    /** closes the connection and cleans up the timer */
    close_current(http);
    lcb_timer_disarm(http->io_timer);
    reset_stream_state(http);

    (void)tm;
    (void)instance;
}
Пример #11
0
static lcb_error_t pause_http(clconfig_provider *pb)
{
    http_provider *http = (http_provider *)pb;
    if (http->always_on) {
        lcb_timer_disarm(http->io_timer);
        return LCB_SUCCESS;
    }

    if (!lcb_timer_armed(http->disconn_timer)) {
        lcb_timer_rearm(http->disconn_timer,
                        PROVIDER_SETTING(pb, bc_http_stream_time));
    }
    return LCB_SUCCESS;
}
Пример #12
0
LIBCOUCHBASE_API
lcb_error_t lcb_timer_destroy(lcb_t instance, lcb_timer_t timer)
{
    int standalone = timer->options & LCB_TIMER_STANDALONE;

    if (!standalone) {
        lcb_aspend_del(&instance->pendops, LCB_PENDTYPE_TIMER, timer);
    }

    lcb_timer_disarm(timer);

    if (timer->state & LCB_TIMER_S_ENTERED) {
        timer->state |= LCB_TIMER_S_DESTROYED;
        lcb_assert(TMR_IS_DESTROYED(timer));
    } else {
        destroy_timer(timer);
    }
    return LCB_SUCCESS;
}
Пример #13
0
/**
 * Call when there is an error in I/O. This includes read, write, connect
 * and timeouts.
 */
static lcb_error_t io_error(http_provider *http)
{
    lcb_error_t err;
    lcb_conn_params params;
    char *errinfo;

    close_current(http);

    params.timeout = PROVIDER_SETTING(&http->base, config_node_timeout);
    params.handler = connect_done_handler;
    err = lcb_connection_next_node(&http->connection,
                                   http->nodes, &params, &errinfo);

    if (err != LCB_SUCCESS) {
        lcb_confmon_provider_failed(&http->base, err);
        lcb_timer_disarm(http->io_timer);
        return err;
    } else {
        setup_request_header(http);
    }
    return LCB_SUCCESS;
}
Пример #14
0
/**
 * Call when there is an error in I/O. This includes read, write, connect
 * and timeouts.
 */
static lcb_error_t io_error(http_provider *http, lcb_error_t origerr)
{
    lcb_error_t err;
    lcb_conn_params params;
    char *errinfo;
    int can_retry = 0;

    close_current(http);

    params.timeout = PROVIDER_SETTING(&http->base, config_node_timeout);
    params.handler = connect_done_handler;

    if (http->base.parent->config) {
        can_retry = 1;
    } else if (origerr != LCB_AUTH_ERROR && origerr != LCB_BUCKET_ENOENT) {
        can_retry = 1;
    }
    if (can_retry) {
        err = lcb_connection_next_node(
                &http->connection, http->nodes, &params, &errinfo);
    } else {
        err = origerr;
    }

    if (err != LCB_SUCCESS) {
        lcb_confmon_provider_failed(&http->base, origerr);
        lcb_timer_disarm(http->io_timer);
        if (is_v220_compat(http)) {
            lcb_log(LOGARGS(http, INFO),
                    "HTTP node list finished. Looping again (disconn_tmo=-1)");
            connect_next(http);
        }
        return origerr;
    } else {
        setup_request_header(http);
    }
    return LCB_SUCCESS;
}
Пример #15
0
lcb_error_t lcb_server_initialize(lcb_server_t *server, int servernum)
{
    /* Initialize all members */
    lcb_error_t err;
    char *p;
    const char *n = vbucket_config_get_server(server->instance->vbucket_config,
                                              servernum);

    err = lcb_connection_init(&server->connection,
                              server->instance->settings.io,
                              &server->instance->settings);
    if (err != LCB_SUCCESS) {
        return err;
    }

    server->connection.data = server;
    server->index = servernum;
    server->authority = strdup(n);
    strcpy(server->curhost.host, n);
    p = strchr(server->curhost.host, ':');
    *p = '\0';
    strcpy(server->curhost.port, p + 1);

    n = vbucket_config_get_couch_api_base(server->instance->vbucket_config,
                                          servernum);
    server->couch_api_base = (n != NULL) ? strdup(n) : NULL;
    n = vbucket_config_get_rest_api_server(server->instance->vbucket_config,
                                           servernum);
    server->rest_api_server = strdup(n);
    server->io_timer = lcb_timer_create_simple(server->instance->settings.io,
                                               server, MCSERVER_TIMEOUT(server),
                                               tmo_thunk);
    lcb_timer_disarm(server->io_timer);

    return LCB_SUCCESS;
}
Пример #16
0
static void io_read_handler(lcb_connection_t conn)
{
    packet_info pi;
    cccp_provider *cccp = conn->data;
    lcb_string jsonstr;
    lcb_error_t err;
    int rv;
    lcb_host_t curhost;

    memset(&pi, 0, sizeof(pi));

    rv = lcb_packet_read_ringbuffer(&pi, conn->input);

    if (rv < 0) {
        LOG(cccp, ERR, "Couldn't parse packet!?");
        mcio_error(cccp, LCB_EINTERNAL);
        return;

    } else if (rv == 0) {
        lcb_sockrw_set_want(conn, LCB_READ_EVENT, 1);
        lcb_sockrw_apply_want(conn);
        return;
    }

    if (PACKET_STATUS(&pi) != PROTOCOL_BINARY_RESPONSE_SUCCESS) {
        lcb_log(LOGARGS(cccp, ERR),
                "CCCP Packet responded with 0x%x; nkey=%d, nbytes=%lu, cmd=0x%x, seq=0x%x",
                PACKET_STATUS(&pi),
                PACKET_NKEY(&pi),
                PACKET_NBODY(&pi),
                PACKET_OPCODE(&pi),
                PACKET_OPAQUE(&pi));

        switch (PACKET_STATUS(&pi)) {
        case PROTOCOL_BINARY_RESPONSE_NOT_SUPPORTED:
        case PROTOCOL_BINARY_RESPONSE_UNKNOWN_COMMAND:
            mcio_error(cccp, LCB_NOT_SUPPORTED);
            break;
        default:
            mcio_error(cccp, LCB_PROTOCOL_ERROR);
            break;
        }

        return;
    }

    if (!PACKET_NBODY(&pi)) {
        mcio_error(cccp, LCB_PROTOCOL_ERROR);
        return;
    }

    if (lcb_string_init(&jsonstr)) {
        mcio_error(cccp, LCB_CLIENT_ENOMEM);
        return;
    }

    if (lcb_string_append(&jsonstr, PACKET_BODY(&pi), PACKET_NBODY(&pi))) {
        mcio_error(cccp, LCB_CLIENT_ENOMEM);
        return;
    }

    curhost = *lcb_connection_get_host(&cccp->connection);
    lcb_packet_release_ringbuffer(&pi, conn->input);
    release_socket(cccp, 1);

    err = lcb_cccp_update(&cccp->base, curhost.host, &jsonstr);
    lcb_string_release(&jsonstr);
    if (err == LCB_SUCCESS) {
        lcb_timer_disarm(cccp->timer);
        cccp->server_active = 0;
    } else {
        schedule_next_request(cccp, LCB_PROTOCOL_ERROR, 0);
    }
}
Пример #17
0
/**
 * Closes the current connection and removes the disconn timer along with it
 */
static void close_current(http_provider *http)
{
    lcb_timer_disarm(http->disconn_timer);
    lcb_connection_close(&http->connection);
}