Exemplo n.º 1
0
static void *writer_main(void *_conn)
{
    struct st_h2o_memcached_conn_t *conn = _conn;
    yrmcds_error err;

    pthread_mutex_lock(&conn->ctx->mutex);

    while (!__sync_add_and_fetch(&conn->writer_exit_requested, 0)) {
        while (!h2o_linklist_is_empty(&conn->ctx->pending)) {
            h2o_memcached_req_t *req = H2O_STRUCT_FROM_MEMBER(h2o_memcached_req_t, pending, conn->ctx->pending.next);
            h2o_linklist_unlink(&req->pending);
            pthread_mutex_unlock(&conn->ctx->mutex);

            switch (req->type) {
            case REQ_TYPE_GET:
                pthread_mutex_lock(&conn->mutex);
                h2o_linklist_insert(&conn->inflight, &req->inflight);
                pthread_mutex_unlock(&conn->mutex);
                if ((err = yrmcds_get(&conn->yrmcds, req->key.base, req->key.len, 0, &req->data.get.serial)) != YRMCDS_OK)
                    goto Error;
                break;
            case REQ_TYPE_SET:
                err = yrmcds_set(&conn->yrmcds, req->key.base, req->key.len, req->data.set.value.base, req->data.set.value.len, 0,
                                 req->data.set.expiration, 0, !conn->yrmcds.text_mode, NULL);
                discard_req(req);
                if (err != YRMCDS_OK)
                    goto Error;
                break;
            case REQ_TYPE_DELETE:
                err = yrmcds_remove(&conn->yrmcds, req->key.base, req->key.len, !conn->yrmcds.text_mode, NULL);
                discard_req(req);
                if (err != YRMCDS_OK)
                    goto Error;
                break;
            default:
                fprintf(stderr, "[lib/common/memcached.c] unknown type:%d\n", (int)req->type);
                err = YRMCDS_NOT_IMPLEMENTED;
                goto Error;
            }

            pthread_mutex_lock(&conn->ctx->mutex);
        }
        pthread_cond_wait(&conn->ctx->cond, &conn->ctx->mutex);
    }

    pthread_mutex_unlock(&conn->ctx->mutex);
    return NULL;

Error:
    fprintf(stderr, "[lib/common/memcached.c] failed to send request; %s\n", yrmcds_strerror(err));
    /* doc says the call can be used to interrupt yrmcds_recv */
    yrmcds_shutdown(&conn->yrmcds);

    return NULL;
}
Exemplo n.º 2
0
static void connect_to_server(h2o_memcached_context_t *ctx, yrmcds *yrmcds)
{
    size_t failcnt;
    yrmcds_error err;

    for (failcnt = 0; (err = yrmcds_connect(yrmcds, ctx->host, ctx->port)) != YRMCDS_OK; ++failcnt) {
        if (failcnt == 0) {
            fprintf(stderr, "[lib/common/memcached.c] failed to connect to memcached at %s:%" PRIu16 ", %s\n", ctx->host, ctx->port,
                    yrmcds_strerror(err));
        }
        ++failcnt;
        usleep(2000000 + rand() % 3000000); /* sleep 2 to 5 seconds */
    }
    /* connected */
    fprintf(stderr, "[lib/common/memcached.c] connected to memcached at %s:%" PRIu16 "\n", ctx->host, ctx->port);
}
Exemplo n.º 3
0
static void reader_main(h2o_memcached_context_t *ctx)
{
    struct st_h2o_memcached_conn_t conn = {ctx, {}, PTHREAD_MUTEX_INITIALIZER, {&conn.inflight, &conn.inflight}, 0};
    pthread_t writer_thread;
    yrmcds_response resp;
    yrmcds_error err;

    /* connect to server and start the writer thread */
    connect_to_server(conn.ctx, &conn.yrmcds);
    pthread_create(&writer_thread, NULL, writer_main, &conn);

    pthread_mutex_lock(&conn.ctx->mutex);
    ++conn.ctx->num_threads_connected;
    pthread_mutex_unlock(&conn.ctx->mutex);

    /* receive data until an error occurs */
    while (1) {
        if ((err = yrmcds_recv(&conn.yrmcds, &resp)) != YRMCDS_OK) {
            fprintf(stderr, "[lib/common/memcached.c] yrmcds_recv:%s\n", yrmcds_strerror(err));
            break;
        }
        h2o_memcached_req_t *req = pop_inflight(&conn, resp.serial);
        if (req == NULL) {
            fprintf(stderr, "[lib/common/memcached.c] received unexpected serial\n");
            break;
        }
        if (resp.status == YRMCDS_STATUS_OK) {
            req->data.get.value = h2o_iovec_init(h2o_mem_alloc(resp.data_len), resp.data_len);
            memcpy(req->data.get.value.base, resp.data, resp.data_len);
            h2o_mem_set_secure((void *)resp.data, 0, resp.data_len);
        }
        h2o_multithread_send_message(req->data.get.receiver, &req->data.get.message);
    }

    /* send error to all the reqs in-flight */
    pthread_mutex_lock(&conn.mutex);
    while (!h2o_linklist_is_empty(&conn.inflight)) {
        h2o_memcached_req_t *req = H2O_STRUCT_FROM_MEMBER(h2o_memcached_req_t, inflight, conn.inflight.next);
        h2o_linklist_unlink(&req->inflight);
        assert(req->type == REQ_TYPE_GET);
        h2o_multithread_send_message(req->data.get.receiver, &req->data.get.message);
    }
    pthread_mutex_unlock(&conn.mutex);

    /* stop the writer thread */
    __sync_add_and_fetch(&conn.writer_exit_requested, 1);
    pthread_mutex_lock(&conn.ctx->mutex);
    pthread_cond_broadcast(&conn.ctx->cond);
    pthread_mutex_unlock(&conn.ctx->mutex);
    pthread_join(writer_thread, NULL);

    /* decrement num_threads_connected, and discard all the pending requests if no connections are alive */
    pthread_mutex_lock(&conn.ctx->mutex);
    if (--conn.ctx->num_threads_connected == 0) {
        while (!h2o_linklist_is_empty(&conn.ctx->pending)) {
            h2o_memcached_req_t *req = H2O_STRUCT_FROM_MEMBER(h2o_memcached_req_t, pending, conn.ctx->pending.next);
            h2o_linklist_unlink(&req->pending);
            discard_req(req);
        }
    }
    pthread_mutex_unlock(&conn.ctx->mutex);

    /* close the connection */
    yrmcds_close(&conn.yrmcds);
}