summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile.am18
-rw-r--r--assoc.c22
-rw-r--r--configure.ac22
-rw-r--r--items.c6
-rw-r--r--memcached.c76
-rw-r--r--memcached.h7
-rw-r--r--memcached_dtrace.d274
-rw-r--r--memcached_dtrace.h276
-rw-r--r--slabs.c58
-rw-r--r--thread.c7
10 files changed, 715 insertions, 51 deletions
diff --git a/Makefile.am b/Makefile.am
index 1b591d3..aecebc1 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -4,8 +4,22 @@ pkginclude_HEADERS = protocol_binary.h
memcached_SOURCES = memcached.c slabs.c slabs.h items.c items.h assoc.c assoc.h memcached.h thread.c stats.c stats.h
memcached_debug_SOURCES = $(memcached_SOURCES)
memcached_CPPFLAGS = -DNDEBUG
-memcached_LDADD = @LIBOBJS@
-memcached_debug_LDADD = $(memcached_LDADD)
+memcached_LDADD = @DTRACE_OBJ@ @DAEMON_OBJ@
+memcached_debug_LDADD = @DTRACE_DEBUG_OBJ@ @DAEMON_OBJ@
+memcached_DEPENDENCIES = @DTRACE_OBJ@ @DAEMON_OBJ@
+memcached_debug_DEPENDENCIES = @DTRACE_DEBUG_OBJ@ @DAEMON_OBJ@
+
+memcached_dtrace.h:
+ ${DTRACE} -h -s memcached_dtrace.d
+ sed -e s,_DTRACE_VERSION,ENABLE_DTRACE,g memcached_dtrace.h | \
+ tr '\t' ' ' | grep -v unistd.h > memcached_dtrace.tmp
+ mv memcached_dtrace.tmp memcached_dtrace.h
+
+memcached_dtrace.o: $(memcached_OBJECTS)
+ $(DTRACE) $(DTRACEFLAGS) -G -o memcached_dtrace.o -s ${srcdir}/memcached_dtrace.d $(memcached_OBJECTS)
+
+memcached_debug_dtrace.o: $(memcached_debug_OBJECTS)
+ $(DTRACE) $(DTRACEFLAGS) -G -o memcached_debug_dtrace.o -s ${srcdir}/memcached_dtrace.d $(memcached_debug_OBJECTS)
SUBDIRS = doc
DIST_DIRS = scripts
diff --git a/assoc.c b/assoc.c
index 5170a8a..09d1201 100644
--- a/assoc.c
+++ b/assoc.c
@@ -496,14 +496,18 @@ item *assoc_find(const char *key, const size_t nkey) {
it = primary_hashtable[hv & hashmask(hashpower)];
}
+ item *ret = NULL;
+ int depth = 0;
while (it) {
- if ((nkey == it->nkey) &&
- (memcmp(key, ITEM_key(it), nkey) == 0)) {
- return it;
+ if ((nkey == it->nkey) && (memcmp(key, ITEM_key(it), nkey) == 0)) {
+ ret = it;
+ break;
}
it = it->h_next;
+ ++depth;
}
- return 0;
+ MEMCACHED_ASSOC_FIND(key, depth);
+ return ret;
}
/* returns the address of the item pointer before the key. if *item == 0,
@@ -595,6 +599,7 @@ int assoc_insert(item *it) {
assoc_expand();
}
+ MEMCACHED_ASSOC_INSERT(ITEM_key(it), hash_items);
return 1;
}
@@ -602,10 +607,15 @@ void assoc_delete(const char *key, const size_t nkey) {
item **before = _hashitem_before(key, nkey);
if (*before) {
- item *nxt = (*before)->h_next;
+ item *nxt;
+ hash_items--;
+ /* The DTrace probe cannot be triggered as the last instruction
+ * due to possible tail-optimization by the compiler
+ */
+ MEMCACHED_ASSOC_DELETE(key, hash_items);
+ nxt = (*before)->h_next;
(*before)->h_next = 0; /* probably pointless, but whatever. */
*before = nxt;
- hash_items--;
return;
}
/* Note: we never actually get here. the callers don't delete things
diff --git a/configure.ac b/configure.ac
index 5c7ae82..28f84cf 100644
--- a/configure.ac
+++ b/configure.ac
@@ -9,6 +9,25 @@ AC_PROG_CC
AM_PROG_CC_C_O
AC_PROG_INSTALL
+AC_ARG_ENABLE(dtrace,
+ [AS_HELP_STRING([--enable-dtrace],[Enable dtrace probes])])
+if test "x$enable_dtrace" == "xyes"; then
+ AC_PATH_PROG([DTRACE], [dtrace], "no", [/usr/sbin:$PATH])
+ if test "x$DTRACE" != "xno"; then
+ AC_DEFINE([ENABLE_DTRACE],1,[Set to nonzero if you want to include DTRACE])
+ DTRACE_OBJ=memcached_dtrace.o
+ DTRACE_DEBUG_OBJ=memcached_debug_dtrace.o
+ else
+ AC_MSG_ERROR([Need dtrace binary and OS support.])
+ fi
+else
+ AC_DEFINE([ENABLE_DTRACE],0,[Set to nonzero if you want to include DTRACE])
+fi
+AC_SUBST(DTRACE)
+AC_SUBST(DTRACE_OBJ)
+AC_SUBST(DTRACE_DEBUG_OBJ)
+AC_SUBST(DTRACEFLAGS)
+
AC_ARG_ENABLE(64bit,
[AS_HELP_STRING([--enable-64bit],[build 64bit verison])])
if test "x$enable_64bit" == "xyes"
@@ -113,7 +132,8 @@ AC_SEARCH_LIBS(socket, socket)
AC_SEARCH_LIBS(gethostbyname, nsl)
AC_SEARCH_LIBS(mallinfo, malloc)
-AC_CHECK_FUNC(daemon,AC_DEFINE([HAVE_DAEMON],,[Define this if you have daemon()]),[AC_LIBOBJ(daemon)])
+AC_CHECK_FUNC(daemon,AC_DEFINE([HAVE_DAEMON],,[Define this if you have daemon()]),[DAEMON_OBJ=daemon.o])
+AC_SUBST(DAEMON_OBJ)
AC_HEADER_STDBOOL
AC_C_CONST
diff --git a/items.c b/items.c
index 72c7a19..2543a2c 100644
--- a/items.c
+++ b/items.c
@@ -228,6 +228,7 @@ static void item_unlink_q(item *it) {
}
int do_item_link(item *it) {
+ MEMCACHED_ITEM_LINK(ITEM_key(it), it->nbytes);
assert((it->it_flags & (ITEM_LINKED|ITEM_SLABBED)) == 0);
assert(it->nbytes < (1024 * 1024)); /* 1MB max size */
it->it_flags |= ITEM_LINKED;
@@ -249,6 +250,7 @@ int do_item_link(item *it) {
}
void do_item_unlink(item *it) {
+ MEMCACHED_ITEM_UNLINK(ITEM_key(it), it->nbytes);
if ((it->it_flags & ITEM_LINKED) != 0) {
it->it_flags &= ~ITEM_LINKED;
STATS_LOCK();
@@ -262,6 +264,7 @@ void do_item_unlink(item *it) {
}
void do_item_remove(item *it) {
+ MEMCACHED_ITEM_REMOVE(ITEM_key(it), it->nbytes);
assert((it->it_flags & ITEM_SLABBED) == 0);
if (it->refcount != 0) {
it->refcount--;
@@ -274,6 +277,7 @@ void do_item_remove(item *it) {
}
void do_item_update(item *it) {
+ MEMCACHED_ITEM_UPDATE(ITEM_key(it), it->nbytes);
if (it->time < current_time - ITEM_UPDATE_INTERVAL) {
assert((it->it_flags & ITEM_SLABBED) == 0);
@@ -286,6 +290,8 @@ void do_item_update(item *it) {
}
int do_item_replace(item *it, item *new_it) {
+ MEMCACHED_ITEM_REPLACE(ITEM_key(it), it->nbytes,
+ ITEM_key(new_it), new_it->nbytes);
assert((it->it_flags & ITEM_SLABBED) == 0);
do_item_unlink(it);
diff --git a/memcached.c b/memcached.c
index 82f3720..489c2d9 100644
--- a/memcached.c
+++ b/memcached.c
@@ -317,6 +317,8 @@ conn *conn_new(const int sfd, enum conn_states init_state,
fprintf(stderr, "calloc()\n");
return NULL;
}
+ MEMCACHED_CONN_CREATE(c);
+
c->rbuf = c->wbuf = 0;
c->ilist = 0;
c->suffixlist = 0;
@@ -341,13 +343,7 @@ conn *conn_new(const int sfd, enum conn_states init_state,
if (c->rbuf == 0 || c->wbuf == 0 || c->ilist == 0 || c->iov == 0 ||
c->msglist == 0 || c->suffixlist == 0) {
- if (c->rbuf != 0) free(c->rbuf);
- if (c->wbuf != 0) free(c->wbuf);
- if (c->ilist != 0) free(c->ilist);
- if (c->suffixlist != 0) free(c->suffixlist);
- if (c->iov != 0) free(c->iov);
- if (c->msglist != 0) free(c->msglist);
- free(c);
+ conn_free(c);
fprintf(stderr, "malloc()\n");
return NULL;
}
@@ -424,6 +420,8 @@ conn *conn_new(const int sfd, enum conn_states init_state,
stats.total_conns++;
STATS_UNLOCK();
+ MEMCACHED_CONN_ALLOCATE(c->sfd);
+
return c;
}
@@ -460,6 +458,7 @@ static void conn_cleanup(conn *c) {
*/
void conn_free(conn *c) {
if (c) {
+ MEMCACHED_CONN_DESTROY(c);
if (c->hdrbuf)
free(c->hdrbuf);
if (c->msglist)
@@ -487,6 +486,7 @@ static void conn_close(conn *c) {
if (settings.verbose > 1)
fprintf(stderr, "<%d connection closed.\n", c->sfd);
+ MEMCACHED_CONN_RELEASE(c->sfd);
close(c->sfd);
accept_new_conns(true);
conn_cleanup(c);
@@ -595,6 +595,10 @@ static void conn_set_state(conn *c, enum conn_states state) {
}
c->state = state;
+
+ if (state == conn_write) {
+ MEMCACHED_PROCESS_COMMAND_END(c->sfd, c->wbuf, c->wbytes);
+ }
}
}
@@ -835,9 +839,32 @@ static void complete_nread_ascii(conn *c) {
out_string(c, "CLIENT_ERROR bad data chunk");
} else {
ret = store_item(it, comm, c);
- if (ret == 1)
+ if (ret == 1) {
out_string(c, "STORED");
- else if(ret == 2)
+#ifdef HAVE_DTRACE
+ switch (comm) {
+ case NREAD_ADD:
+ MEMCACHED_COMMAND_ADD(c->sfd, ITEM_key(it), it->nbytes);
+ break;
+ case NREAD_REPLACE:
+ MEMCACHED_COMMAND_REPLACE(c->sfd, ITEM_key(it), it->nbytes);
+ break;
+ case NREAD_APPEND:
+ MEMCACHED_COMMAND_APPEND(c->sfd, ITEM_key(it), it->nbytes);
+ break;
+ case NREAD_PREPEND:
+ MEMCACHED_COMMAND_PREPEND(c->sfd, ITEM_key(it), it->nbytes);
+ break;
+ case NREAD_SET:
+ MEMCACHED_COMMAND_SET(c->sfd, ITEM_key(it), it->nbytes);
+ break;
+ case NREAD_CAS:
+ MEMCACHED_COMMAND_CAS(c->sfd, ITEM_key(it), it->nbytes,
+ it->cas_id);
+ break;
+ }
+#endif
+ } else if(ret == 2)
out_string(c, "EXISTS");
else if(ret == 3)
out_string(c, "NOT_FOUND");
@@ -1024,7 +1051,7 @@ static void complete_incr_bin(conn *c) {
/* Weird magic in add_delta forces me to pad here */
char tmpbuf[INCR_MAX_STORAGE_LEN];
uint64_t l = 0;
- add_delta(it, c->cmd == PROTOCOL_BINARY_CMD_INCREMENT,
+ add_delta(c, it, c->cmd == PROTOCOL_BINARY_CMD_INCREMENT,
req->message.body.delta, tmpbuf);
rsp->message.body.value = swap64(strtoull(tmpbuf, NULL, 10));
c->cas = it->cas_id;
@@ -2153,6 +2180,8 @@ static inline void process_get_command(conn *c, token_t *tokens, size_t ntokens,
if (return_cas)
{
+ MEMCACHED_COMMAND_GETS(c->sfd, ITEM_key(it), it->nbytes,
+ it->cas_id);
/* Goofy mid-flight realloc. */
if (i >= c->suffixsize) {
char **new_suffix_list = realloc(c->suffixlist,
@@ -2186,6 +2215,8 @@ static inline void process_get_command(conn *c, token_t *tokens, size_t ntokens,
}
else
{
+ MEMCACHED_COMMAND_GET(c->sfd, ITEM_key(it), it->nbytes);
+
if (add_iov(c, "VALUE ", 6) != 0 ||
add_iov(c, ITEM_key(it), it->nkey) != 0 ||
add_iov(c, ITEM_suffix(it), it->nsuffix + it->nbytes) != 0)
@@ -2206,6 +2237,11 @@ static inline void process_get_command(conn *c, token_t *tokens, size_t ntokens,
} else {
stats_get_misses++;
+ if (return_cas) {
+ MEMCACHED_COMMAND_GETS(c->sfd, key, -1, 0);
+ } else {
+ MEMCACHED_COMMAND_GET(c->sfd, key, -1);
+ }
}
key_token++;
@@ -2373,13 +2409,14 @@ static void process_arithmetic_command(conn *c, token_t *tokens, const size_t nt
return;
}
- out_string(c, add_delta(it, incr, delta, temp));
+ out_string(c, add_delta(c, it, incr, delta, temp));
item_remove(it); /* release our reference */
}
/*
* adds a delta value to a numeric item.
*
+ * c connection requesting the operation
* it item to adjust
* incr true to increment value, false to decrement
* delta amount to adjust value by
@@ -2387,7 +2424,7 @@ static void process_arithmetic_command(conn *c, token_t *tokens, const size_t nt
*
* returns a response string to send back to the client.
*/
-char *do_add_delta(item *it, const bool incr, const int64_t delta, char *buf) {
+char *do_add_delta(conn *c, item *it, const bool incr, const int64_t delta, char *buf) {
char *ptr;
int64_t value;
int res;
@@ -2401,13 +2438,15 @@ char *do_add_delta(item *it, const bool incr, const int64_t delta, char *buf) {
return "CLIENT_ERROR cannot increment or decrement non-numeric value";
}
- if (incr)
+ if (incr) {
value += delta;
- else {
+ MEMCACHED_COMMAND_INCR(c->sfd, ITEM_key(it), value);
+ } else {
value -= delta;
- }
- if(value < 0) {
- value = 0;
+ if(value < 0) {
+ value = 0;
+ }
+ MEMCACHED_COMMAND_DECR(c->sfd, ITEM_key(it), value);
}
sprintf(buf, "%llu", value);
res = strlen(buf);
@@ -2465,6 +2504,7 @@ static void process_delete_command(conn *c, token_t *tokens, const size_t ntoken
it = item_get(key, nkey);
if (it) {
+ MEMCACHED_PROCESS_COMMAND_START(c->sfd, c->rcurr, c->rbytes);
item_unlink(it);
item_remove(it); /* release our reference */
out_string(c, "DELETED");
@@ -2494,6 +2534,8 @@ static void process_command(conn *c, char *command) {
assert(c != NULL);
+ MEMCACHED_PROCESS_COMMAND_START(c->sfd, c->rcurr, c->rbytes);
+
if (settings.verbose > 1)
fprintf(stderr, "<%d %s\n", c->sfd, command);
diff --git a/memcached.h b/memcached.h
index f1fe6a9..4eccce1 100644
--- a/memcached.h
+++ b/memcached.h
@@ -281,7 +281,8 @@ conn *do_conn_from_freelist();
bool do_conn_add_to_freelist(conn *c);
char *do_suffix_from_freelist();
bool do_suffix_add_to_freelist(char *s);
-char *do_add_delta(item *item, const bool incr, const int64_t delta, char *buf);
+char *do_add_delta(conn *c, item *item, const bool incr, const int64_t delta,
+ char *buf);
int do_store_item(item *item, int comm, conn* c);
conn *conn_new(const int sfd, const enum conn_states init_state, const int event_flags, const int read_buffer_size, enum protocol prot, struct event_base *base);
@@ -290,6 +291,7 @@ conn *conn_new(const int sfd, const enum conn_states init_state, const int event
#include "slabs.h"
#include "assoc.h"
#include "items.h"
+#include "memcached_dtrace.h"
/*
@@ -304,7 +306,8 @@ int dispatch_event_add(int thread, conn *c);
void dispatch_conn_new(int sfd, enum conn_states init_state, int event_flags, int read_buffer_size, enum protocol prot);
/* Lock wrappers for cache functions that are called from main loop. */
-char *add_delta(item *item, const int incr, const int64_t delta, char *buf);
+char *add_delta(conn *c, item *item, const int incr, const int64_t delta,
+ char *buf);
void assoc_move_next_bucket(void);
conn *conn_from_freelist(void);
bool conn_add_to_freelist(conn *c);
diff --git a/memcached_dtrace.d b/memcached_dtrace.d
new file mode 100644
index 0000000..9119dd4
--- /dev/null
+++ b/memcached_dtrace.d
@@ -0,0 +1,274 @@
+/*
+ * Copyright (c) <2008>, Sun Microsystems, Inc.
+ * 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.
+ * * Neither the name of the nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY SUN MICROSYSTEMS, INC. ``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 SUN MICROSYSTEMS, INC. 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.
+ */
+provider memcached {
+ /**
+ * Fired when a connection object is allocated from the connection pool
+ * @param connid the connection id
+ */
+ probe conn__allocate(int connid);
+
+ /**
+ * Fired when a connection object is released back to the connection pool
+ * @param connid the connection id
+ */
+ probe conn__release(int connid);
+
+ /**
+ * Fired when a new connection object is being created (there is no more
+ * connection objects in the connection pool)
+ * @param ptr pointer to the connection object
+ */
+ probe conn__create(void *ptr);
+
+ /**
+ * Fired when a connection object is being destroyed ("released back to
+ * the memory subsystem")
+ * @param ptr pointer to the connection object
+ */
+ probe conn__destroy(void *ptr);
+
+ /**
+ * Fired when a connection is dispatched from the "main thread" to a
+ * worker thread.
+ * @param connid the connection id
+ * @param threadid the thread id
+ */
+ probe conn__dispatch(int connid, int threadid);
+
+ /**
+ * Allocate memory from the slab allocator
+ * @param size the requested size
+ * @param slabclass the allocation will be fulfilled in this class
+ * @param slabsize the size of each item in this class
+ * @param ptr pointer to allocated memory
+ */
+ probe slabs__allocate(int size, int slabclass, int slabsize, void* ptr);
+
+ /**
+ * Failed to allocate memory (out of memory)
+ * @param size the requested size
+ * @param slabclass the class that failed to fulfill the request
+ */
+ probe slabs__allocate__failed(int size, int slabclass);
+
+ /**
+ * Fired when a slab class needs more space
+ * @param slabclass class that needs more memory
+ */
+ probe slabs__slabclass__allocate(int slabclass);
+
+ /**
+ * Failed to allocate memory (out of memory)
+ * @param slabclass the class that failed grab more memory
+ */
+ probe slabs__slabclass__allocate__failed(int slabclass);
+
+ /**
+ * Release memory
+ * @param size the size of the memory
+ * @param slabclass the class the memory belongs to
+ * @param ptr pointer to the memory to release
+ */
+ probe slabs__free(int size, int slabclass, void* ptr);
+
+ /**
+ * Fired when the when we have searched the hash table for a named key.
+ * These two elements provide an insight in how well the hash function
+ * functions. Long traversals are a sign of a less optimal function,
+ * wasting cpu capacity.
+ *
+ * @param key the key searched for
+ * @param depth the depth in the list of hash table
+ */
+ probe assoc__find(const char *key, int depth);
+
+ /**
+ * Fired when a new item has been inserted.
+ * @param key the key just inserted
+ * @param nokeys the total number of keys currently being stored,
+ * including the key for which insert was called.
+ */
+ probe assoc__insert(const char *key, int nokeys);
+
+ /**
+ * Fired when a new item has been removed.
+ * @param key the key just deleted
+ * @param nokeys the total number of keys currently being stored,
+ * excluding the key for which delete was called.
+ */
+ probe assoc__delete(const char *key, int nokeys);
+
+ /**
+ * Fired when an item is being linked in the cache
+ * @param key the items key
+ * @param size the size of the data
+ */
+ probe item__link(const char *key, int size);
+
+ /**
+ * Fired when an item is being deleted
+ * @param key the items key
+ * @param size the size of the data
+ */
+ probe item__unlink(const char *key, int size);
+
+ /**
+ * Fired when the refcount for an item is reduced
+ * @param key the items key
+ * @param size the size of the data
+ */
+ probe item__remove(const char *key, int size);
+
+ /**
+ * Fired when the "last refenced" time is updated
+ * @param key the items key
+ * @param size the size of the data
+ */
+ probe item__update(const char *key, int size);
+
+ /**
+ * Fired when an item is bein replaced with another item
+ * @param oldkey the key of the item to replace
+ * @param oldsize the size of the old item
+ * @param newkey the key of the new item
+ * @param newsize the size of the new item
+ */
+ probe item__replace(const char *oldkey, int oldsize, const char *newkey, int newsize);
+
+ /**
+ * Fired when the processing of a command starts
+ * @param connid the connection id
+ * @param request the incomming request
+ * @param size the size of the request
+ */
+ probe process__command__start(int connid, const void *request, int size);
+
+ /**
+ * Fired when the processing of a command is done
+ * @param connid the connection id
+ * @param respnse the response to send back to the client
+ * @param size the size of the response
+ */
+ probe process__command__end(int connid, const void *response, int size);
+
+ /**
+ * Fired for a get-command
+ * @param connid connection id
+ * @param key requested key
+ * @param size size of the key's data (or -1 if not found)
+ */
+ probe command__get(int connid, const char *key, int size);
+
+ /**
+ * Fired for a gets command
+ * @param connid connection id
+ * @param key requested key
+ * @param size size of the key's data (or -1 if not found)
+ * @param casid the casid for the item
+ */
+ probe command__gets(int connid, const char *key, int size, int64_t casid);
+
+ /**
+ * Fired for a add-command
+ * @param connid connection id
+ * @param key requested key
+ * @param size the new size of the key's data (or -1 if not found)
+ */
+ probe command__add(int connid, const char *key, int size);
+
+ /**
+ * Fired for a set-command
+ * @param connid connection id
+ * @param key requested key
+ * @param size the new size of the key's data (or -1 if not found)
+ */
+ probe command__set(int connid, const char *key, int size);
+
+ /**
+ * Fired for a replace-command
+ * @param connid connection id
+ * @param key requested key
+ * @param size the new size of the key's data (or -1 if not found)
+ */
+ probe command__replace(int connid, const char *key, int size);
+
+ /**
+ * Fired for a prepend-command
+ * @param connid connection id
+ * @param key requested key
+ * @param size the new size of the key's data (or -1 if not found)
+ */
+ probe command__prepend(int connid, const char *key, int size);
+
+ /**
+ * Fired for a append-command
+ * @param connid connection id
+ * @param key requested key
+ * @param size the new size of the key's data (or -1 if not found)
+ */
+ probe command__append(int connid, const char *key, int size);
+
+ /**
+ * Fired for a cas-command
+ * @param connid connection id
+ * @param key requested key
+ * @param size size of the key's data (or -1 if not found)
+ * @param casid the cas id requested
+ */
+ probe command__cas(int connid, const char *key, int size, int64_t casid);
+
+ /**
+ * Fired for incr command
+ * @param connid connection id
+ * @param key the requested key
+ * @param val the new value
+ */
+ probe command__incr(int connid, const char *key, int64_t val);
+
+ /**
+ * Fired for decr command
+ * @param connid connection id
+ * @param key the requested key
+ * @param val the new value
+ */
+ probe command__decr(int connid, const char *key, int64_t val);
+
+ /**
+ * Fired for a delete command
+ * @param connid connection id
+ * @param key the requested key
+ * @param exptime the expiry time
+ */
+ probe command__delete(int connid, const char *key, long exptime);
+
+};
+
+#pragma D attributes Unstable/Unstable/Common provider memcached provider
+#pragma D attributes Private/Private/Common provider memcached module
+#pragma D attributes Private/Private/Common provider memcached function
+#pragma D attributes Unstable/Unstable/Common provider memcached name
+#pragma D attributes Unstable/Unstable/Common provider memcached args
diff --git a/memcached_dtrace.h b/memcached_dtrace.h
new file mode 100644
index 0000000..c296d06
--- /dev/null
+++ b/memcached_dtrace.h
@@ -0,0 +1,276 @@
+/*
+ * Generated by dtrace(1M).
+ */
+
+#ifndef _MEMCACHED_DTRACE_H
+#define _MEMCACHED_DTRACE_H
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#if ENABLE_DTRACE
+
+#define MEMCACHED_ASSOC_DELETE(arg0, arg1) \
+ __dtrace_memcached___assoc__delete(arg0, arg1)
+#define MEMCACHED_ASSOC_DELETE_ENABLED() \
+ __dtraceenabled_memcached___assoc__delete()
+#define MEMCACHED_ASSOC_FIND(arg0, arg1) \
+ __dtrace_memcached___assoc__find(arg0, arg1)
+#define MEMCACHED_ASSOC_FIND_ENABLED() \
+ __dtraceenabled_memcached___assoc__find()
+#define MEMCACHED_ASSOC_INSERT(arg0, arg1) \
+ __dtrace_memcached___assoc__insert(arg0, arg1)
+#define MEMCACHED_ASSOC_INSERT_ENABLED() \
+ __dtraceenabled_memcached___assoc__insert()
+#define MEMCACHED_COMMAND_ADD(arg0, arg1, arg2) \
+ __dtrace_memcached___command__add(arg0, arg1, arg2)
+#define MEMCACHED_COMMAND_ADD_ENABLED() \
+ __dtraceenabled_memcached___command__add()
+#define MEMCACHED_COMMAND_APPEND(arg0, arg1, arg2) \
+ __dtrace_memcached___command__append(arg0, arg1, arg2)
+#define MEMCACHED_COMMAND_APPEND_ENABLED() \
+ __dtraceenabled_memcached___command__append()
+#define MEMCACHED_COMMAND_CAS(arg0, arg1, arg2, arg3) \
+ __dtrace_memcached___command__cas(arg0, arg1, arg2, arg3)
+#define MEMCACHED_COMMAND_CAS_ENABLED() \
+ __dtraceenabled_memcached___command__cas()
+#define MEMCACHED_COMMAND_DECR(arg0, arg1, arg2) \
+ __dtrace_memcached___command__decr(arg0, arg1, arg2)
+#define MEMCACHED_COMMAND_DECR_ENABLED() \
+ __dtraceenabled_memcached___command__decr()
+#define MEMCACHED_COMMAND_DELETE(arg0, arg1, arg2) \
+ __dtrace_memcached___command__delete(arg0, arg1, arg2)
+#define MEMCACHED_COMMAND_DELETE_ENABLED() \
+ __dtraceenabled_memcached___command__delete()
+#define MEMCACHED_COMMAND_GET(arg0, arg1, arg2) \
+ __dtrace_memcached___command__get(arg0, arg1, arg2)
+#define MEMCACHED_COMMAND_GET_ENABLED() \
+ __dtraceenabled_memcached___command__get()
+#define MEMCACHED_COMMAND_GETS(arg0, arg1, arg2, arg3) \
+ __dtrace_memcached___command__gets(arg0, arg1, arg2, arg3)
+#define MEMCACHED_COMMAND_GETS_ENABLED() \
+ __dtraceenabled_memcached___command__gets()
+#define MEMCACHED_COMMAND_INCR(arg0, arg1, arg2) \
+ __dtrace_memcached___command__incr(arg0, arg1, arg2)
+#define MEMCACHED_COMMAND_INCR_ENABLED() \
+ __dtraceenabled_memcached___command__incr()
+#define MEMCACHED_COMMAND_PREPEND(arg0, arg1, arg2) \
+ __dtrace_memcached___command__prepend(arg0, arg1, arg2)
+#define MEMCACHED_COMMAND_PREPEND_ENABLED() \
+ __dtraceenabled_memcached___command__prepend()
+#define MEMCACHED_COMMAND_REPLACE(arg0, arg1, arg2) \
+ __dtrace_memcached___command__replace(arg0, arg1, arg2)
+#define MEMCACHED_COMMAND_REPLACE_ENABLED() \
+ __dtraceenabled_memcached___command__replace()
+#define MEMCACHED_COMMAND_SET(arg0, arg1, arg2) \
+ __dtrace_memcached___command__set(arg0, arg1, arg2)
+#define MEMCACHED_COMMAND_SET_ENABLED() \
+ __dtraceenabled_memcached___command__set()
+#define MEMCACHED_CONN_ALLOCATE(arg0) \
+ __dtrace_memcached___conn__allocate(arg0)
+#define MEMCACHED_CONN_ALLOCATE_ENABLED() \
+ __dtraceenabled_memcached___conn__allocate()
+#define MEMCACHED_CONN_CREATE(arg0) \
+ __dtrace_memcached___conn__create(arg0)
+#define MEMCACHED_CONN_CREATE_ENABLED() \
+ __dtraceenabled_memcached___conn__create()
+#define MEMCACHED_CONN_DESTROY(arg0) \
+ __dtrace_memcached___conn__destroy(arg0)
+#define MEMCACHED_CONN_DESTROY_ENABLED() \
+ __dtraceenabled_memcached___conn__destroy()
+#define MEMCACHED_CONN_DISPATCH(arg0, arg1) \
+ __dtrace_memcached___conn__dispatch(arg0, arg1)
+#define MEMCACHED_CONN_DISPATCH_ENABLED() \
+ __dtraceenabled_memcached___conn__dispatch()
+#define MEMCACHED_CONN_RELEASE(arg0) \
+ __dtrace_memcached___conn__release(arg0)
+#define MEMCACHED_CONN_RELEASE_ENABLED() \
+ __dtraceenabled_memcached___conn__release()
+#define MEMCACHED_ITEM_LINK(arg0, arg1) \
+ __dtrace_memcached___item__link(arg0, arg1)
+#define MEMCACHED_ITEM_LINK_ENABLED() \
+ __dtraceenabled_memcached___item__link()
+#define MEMCACHED_ITEM_REMOVE(arg0, arg1) \
+ __dtrace_memcached___item__remove(arg0, arg1)
+#define MEMCACHED_ITEM_REMOVE_ENABLED() \
+ __dtraceenabled_memcached___item__remove()
+#define MEMCACHED_ITEM_REPLACE(arg0, arg1, arg2, arg3) \
+ __dtrace_memcached___item__replace(arg0, arg1, arg2, arg3)
+#define MEMCACHED_ITEM_REPLACE_ENABLED() \
+ __dtraceenabled_memcached___item__replace()
+#define MEMCACHED_ITEM_UNLINK(arg0, arg1) \
+ __dtrace_memcached___item__unlink(arg0, arg1)
+#define MEMCACHED_ITEM_UNLINK_ENABLED() \
+ __dtraceenabled_memcached___item__unlink()
+#define MEMCACHED_ITEM_UPDATE(arg0, arg1) \
+ __dtrace_memcached___item__update(arg0, arg1)
+#define MEMCACHED_ITEM_UPDATE_ENABLED() \
+ __dtraceenabled_memcached___item__update()
+#define MEMCACHED_PROCESS_COMMAND_END(arg0, arg1, arg2) \
+ __dtrace_memcached___process__command__end(arg0, arg1, arg2)
+#define MEMCACHED_PROCESS_COMMAND_END_ENABLED() \
+ __dtraceenabled_memcached___process__command__end()
+#define MEMCACHED_PROCESS_COMMAND_START(arg0, arg1, arg2) \
+ __dtrace_memcached___process__command__start(arg0, arg1, arg2)
+#define MEMCACHED_PROCESS_COMMAND_START_ENABLED() \
+ __dtraceenabled_memcached___process__command__start()
+#define MEMCACHED_SLABS_ALLOCATE(arg0, arg1, arg2, arg3) \
+ __dtrace_memcached___slabs__allocate(arg0, arg1, arg2, arg3)
+#define MEMCACHED_SLABS_ALLOCATE_ENABLED() \
+ __dtraceenabled_memcached___slabs__allocate()
+#define MEMCACHED_SLABS_ALLOCATE_FAILED(arg0, arg1) \
+ __dtrace_memcached___slabs__allocate__failed(arg0, arg1)
+#define MEMCACHED_SLABS_ALLOCATE_FAILED_ENABLED() \
+ __dtraceenabled_memcached___slabs__allocate__failed()
+#define MEMCACHED_SLABS_FREE(arg0, arg1, arg2) \
+ __dtrace_memcached___slabs__free(arg0, arg1, arg2)
+#define MEMCACHED_SLABS_FREE_ENABLED() \
+ __dtraceenabled_memcached___slabs__free()
+#define MEMCACHED_SLABS_SLABCLASS_ALLOCATE(arg0) \
+ __dtrace_memcached___slabs__slabclass__allocate(arg0)
+#define MEMCACHED_SLABS_SLABCLASS_ALLOCATE_ENABLED() \
+ __dtraceenabled_memcached___slabs__slabclass__allocate()
+#define MEMCACHED_SLABS_SLABCLASS_ALLOCATE_FAILED(arg0) \
+ __dtrace_memcached___slabs__slabclass__allocate__failed(arg0)
+#define MEMCACHED_SLABS_SLABCLASS_ALLOCATE_FAILED_ENABLED() \
+ __dtraceenabled_memcached___slabs__slabclass__allocate__failed()
+
+
+extern void __dtrace_memcached___assoc__delete(char *, int);
+extern int __dtraceenabled_memcached___assoc__delete(void);
+extern void __dtrace_memcached___assoc__find(char *, int);
+extern int __dtraceenabled_memcached___assoc__find(void);
+extern void __dtrace_memcached___assoc__insert(char *, int);
+extern int __dtraceenabled_memcached___assoc__insert(void);
+extern void __dtrace_memcached___command__add(int, char *, int);
+extern int __dtraceenabled_memcached___command__add(void);
+extern void __dtrace_memcached___command__append(int, char *, int);
+extern int __dtraceenabled_memcached___command__append(void);
+extern void __dtrace_memcached___command__cas(int, char *, int, int64_t);
+extern int __dtraceenabled_memcached___command__cas(void);
+extern void __dtrace_memcached___command__decr(int, char *, int64_t);
+extern int __dtraceenabled_memcached___command__decr(void);
+extern void __dtrace_memcached___command__delete(int, char *, long);
+extern int __dtraceenabled_memcached___command__delete(void);
+extern void __dtrace_memcached___command__get(int, char *, int);
+extern int __dtraceenabled_memcached___command__get(void);
+extern void __dtrace_memcached___command__gets(int, char *, int, int64_t);
+extern int __dtraceenabled_memcached___command__gets(void);
+extern void __dtrace_memcached___command__incr(int, char *, int64_t);
+extern int __dtraceenabled_memcached___command__incr(void);
+extern void __dtrace_memcached___command__prepend(int, char *, int);
+extern int __dtraceenabled_memcached___command__prepend(void);
+extern void __dtrace_memcached___command__replace(int, char *, int);
+extern int __dtraceenabled_memcached___command__replace(void);
+extern void __dtrace_memcached___command__set(int, char *, int);
+extern int __dtraceenabled_memcached___command__set(void);
+extern void __dtrace_memcached___conn__allocate(int);
+extern int __dtraceenabled_memcached___conn__allocate(void);
+extern void __dtrace_memcached___conn__create(void *);
+extern int __dtraceenabled_memcached___conn__create(void);
+extern void __dtrace_memcached___conn__destroy(void *);
+extern int __dtraceenabled_memcached___conn__destroy(void);
+extern void __dtrace_memcached___conn__dispatch(int, int);
+extern int __dtraceenabled_memcached___conn__dispatch(void);
+extern void __dtrace_memcached___conn__release(int);
+extern int __dtraceenabled_memcached___conn__release(void);
+extern void __dtrace_memcached___item__link(char *, int);
+extern int __dtraceenabled_memcached___item__link(void);
+extern void __dtrace_memcached___item__remove(char *, int);
+extern int __dtraceenabled_memcached___item__remove(void);
+extern void __dtrace_memcached___item__replace(char *, int, char *, int);
+extern int __dtraceenabled_memcached___item__replace(void);
+extern void __dtrace_memcached___item__unlink(char *, int);
+extern int __dtraceenabled_memcached___item__unlink(void);
+extern void __dtrace_memcached___item__update(char *, int);
+extern int __dtraceenabled_memcached___item__update(void);
+extern void __dtrace_memcached___process__command__end(int, void *, int);
+extern int __dtraceenabled_memcached___process__command__end(void);
+extern void __dtrace_memcached___process__command__start(int, void *, int);
+extern int __dtraceenabled_memcached___process__command__start(void);
+extern void __dtrace_memcached___slabs__allocate(int, int, int, void *);
+extern int __dtraceenabled_memcached___slabs__allocate(void);
+extern void __dtrace_memcached___slabs__allocate__failed(int, int);
+extern int __dtraceenabled_memcached___slabs__allocate__failed(void);
+extern void __dtrace_memcached___slabs__free(int, int, void *);
+extern int __dtraceenabled_memcached___slabs__free(void);
+extern void __dtrace_memcached___slabs__slabclass__allocate(int);
+extern int __dtraceenabled_memcached___slabs__slabclass__allocate(void);
+extern void __dtrace_memcached___slabs__slabclass__allocate__failed(int);
+extern int __dtraceenabled_memcached___slabs__slabclass__allocate__failed(void);
+
+#else
+
+#define MEMCACHED_ASSOC_DELETE(arg0, arg1)
+#define MEMCACHED_ASSOC_DELETE_ENABLED() (0)
+#define MEMCACHED_ASSOC_FIND(arg0, arg1)
+#define MEMCACHED_ASSOC_FIND_ENABLED() (0)
+#define MEMCACHED_ASSOC_INSERT(arg0, arg1)
+#define MEMCACHED_ASSOC_INSERT_ENABLED() (0)
+#define MEMCACHED_COMMAND_ADD(arg0, arg1, arg2)
+#define MEMCACHED_COMMAND_ADD_ENABLED() (0)
+#define MEMCACHED_COMMAND_APPEND(arg0, arg1, arg2)
+#define MEMCACHED_COMMAND_APPEND_ENABLED() (0)
+#define MEMCACHED_COMMAND_CAS(arg0, arg1, arg2, arg3)
+#define MEMCACHED_COMMAND_CAS_ENABLED() (0)
+#define MEMCACHED_COMMAND_DECR(arg0, arg1, arg2)
+#define MEMCACHED_COMMAND_DECR_ENABLED() (0)
+#define MEMCACHED_COMMAND_DELETE(arg0, arg1, arg2)
+#define MEMCACHED_COMMAND_DELETE_ENABLED() (0)
+#define MEMCACHED_COMMAND_GET(arg0, arg1, arg2)
+#define MEMCACHED_COMMAND_GET_ENABLED() (0)
+#define MEMCACHED_COMMAND_GETS(arg0, arg1, arg2, arg3)
+#define MEMCACHED_COMMAND_GETS_ENABLED() (0)
+#define MEMCACHED_COMMAND_INCR(arg0, arg1, arg2)
+#define MEMCACHED_COMMAND_INCR_ENABLED() (0)
+#define MEMCACHED_COMMAND_PREPEND(arg0, arg1, arg2)
+#define MEMCACHED_COMMAND_PREPEND_ENABLED() (0)
+#define MEMCACHED_COMMAND_REPLACE(arg0, arg1, arg2)
+#define MEMCACHED_COMMAND_REPLACE_ENABLED() (0)
+#define MEMCACHED_COMMAND_SET(arg0, arg1, arg2)
+#define MEMCACHED_COMMAND_SET_ENABLED() (0)
+#define MEMCACHED_CONN_ALLOCATE(arg0)
+#define MEMCACHED_CONN_ALLOCATE_ENABLED() (0)
+#define MEMCACHED_CONN_CREATE(arg0)
+#define MEMCACHED_CONN_CREATE_ENABLED() (0)
+#define MEMCACHED_CONN_DESTROY(arg0)
+#define MEMCACHED_CONN_DESTROY_ENABLED() (0)
+#define MEMCACHED_CONN_DISPATCH(arg0, arg1)
+#define MEMCACHED_CONN_DISPATCH_ENABLED() (0)
+#define MEMCACHED_CONN_RELEASE(arg0)
+#define MEMCACHED_CONN_RELEASE_ENABLED() (0)
+#define MEMCACHED_ITEM_LINK(arg0, arg1)
+#define MEMCACHED_ITEM_LINK_ENABLED() (0)
+#define MEMCACHED_ITEM_REMOVE(arg0, arg1)
+#define MEMCACHED_ITEM_REMOVE_ENABLED() (0)
+#define MEMCACHED_ITEM_REPLACE(arg0, arg1, arg2, arg3)
+#define MEMCACHED_ITEM_REPLACE_ENABLED() (0)
+#define MEMCACHED_ITEM_UNLINK(arg0, arg1)
+#define MEMCACHED_ITEM_UNLINK_ENABLED() (0)
+#define MEMCACHED_ITEM_UPDATE(arg0, arg1)
+#define MEMCACHED_ITEM_UPDATE_ENABLED() (0)
+#define MEMCACHED_PROCESS_COMMAND_END(arg0, arg1, arg2)
+#define MEMCACHED_PROCESS_COMMAND_END_ENABLED() (0)
+#define MEMCACHED_PROCESS_COMMAND_START(arg0, arg1, arg2)
+#define MEMCACHED_PROCESS_COMMAND_START_ENABLED() (0)
+#define MEMCACHED_SLABS_ALLOCATE(arg0, arg1, arg2, arg3)
+#define MEMCACHED_SLABS_ALLOCATE_ENABLED() (0)
+#define MEMCACHED_SLABS_ALLOCATE_FAILED(arg0, arg1)
+#define MEMCACHED_SLABS_ALLOCATE_FAILED_ENABLED() (0)
+#define MEMCACHED_SLABS_FREE(arg0, arg1, arg2)
+#define MEMCACHED_SLABS_FREE_ENABLED() (0)
+#define MEMCACHED_SLABS_SLABCLASS_ALLOCATE(arg0)
+#define MEMCACHED_SLABS_SLABCLASS_ALLOCATE_ENABLED() (0)
+#define MEMCACHED_SLABS_SLABCLASS_ALLOCATE_FAILED(arg0)
+#define MEMCACHED_SLABS_SLABCLASS_ALLOCATE_FAILED_ENABLED() (0)
+
+#endif
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _MEMCACHED_DTRACE_H */
diff --git a/slabs.c b/slabs.c
index c55b624..4ab5fe6 100644
--- a/slabs.c
+++ b/slabs.c
@@ -200,13 +200,13 @@ static int do_slabs_newslab(const unsigned int id) {
#endif
char *ptr;
- if (mem_limit && mem_malloced + len > mem_limit && p->slabs > 0)
- return 0;
-
- if (grow_slab_list(id) == 0) return 0;
+ if ((mem_limit && mem_malloced + len > mem_limit && p->slabs > 0) ||
+ (grow_slab_list(id) == 0) ||
+ ((ptr = memory_allocate((size_t)len)) == 0)) {
- ptr = memory_allocate((size_t)len);
- if (ptr == 0) return 0;
+ MEMCACHED_SLABS_SLABCLASS_ALLOCATE_FAILED(id);
+ return 0;
+ }
memset(ptr, 0, (size_t)len);
p->end_page_ptr = ptr;
@@ -214,47 +214,62 @@ static int do_slabs_newslab(const unsigned int id) {
p->slab_list[p->slabs++] = ptr;
mem_malloced += len;
+
+ MEMCACHED_SLABS_SLABCLASS_ALLOCATE(id);
return 1;
}
/*@null@*/
void *do_slabs_alloc(const size_t size, unsigned int id) {
slabclass_t *p;
+ void *ret = NULL;
- if (id < POWER_SMALLEST || id > power_largest)
+ if (id < POWER_SMALLEST || id > power_largest) {
+ MEMCACHED_SLABS_ALLOCATE_FAILED(size, 0);
return NULL;
+ }
p = &slabclass[id];
assert(p->sl_curr == 0 || ((item *)p->slots[p->sl_curr - 1])->slabs_clsid == 0);
#ifdef USE_SYSTEM_MALLOC
- if (mem_limit && mem_malloced + size > mem_limit)
+ if (mem_limit && mem_malloced + size > mem_limit) {
+ MEMCACHED_SLABS_ALLOCATE_FAILED(size, id);
return 0;
+ }
mem_malloced += size;
- return malloc(size);
+ ret = malloc(size);
+ MEMCACHED_SLABS_ALLOCATE(size, id, 0, ret);
+ return ret;
#endif
/* fail unless we have space at the end of a recently allocated page,
we have something on our freelist, or we could allocate a new page */
- if (! (p->end_page_ptr != 0 || p->sl_curr != 0 || do_slabs_newslab(id) != 0))
- return 0;
-
- /* return off our freelist, if we have one */
- if (p->sl_curr != 0)
- return p->slots[--p->sl_curr];
-
- /* if we recently allocated a whole page, return from that */
- if (p->end_page_ptr) {
- void *ptr = p->end_page_ptr;
+ if (! (p->end_page_ptr != 0 || p->sl_curr != 0 ||
+ do_slabs_newslab(id) != 0)) {
+ /* We don't have more memory available */
+ ret = NULL;
+ } else if (p->sl_curr != 0) {
+ /* return off our freelist */
+ ret = p->slots[--p->sl_curr];
+ } else {
+ /* if we recently allocated a whole page, return from that */
+ assert(p->end_page_ptr != NULL);
+ ret = p->end_page_ptr;
if (--p->end_page_free != 0) {
p->end_page_ptr += p->size;
} else {
p->end_page_ptr = 0;
}
- return ptr;
}
- return NULL; /* shouldn't ever get here */
+ if (ret) {
+ MEMCACHED_SLABS_ALLOCATE(size, id, p->size, ret);
+ } else {
+ MEMCACHED_SLABS_ALLOCATE_FAILED(size, id);
+ }
+
+ return ret;
}
void do_slabs_free(void *ptr, const size_t size, unsigned int id) {
@@ -265,6 +280,7 @@ void do_slabs_free(void *ptr, const size_t size, unsigned int id) {
if (id < POWER_SMALLEST || id > power_largest)
return;
+ MEMCACHED_SLABS_FREE(size, id, ptr);
p = &slabclass[id];
#ifdef USE_SYSTEM_MALLOC
diff --git a/thread.c b/thread.c
index ae75fea..5a7afa9 100644
--- a/thread.c
+++ b/thread.c
@@ -380,6 +380,8 @@ void dispatch_conn_new(int sfd, enum conn_states init_state, int event_flags,
item->protocol = prot;
cq_push(&threads[thread].new_conn_queue, item);
+
+ MEMCACHED_CONN_DISPATCH(sfd, threads[thread].thread_id);
if (write(threads[thread].notify_send_fd, "", 1) != 1) {
perror("Writing to thread notify pipe");
}
@@ -469,11 +471,12 @@ void item_update(item *item) {
/*
* Does arithmetic on a numeric item value.
*/
-char *add_delta(item *item, int incr, const int64_t delta, char *buf) {
+char *add_delta(conn *c, item *item, int incr, const int64_t delta,
+ char *buf) {
char *ret;
pthread_mutex_lock(&cache_lock);
- ret = do_add_delta(item, incr, delta, buf);
+ ret = do_add_delta(c, item, incr, delta, buf);
pthread_mutex_unlock(&cache_lock);
return ret;
}