/* Resource destructors. */ static void destruct_conn(php_yrmcds_t* c) { c->reference_count -= 1; if( c->pkey ) { uint32_t serial; yrmcds_set_timeout(&c->res, (int)YRMCDS_G(default_timeout)); int e = yrmcds_unlockall(&c->res, 0, &serial); if( e != YRMCDS_OK ) { on_broken_connection_detected(c, e, YRMCDS_STATUS_OK); return; } yrmcds_response r; do { e = yrmcds_recv(&c->res, &r); if( e != YRMCDS_OK ) { on_broken_connection_detected(c, e, YRMCDS_STATUS_OK); return; } } while( r.serial != serial ); if( r.status != YRMCDS_STATUS_OK && // memcached does not support locking, so r.status != YRMCDS_STATUS_UNKNOWNCOMMAND ) { on_broken_connection_detected(c, e, r.status); return; } return; } // Since `c` does not use persistent connection, // the resources of `c` is not shared with other clients. // Therefore, we can clean up resources here. yrmcds_close(&c->res); efree(c); }
static ZEND_RSRC_DTOR_FUNC(php_yrmcds_resource_pdtor) { if( res->ptr == NULL ) return; php_yrmcds_t* c = (php_yrmcds_t*)res->ptr; if( c->reference_count != 0 ) { char buf[256]; snprintf(buf, sizeof(buf), "yrmcds: non-zero reference_count on pdtor: %zu", c->reference_count); php_log_err(buf); } yrmcds_close(&c->res); pefree((void*)c->pkey, 1); pefree(c, 1); res->ptr = NULL; }
int main(int argc, char** argv) { const char* server = DEFAULT_SERVER; uint16_t port = DEFAULT_PORT; size_t compression = DEFAULT_COMPRESS; while( 1 ) { int n; int c = getopt(argc, argv, "s:p:c:dqvh"); if( c == -1 ) break; switch( c ) { case 's': server = optarg; break; case 'p': n = atoi(optarg); if( n <= 0 || n > 65535 ) { fprintf(stderr, "Invalid TCP port.\n"); return 1; } port = (uint16_t)n; break; case 'c': n = atoi(optarg); if( n <= 0 ) { fprintf(stderr, "Invalid compression thoreshold.\n"); return 1; } compression = (size_t)n; break; case 'd': debug = 1; break; case 'q': quiet = 1; break; case 'v': version(); return 0; case 'h': usage(); return 0; default: return 1; } } if( optind == argc ) { usage(); return 0; } const char* cmd = argv[optind]; argc -= optind + 1; argv += optind + 1; yrmcds s[1]; yrmcds_error e = yrmcds_connect(s, server, port); CHECK_ERROR(e); e = yrmcds_set_compression(s, compression); if( e != 0 && e != YRMCDS_NOT_IMPLEMENTED ) { yrmcds_close(s); CHECK_ERROR(e); } int ret = 1; #define do_cmd(name) \ if( strcmp(cmd, #name) == 0 ) { \ ret = cmd_##name(argc, argv, s); \ goto OUT; \ } do_cmd(noop); do_cmd(get); do_cmd(getk); do_cmd(gat); do_cmd(gatk); do_cmd(lag); do_cmd(lagk); do_cmd(touch); do_cmd(set); do_cmd(replace); do_cmd(add); do_cmd(rau); do_cmd(incr); do_cmd(decr); do_cmd(append); do_cmd(prepend); do_cmd(delete); do_cmd(lock); do_cmd(unlock); do_cmd(unlockall); do_cmd(flush); do_cmd(stat); do_cmd(keys); do_cmd(version); do_cmd(quit); fprintf(stderr, "No such command: %s\n", cmd); OUT: yrmcds_close(s); return ret; }
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); }