summaryrefslogtreecommitdiffstats
path: root/src/libutil/memcached.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/libutil/memcached.c')
-rw-r--r--src/libutil/memcached.c831
1 files changed, 0 insertions, 831 deletions
diff --git a/src/libutil/memcached.c b/src/libutil/memcached.c
deleted file mode 100644
index e4c9be9d2..000000000
--- a/src/libutil/memcached.c
+++ /dev/null
@@ -1,831 +0,0 @@
-/*
- * Copyright (c) 2009-2012, Vsevolod Stakhov
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY AUTHOR ''AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL AUTHOR BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifdef _THREAD_SAFE
-# include <pthread.h>
-#endif
-
-#include <stdarg.h>
-
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <sys/param.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sysexits.h>
-#include <unistd.h>
-#include <syslog.h>
-
-#include <netinet/in.h>
-#include <arpa/inet.h>
-#include <sys/socket.h>
-#include <sys/poll.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <sys/uio.h>
-#include <event.h>
-#include <glib.h>
-
-#include "memcached.h"
-
-#define CRLF "\r\n"
-#define END_TRAILER "END" CRLF
-#define STORED_TRAILER "STORED" CRLF
-#define NOT_STORED_TRAILER "NOT STORED" CRLF
-#define EXISTS_TRAILER "EXISTS" CRLF
-#define DELETED_TRAILER "DELETED" CRLF
-#define NOT_FOUND_TRAILER "NOT_FOUND" CRLF
-#define CLIENT_ERROR_TRAILER "CLIENT_ERROR"
-#define SERVER_ERROR_TRAILER "SERVER_ERROR"
-
-#define READ_BUFSIZ 1500
-#define MAX_RETRIES 3
-
-/* Header for udp protocol */
-struct memc_udp_header {
- guint16 req_id;
- guint16 seq_num;
- guint16 dg_sent;
- guint16 unused;
-};
-
-static void socket_callback (gint fd, short what, void *arg);
-static gint memc_parse_header (gchar *buf, size_t * len, gchar **end);
-
-/*
- * Write to syslog if OPT_DEBUG is specified
- */
-static void
-memc_log (const memcached_ctx_t * ctx, gint line, const gchar *fmt, ...)
-{
- va_list args;
- if (ctx->options & MEMC_OPT_DEBUG) {
- va_start (args, fmt);
- g_log (G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "memc_debug(%d): host: %s, port: %d", line, inet_ntoa (ctx->addr), ntohs (ctx->port));
- g_logv (G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, fmt, args);
- va_end (args);
- }
-}
-
-/*
- * Callback for write command
- */
-static void
-write_handler (gint fd, short what, memcached_ctx_t * ctx)
-{
- gchar read_buf[READ_BUFSIZ];
- gint retries;
- ssize_t r;
- struct memc_udp_header header;
- struct iovec iov[4];
-
- /* Write something to memcached */
- if (what == EV_WRITE) {
- if (ctx->protocol == UDP_TEXT) {
- /* Send udp header */
- bzero (&header, sizeof (header));
- header.dg_sent = htons (1);
- header.req_id = ctx->count;
- }
-
- r = snprintf (read_buf, READ_BUFSIZ, "%s %s 0 %d %zu" CRLF, ctx->cmd, ctx->param->key, ctx->param->expire, ctx->param->bufsize);
- memc_log (ctx, __LINE__, "memc_write: send write request to memcached: %s", read_buf);
-
- if (ctx->protocol == UDP_TEXT) {
- iov[0].iov_base = &header;
- iov[0].iov_len = sizeof (struct memc_udp_header);
- if (ctx->param->bufpos == 0) {
- iov[1].iov_base = read_buf;
- iov[1].iov_len = r;
- }
- else {
- iov[1].iov_base = NULL;
- iov[1].iov_len = 0;
- }
- iov[2].iov_base = ctx->param->buf + ctx->param->bufpos;
- iov[2].iov_len = ctx->param->bufsize - ctx->param->bufpos;
- iov[3].iov_base = CRLF;
- iov[3].iov_len = sizeof (CRLF) - 1;
- if (writev (ctx->sock, iov, 4) == -1) {
- memc_log (ctx, __LINE__, "memc_write: writev failed: %s", strerror (errno));
- }
- }
- else {
- iov[0].iov_base = read_buf;
- iov[0].iov_len = r;
- iov[1].iov_base = ctx->param->buf + ctx->param->bufpos;
- iov[1].iov_len = ctx->param->bufsize - ctx->param->bufpos;
- iov[2].iov_base = CRLF;
- iov[2].iov_len = sizeof (CRLF) - 1;
- if (writev (ctx->sock, iov, 3) == -1) {
- memc_log (ctx, __LINE__, "memc_write: writev failed: %s", strerror (errno));
- }
- }
- event_del (&ctx->mem_ev);
- event_set (&ctx->mem_ev, ctx->sock, EV_READ | EV_PERSIST | EV_TIMEOUT, socket_callback, (void *)ctx);
- event_add (&ctx->mem_ev, &ctx->timeout);
- }
- else if (what == EV_READ) {
- /* Read header */
- retries = 0;
- while (ctx->protocol == UDP_TEXT) {
- iov[0].iov_base = &header;
- iov[0].iov_len = sizeof (struct memc_udp_header);
- iov[1].iov_base = read_buf;
- iov[1].iov_len = READ_BUFSIZ;
- if ((r = readv (ctx->sock, iov, 2)) == -1) {
- event_del (&ctx->mem_ev);
- ctx->callback (ctx, SERVER_ERROR, ctx->callback_data);
- }
- if (header.req_id != ctx->count && retries < MAX_RETRIES) {
- retries++;
- /* Not our reply packet */
- continue;
- }
- break;
- }
- if (ctx->protocol != UDP_TEXT) {
- r = read (ctx->sock, read_buf, READ_BUFSIZ - 1);
- }
- memc_log (ctx, __LINE__, "memc_write: read reply from memcached: %s", read_buf);
- /* Increment count */
- ctx->count++;
- event_del (&ctx->mem_ev);
- if (strncmp (read_buf, STORED_TRAILER, sizeof (STORED_TRAILER) - 1) == 0) {
- ctx->callback (ctx, OK, ctx->callback_data);
- }
- else if (strncmp (read_buf, NOT_STORED_TRAILER, sizeof (NOT_STORED_TRAILER) - 1) == 0) {
- ctx->callback (ctx, CLIENT_ERROR, ctx->callback_data);
- }
- else if (strncmp (read_buf, EXISTS_TRAILER, sizeof (EXISTS_TRAILER) - 1) == 0) {
- ctx->callback (ctx, EXISTS, ctx->callback_data);
- }
- else {
- ctx->callback (ctx, SERVER_ERROR, ctx->callback_data);
- }
- }
- else if (what == EV_TIMEOUT) {
- event_del (&ctx->mem_ev);
- ctx->callback (ctx, SERVER_TIMEOUT, ctx->callback_data);
- }
-}
-
-/*
- * Callback for read command
- */
-static void
-read_handler (gint fd, short what, memcached_ctx_t * ctx)
-{
- gchar read_buf[READ_BUFSIZ];
- gchar *p;
- ssize_t r;
- size_t datalen;
- struct memc_udp_header header;
- struct iovec iov[2];
- gint retries = 0, t;
-
- if (what == EV_WRITE) {
- /* Send command to memcached */
- if (ctx->protocol == UDP_TEXT) {
- /* Send udp header */
- bzero (&header, sizeof (header));
- header.dg_sent = htons (1);
- header.req_id = ctx->count;
- }
-
- r = snprintf (read_buf, READ_BUFSIZ, "%s %s" CRLF, ctx->cmd, ctx->param->key);
- memc_log (ctx, __LINE__, "memc_read: send read request to memcached: %s", read_buf);
- if (ctx->protocol == UDP_TEXT) {
- iov[0].iov_base = &header;
- iov[0].iov_len = sizeof (struct memc_udp_header);
- iov[1].iov_base = read_buf;
- iov[1].iov_len = r;
- if (writev (ctx->sock, iov, 2) == -1) {
- memc_log (ctx, __LINE__, "memc_write: writev failed: %s", strerror (errno));
- }
- }
- else {
- if (write (ctx->sock, read_buf, r) == -1) {
- memc_log (ctx, __LINE__, "memc_write: write failed: %s", strerror (errno));
- }
- }
- event_del (&ctx->mem_ev);
- event_set (&ctx->mem_ev, ctx->sock, EV_READ | EV_PERSIST | EV_TIMEOUT, socket_callback, (void *)ctx);
- event_add (&ctx->mem_ev, &ctx->timeout);
- }
- else if (what == EV_READ) {
- while (ctx->protocol == UDP_TEXT) {
- iov[0].iov_base = &header;
- iov[0].iov_len = sizeof (struct memc_udp_header);
- iov[1].iov_base = read_buf;
- iov[1].iov_len = READ_BUFSIZ;
- if ((r = readv (ctx->sock, iov, 2)) == -1) {
- event_del (&ctx->mem_ev);
- ctx->callback (ctx, SERVER_ERROR, ctx->callback_data);
- return;
- }
- memc_log (ctx, __LINE__, "memc_read: got read_buf: %s", read_buf);
- if (header.req_id != ctx->count && retries < MAX_RETRIES) {
- memc_log (ctx, __LINE__, "memc_read: got wrong packet id: %d, %d was awaited", header.req_id, ctx->count);
- retries++;
- /* Not our reply packet */
- continue;
- }
- break;
- }
- if (ctx->protocol != UDP_TEXT) {
- r = read (ctx->sock, read_buf, READ_BUFSIZ - 1);
- }
-
- if (r > 0) {
- read_buf[r] = 0;
- if (ctx->param->bufpos == 0) {
- t = memc_parse_header (read_buf, &datalen, &p);
- if (t < 0) {
- event_del (&ctx->mem_ev);
- memc_log (ctx, __LINE__, "memc_read: cannot parse memcached reply");
- ctx->callback (ctx, SERVER_ERROR, ctx->callback_data);
- return;
- }
- else if (t == 0) {
- memc_log (ctx, __LINE__, "memc_read: record does not exists");
- event_del (&ctx->mem_ev);
- ctx->callback (ctx, NOT_EXISTS, ctx->callback_data);
- return;
- }
-
- if (datalen > ctx->param->bufsize) {
- memc_log (ctx, __LINE__, "memc_read: user's buffer is too small: %zd, %zd required", ctx->param->bufsize, datalen);
- event_del (&ctx->mem_ev);
- ctx->callback (ctx, WRONG_LENGTH, ctx->callback_data);
- return;
- }
- /* Check if we already have all data in buffer */
- if (r >= (ssize_t)(datalen + sizeof (END_TRAILER) + sizeof (CRLF) - 2)) {
- /* Store all data in param's buffer */
- memcpy (ctx->param->buf + ctx->param->bufpos, p, datalen);
- /* Increment count */
- ctx->count++;
- event_del (&ctx->mem_ev);
- ctx->callback (ctx, OK, ctx->callback_data);
- return;
- }
- /* Subtract from sum parsed header's length */
- r -= p - read_buf;
- }
- else {
- p = read_buf;
- }
-
- if (strncmp (ctx->param->buf + ctx->param->bufpos + r - sizeof (END_TRAILER) - sizeof (CRLF) + 2, END_TRAILER, sizeof (END_TRAILER) - 1) == 0) {
- r -= sizeof (END_TRAILER) - sizeof (CRLF) - 2;
- memcpy (ctx->param->buf + ctx->param->bufpos, p, r);
- event_del (&ctx->mem_ev);
- ctx->callback (ctx, OK, ctx->callback_data);
- return;
- }
- /* Store this part of data in param's buffer */
- memcpy (ctx->param->buf + ctx->param->bufpos, p, r);
- ctx->param->bufpos += r;
- }
- else {
- memc_log (ctx, __LINE__, "memc_read: read(v) failed: %d, %s", r, strerror (errno));
- event_del (&ctx->mem_ev);
- ctx->callback (ctx, SERVER_ERROR, ctx->callback_data);
- return;
- }
-
- ctx->count++;
- }
- else if (what == EV_TIMEOUT) {
- event_del (&ctx->mem_ev);
- ctx->callback (ctx, SERVER_TIMEOUT, ctx->callback_data);
- }
-
-}
-
-/*
- * Callback for delete command
- */
-static void
-delete_handler (gint fd, short what, memcached_ctx_t * ctx)
-{
- gchar read_buf[READ_BUFSIZ];
- gint retries;
- ssize_t r;
- struct memc_udp_header header;
- struct iovec iov[2];
-
- /* Write something to memcached */
- if (what == EV_WRITE) {
- if (ctx->protocol == UDP_TEXT) {
- /* Send udp header */
- bzero (&header, sizeof (header));
- header.dg_sent = htons (1);
- header.req_id = ctx->count;
- }
- r = snprintf (read_buf, READ_BUFSIZ, "delete %s" CRLF, ctx->param->key);
- memc_log (ctx, __LINE__, "memc_delete: send delete request to memcached: %s", read_buf);
-
- if (ctx->protocol == UDP_TEXT) {
- iov[0].iov_base = &header;
- iov[0].iov_len = sizeof (struct memc_udp_header);
- iov[1].iov_base = read_buf;
- iov[1].iov_len = r;
- ctx->param->bufpos = writev (ctx->sock, iov, 2);
- if (ctx->param->bufpos == (size_t)-1) {
- memc_log (ctx, __LINE__, "memc_write: writev failed: %s", strerror (errno));
- }
- }
- else {
- if (write (ctx->sock, read_buf, r) == -1) {
- memc_log (ctx, __LINE__, "memc_write: write failed: %s", strerror (errno));
- }
- }
- event_del (&ctx->mem_ev);
- event_set (&ctx->mem_ev, ctx->sock, EV_READ | EV_PERSIST | EV_TIMEOUT, socket_callback, (void *)ctx);
- event_add (&ctx->mem_ev, &ctx->timeout);
- }
- else if (what == EV_READ) {
- /* Read header */
- retries = 0;
- while (ctx->protocol == UDP_TEXT) {
- iov[0].iov_base = &header;
- iov[0].iov_len = sizeof (struct memc_udp_header);
- iov[1].iov_base = read_buf;
- iov[1].iov_len = READ_BUFSIZ;
- if ((r = readv (ctx->sock, iov, 2)) == -1) {
- event_del (&ctx->mem_ev);
- ctx->callback (ctx, SERVER_ERROR, ctx->callback_data);
- return;
- }
- if (header.req_id != ctx->count && retries < MAX_RETRIES) {
- retries++;
- /* Not our reply packet */
- continue;
- }
- break;
- }
- if (ctx->protocol != UDP_TEXT) {
- r = read (ctx->sock, read_buf, READ_BUFSIZ - 1);
- }
- /* Increment count */
- ctx->count++;
- event_del (&ctx->mem_ev);
- if (strncmp (read_buf, DELETED_TRAILER, sizeof (STORED_TRAILER) - 1) == 0) {
- ctx->callback (ctx, OK, ctx->callback_data);
- }
- else if (strncmp (read_buf, NOT_FOUND_TRAILER, sizeof (NOT_FOUND_TRAILER) - 1) == 0) {
- ctx->callback (ctx, NOT_EXISTS, ctx->callback_data);
- }
- else {
- ctx->callback (ctx, SERVER_ERROR, ctx->callback_data);
- }
- }
- else if (what == EV_TIMEOUT) {
- event_del (&ctx->mem_ev);
- ctx->callback (ctx, SERVER_TIMEOUT, ctx->callback_data);
- }
-}
-
-/*
- * Callback for our socket events
- */
-static void
-socket_callback (gint fd, short what, void *arg)
-{
- memcached_ctx_t *ctx = (memcached_ctx_t *) arg;
-
- switch (ctx->op) {
- case CMD_NULL:
- /* Do nothing here */
- break;
- case CMD_CONNECT:
- /* We have write readiness after connect call, so reinit event */
- ctx->cmd = "connect";
- if (what == EV_WRITE) {
- event_del (&ctx->mem_ev);
- event_set (&ctx->mem_ev, ctx->sock, EV_READ | EV_PERSIST | EV_TIMEOUT, socket_callback, (void *)ctx);
- event_add (&ctx->mem_ev, NULL);
- ctx->callback (ctx, OK, ctx->callback_data);
- ctx->alive = 1;
- }
- else {
- ctx->callback (ctx, SERVER_TIMEOUT, ctx->callback_data);
- ctx->alive = 0;
- }
- break;
- case CMD_WRITE:
- write_handler (fd, what, ctx);
- break;
- case CMD_READ:
- read_handler (fd, what, ctx);
- break;
- case CMD_DELETE:
- delete_handler (fd, what, ctx);
- break;
- }
-}
-
-/*
- * Common callback function for memcached operations if no user's callback is specified
- */
-static void
-common_memc_callback (memcached_ctx_t * ctx, memc_error_t error, void *data)
-{
- memc_log (ctx, __LINE__, "common_memc_callback: result of memc command '%s' is '%s'", ctx->cmd, memc_strerror (error));
-}
-
-/*
- * Make socket for udp connection
- */
-static gint
-memc_make_udp_sock (memcached_ctx_t * ctx)
-{
- struct sockaddr_in sc;
- gint ofl;
-
- bzero (&sc, sizeof (struct sockaddr_in *));
- sc.sin_family = AF_INET;
- sc.sin_port = ctx->port;
- memcpy (&sc.sin_addr, &ctx->addr, sizeof (struct in_addr));
-
- ctx->sock = socket (PF_INET, SOCK_DGRAM, 0);
-
- if (ctx->sock == -1) {
- memc_log (ctx, __LINE__, "memc_make_udp_sock: socket() failed: %s", strerror (errno));
- return -1;
- }
-
- /* set nonblocking */
- ofl = fcntl (ctx->sock, F_GETFL, 0);
- fcntl (ctx->sock, F_SETFL, ofl | O_NONBLOCK);
-
- /*
- * Call connect to set default destination for datagrams
- * May not block
- */
- ctx->op = CMD_CONNECT;
- event_set (&ctx->mem_ev, ctx->sock, EV_WRITE | EV_TIMEOUT, socket_callback, (void *)ctx);
- event_add (&ctx->mem_ev, NULL);
- return connect (ctx->sock, (struct sockaddr *)&sc, sizeof (struct sockaddr_in));
-}
-
-/*
- * Make socket for tcp connection
- */
-static gint
-memc_make_tcp_sock (memcached_ctx_t * ctx)
-{
- struct sockaddr_in sc;
- gint ofl, r;
-
- bzero (&sc, sizeof (struct sockaddr_in *));
- sc.sin_family = AF_INET;
- sc.sin_port = ctx->port;
- memcpy (&sc.sin_addr, &ctx->addr, sizeof (struct in_addr));
-
- ctx->sock = socket (PF_INET, SOCK_STREAM, 0);
-
- if (ctx->sock == -1) {
- memc_log (ctx, __LINE__, "memc_make_tcp_sock: socket() failed: %s", strerror (errno));
- return -1;
- }
-
- /* set nonblocking */
- ofl = fcntl (ctx->sock, F_GETFL, 0);
- fcntl (ctx->sock, F_SETFL, ofl | O_NONBLOCK);
-
- if ((r = connect (ctx->sock, (struct sockaddr *)&sc, sizeof (struct sockaddr_in))) == -1) {
- if (errno != EINPROGRESS) {
- close (ctx->sock);
- ctx->sock = -1;
- memc_log (ctx, __LINE__, "memc_make_tcp_sock: connect() failed: %s", strerror (errno));
- return -1;
- }
- }
- ctx->op = CMD_CONNECT;
- event_set (&ctx->mem_ev, ctx->sock, EV_WRITE | EV_TIMEOUT, socket_callback, (void *)ctx);
- event_add (&ctx->mem_ev, &ctx->timeout);
- return 0;
-}
-
-/*
- * Parse VALUE reply from server and set len argument to value returned by memcached
- */
-static gint
-memc_parse_header (gchar *buf, size_t * len, gchar **end)
-{
- gchar *p, *c;
- gint i;
-
- /* VALUE <key> <flags> <bytes> [<cas unique>]\r\n */
- c = strstr (buf, CRLF);
- if (c == NULL) {
- return -1;
- }
- *end = c + sizeof (CRLF) - 1;
-
- if (strncmp (buf, "VALUE ", sizeof ("VALUE ") - 1) == 0) {
- p = buf + sizeof ("VALUE ") - 1;
-
- /* Read bytes value and ignore all other fields, such as flags and key */
- for (i = 0; i < 2; i++) {
- while (p++ < c && *p != ' ');
-
- if (p > c) {
- return -1;
- }
- }
- *len = strtoul (p, &c, 10);
- return 1;
- }
- /* If value not found memcached return just END\r\n , in this case return 0 */
- else if (strncmp (buf, END_TRAILER, sizeof (END_TRAILER) - 1) == 0) {
- return 0;
- }
-
- return -1;
-}
-
-
-/*
- * Common read command handler for memcached
- */
-memc_error_t
-memc_read (memcached_ctx_t * ctx, const gchar *cmd, memcached_param_t * param)
-{
- ctx->cmd = cmd;
- ctx->op = CMD_READ;
- ctx->param = param;
- event_set (&ctx->mem_ev, ctx->sock, EV_WRITE | EV_TIMEOUT, socket_callback, (void *)ctx);
- event_add (&ctx->mem_ev, &ctx->timeout);
-
- return OK;
-}
-
-/*
- * Common write command handler for memcached
- */
-memc_error_t
-memc_write (memcached_ctx_t * ctx, const gchar *cmd, memcached_param_t * param, gint expire)
-{
- ctx->cmd = cmd;
- ctx->op = CMD_WRITE;
- ctx->param = param;
- param->expire = expire;
- event_set (&ctx->mem_ev, ctx->sock, EV_WRITE | EV_TIMEOUT, socket_callback, (void *)ctx);
- event_add (&ctx->mem_ev, &ctx->timeout);
-
- return OK;
-}
-
-/*
- * Delete command handler
- */
-memc_error_t
-memc_delete (memcached_ctx_t * ctx, memcached_param_t * param)
-{
- ctx->cmd = "delete";
- ctx->op = CMD_DELETE;
- ctx->param = param;
- event_set (&ctx->mem_ev, ctx->sock, EV_WRITE | EV_TIMEOUT, socket_callback, (void *)ctx);
- event_add (&ctx->mem_ev, &ctx->timeout);
-
- return OK;
-}
-
-/*
- * Write handler for memcached mirroring
- * writing is done to each memcached server
- */
-memc_error_t
-memc_write_mirror (memcached_ctx_t * ctx, size_t memcached_num, const gchar *cmd, memcached_param_t * param, gint expire)
-{
- memc_error_t r, result = OK;
-
- while (memcached_num--) {
- if (ctx[memcached_num].alive == 1) {
- r = memc_write (&ctx[memcached_num], cmd, param, expire);
- if (r != OK) {
- memc_log (&ctx[memcached_num], __LINE__, "memc_write_mirror: cannot write to mirror server: %s", memc_strerror (r));
- result = r;
- ctx[memcached_num].alive = 0;
- }
- }
- }
-
- return result;
-}
-
-/*
- * Read handler for memcached mirroring
- * reading is done from first active memcached server
- */
-memc_error_t
-memc_read_mirror (memcached_ctx_t * ctx, size_t memcached_num, const gchar *cmd, memcached_param_t * param)
-{
- memc_error_t r, result = OK;
-
- while (memcached_num--) {
- if (ctx[memcached_num].alive == 1) {
- r = memc_read (&ctx[memcached_num], cmd, param);
- if (r != OK) {
- result = r;
- if (r != NOT_EXISTS) {
- ctx[memcached_num].alive = 0;
- memc_log (&ctx[memcached_num], __LINE__, "memc_read_mirror: cannot write read from mirror server: %s", memc_strerror (r));
- }
- else {
- memc_log (&ctx[memcached_num], __LINE__, "memc_read_mirror: record not exists", memc_strerror (r));
- }
- }
- else {
- break;
- }
- }
- }
-
- return result;
-}
-
-/*
- * Delete handler for memcached mirroring
- * deleting is done for each active memcached server
- */
-memc_error_t
-memc_delete_mirror (memcached_ctx_t * ctx, size_t memcached_num, const gchar *cmd, memcached_param_t * param)
-{
- memc_error_t r, result = OK;
-
- while (memcached_num--) {
- if (ctx[memcached_num].alive == 1) {
- r = memc_delete (&ctx[memcached_num], param);
- if (r != OK) {
- result = r;
- if (r != NOT_EXISTS) {
- ctx[memcached_num].alive = 0;
- memc_log (&ctx[memcached_num], __LINE__, "memc_delete_mirror: cannot delete from mirror server: %s", memc_strerror (r));
- }
- }
- }
- }
-
- return result;
-}
-
-
-/*
- * Initialize memcached context for specified protocol
- */
-gint
-memc_init_ctx (memcached_ctx_t * ctx)
-{
- if (ctx == NULL) {
- return -1;
- }
-
- ctx->count = 0;
- ctx->alive = 0;
- ctx->op = CMD_NULL;
- /* Set default callback */
- if (ctx->callback == NULL) {
- ctx->callback = common_memc_callback;
- }
-
- switch (ctx->protocol) {
- case UDP_TEXT:
- return memc_make_udp_sock (ctx);
- break;
- case TCP_TEXT:
- return memc_make_tcp_sock (ctx);
- break;
- /* Not implemented */
- case UDP_BIN:
- case TCP_BIN:
- default:
- return -1;
- }
-}
-
-/*
- * Mirror init
- */
-gint
-memc_init_ctx_mirror (memcached_ctx_t * ctx, size_t memcached_num)
-{
- gint r, result = -1;
- while (memcached_num--) {
- if (ctx[memcached_num].alive == 1) {
- r = memc_init_ctx (&ctx[memcached_num]);
- if (r == -1) {
- ctx[memcached_num].alive = 0;
- memc_log (&ctx[memcached_num], __LINE__, "memc_init_ctx_mirror: cannot connect to server");
- }
- else {
- result = 1;
- }
- }
- }
-
- return result;
-}
-
-/*
- * Close context connection
- */
-gint
-memc_close_ctx (memcached_ctx_t * ctx)
-{
- if (ctx != NULL && ctx->sock != -1) {
- event_del (&ctx->mem_ev);
- return close (ctx->sock);
- }
-
- return -1;
-}
-
-/*
- * Mirror close
- */
-gint
-memc_close_ctx_mirror (memcached_ctx_t * ctx, size_t memcached_num)
-{
- gint r = 0;
- while (memcached_num--) {
- if (ctx[memcached_num].alive == 1) {
- r = memc_close_ctx (&ctx[memcached_num]);
- if (r == -1) {
- memc_log (&ctx[memcached_num], __LINE__, "memc_close_ctx_mirror: cannot close connection to server properly");
- ctx[memcached_num].alive = 0;
- }
- }
- }
-
- return r;
-}
-
-
-const gchar *
-memc_strerror (memc_error_t err)
-{
- const gchar *p;
-
- switch (err) {
- case OK:
- p = "Ok";
- break;
- case BAD_COMMAND:
- p = "Bad command";
- break;
- case CLIENT_ERROR:
- p = "Client error";
- break;
- case SERVER_ERROR:
- p = "Server error";
- break;
- case SERVER_TIMEOUT:
- p = "Server timeout";
- break;
- case NOT_EXISTS:
- p = "Key not found";
- break;
- case EXISTS:
- p = "Key already exists";
- break;
- case WRONG_LENGTH:
- p = "Wrong result length";
- break;
- default:
- p = "Unknown error";
- break;
- }
-
- return p;
-}
-
-/*
- * vi:ts=4
- */