diff options
-rw-r--r-- | Makefile.am | 18 | ||||
-rw-r--r-- | assoc.c | 22 | ||||
-rw-r--r-- | configure.ac | 22 | ||||
-rw-r--r-- | items.c | 6 | ||||
-rw-r--r-- | memcached.c | 76 | ||||
-rw-r--r-- | memcached.h | 7 | ||||
-rw-r--r-- | memcached_dtrace.d | 274 | ||||
-rw-r--r-- | memcached_dtrace.h | 276 | ||||
-rw-r--r-- | slabs.c | 58 | ||||
-rw-r--r-- | thread.c | 7 |
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 @@ -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 @@ -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 */ @@ -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 @@ -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; } |