/* not every context has srv ready, extract from context instead */ static void mc_ctx_release(liServer *_srv, gpointer param) { memcached_ctx *ctx = param; liServer *srv; guint i; UNUSED(_srv); if (NULL == ctx) return; srv = ctx->srv; assert(g_atomic_int_get(&ctx->refcount) > 0); if (!g_atomic_int_dec_and_test(&ctx->refcount)) return; if (ctx->worker_client_ctx) { for (i = 0; i < srv->worker_count; i++) { li_memcached_con_release(ctx->worker_client_ctx[i]); } g_slice_free1(sizeof(liMemcachedCon*) * srv->worker_count, ctx->worker_client_ctx); } li_sockaddr_clear(&ctx->addr); li_pattern_free(ctx->pattern); li_action_release(srv, ctx->act_found); li_action_release(srv, ctx->act_miss); if (ctx->mconf_link.data) { /* still in LI_SERVER_INIT */ memcached_config *mconf = ctx->p->data; g_queue_unlink(&mconf->prepare_ctx, &ctx->mconf_link); ctx->mconf_link.data = NULL; } ctx->srv = NULL; g_slice_free(memcached_ctx, ctx); }
static void free_request(liMemcachedCon *con, int_request *req) { if (!req) return; li_memcached_con_release(con); if (NULL != req->iter.data) { req->iter.data = NULL; g_queue_unlink(&con->req_queue, &req->iter); } switch (req->type) { case REQ_GET: break; case REQ_SET: li_buffer_release(req->data); req->data = NULL; break; } g_string_free(req->key, TRUE); req->key = NULL; g_slice_free(int_request, req); }
static void memcached_io_cb(liEventBase *watcher, int events) { liMemcachedCon *con = LI_CONTAINER_OF(li_event_io_from(watcher), liMemcachedCon, con_watcher); if (1 == g_atomic_int_get(&con->refcount) && li_event_active(&con->con_watcher)) { memcached_stop_io(con); return; } if (-1 == con->fd) { memcached_connect(con); return; } li_memcached_con_acquire(con); /* make sure con isn't freed in the middle of something */ if (events & LI_EV_WRITE) { int i; ssize_t written, len; gchar *data; send_item *si; si = g_queue_peek_head(&con->out); for (i = 0; si && (i < 10); i++) { /* don't send more than 10 chunks */ data = si->buf->addr + si->pos; len = si->len; written = write(li_event_io_fd(&con->con_watcher), data, len); if (written < 0) { switch (errno) { case EINTR: continue; case EAGAIN: #if EWOULDBLOCK != EAGAIN case EWOULDBLOCK: #endif goto write_eagain; default: /* Fatal error, connection has to be closed */ g_clear_error(&con->err); g_set_error(&con->err, LI_MEMCACHED_ERROR, LI_MEMCACHED_CONNECTION, "Couldn't write socket '%s': %s", li_sockaddr_to_string(con->addr, con->tmpstr, TRUE)->str, g_strerror(errno)); close_con(con); goto out; } } else { si->pos += written; si->len -= written; if (0 == si->len) { send_queue_item_free(si); g_queue_pop_head(&con->out); si = g_queue_peek_head(&con->out); } } } write_eagain: send_queue_clean(&con->out); } if (events & LI_EV_READ) { do { handle_read(con); } while (con->remaining && con->remaining->used > 0); } out: memcached_update_io(con); li_memcached_con_release(con); }
static void memcached_stop_io(liMemcachedCon *con) { if (li_event_active(&con->con_watcher)) { li_event_stop(&con->con_watcher); li_memcached_con_release(con); } }
static void memcached_stop_io(liMemcachedCon *con) { if (((ev_watcher*) &con->con_watcher)->active) { li_ev_safe_ref_and_stop(ev_io_stop, con->loop, &con->con_watcher); li_memcached_con_release(con); } }