Skip to content

Commit

Permalink
Create a generic cache for objects of same size
Browse files Browse the repository at this point in the history
The suffix pool could be thread-local and use the generic cache
  • Loading branch information
Trond Norbye authored and dustin committed Apr 17, 2009
1 parent ee0c3d5 commit 4c86fa5
Show file tree
Hide file tree
Showing 10 changed files with 530 additions and 223 deletions.
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -33,5 +33,5 @@ memcached-*.tar.gz
doc/protocol-binary-range.txt
doc/protocol-binary.txt
/sizes
/internal_tests
/version.m4
/testapp
17 changes: 11 additions & 6 deletions Makefile.am
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
bin_PROGRAMS = memcached
pkginclude_HEADERS = protocol_binary.h
noinst_PROGRAMS = memcached-debug sizes internal_tests
noinst_PROGRAMS = memcached-debug sizes testapp

BUILT_SOURCES=

testapp_SOURCES = testapp.c util.c util.h

memcached_SOURCES = memcached.c memcached.h \
hash.c hash.h \
slabs.c slabs.h \
Expand All @@ -12,7 +14,12 @@ memcached_SOURCES = memcached.c memcached.h \
thread.c daemon.c \
stats.c stats.h \
util.c util.h \
trace.h
trace.h cache.h

if BUILD_CACHE
memcached_SOURCES += cache.c
testapp_SOURCES += cache.c
endif

if BUILD_SOLARIS_PRIVS
memcached_SOURCES += solaris_priv.c
Expand All @@ -28,8 +35,6 @@ memcached_DEPENDENCIES =
memcached_debug_DEPENDENCIES =
CLEANFILES=

internal_tests_SOURCES = internal_tests.c util.c

if BUILD_DTRACE
BUILT_SOURCES += memcached_dtrace.h
CLEANFILES += memcached_dtrace.h
Expand Down Expand Up @@ -62,9 +67,9 @@ EXTRA_DIST = doc scripts TODO t memcached.spec memcached_dtrace.d version.m4

MOSTLYCLEANFILES = *.gcov *.gcno *.gcda *.tcov

test: memcached-debug internal_tests sizes
test: memcached-debug sizes testapp
$(srcdir)/sizes
$(srcdir)/internal_tests
$(srcdir)/testapp
prove $(srcdir)/t
@if test `basename $(PROFILER)` = "gcov"; then \
for file in memcached_debug-*.gc??; do \
Expand Down
146 changes: 146 additions & 0 deletions cache.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
/* -*- Mode: C; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
#include <stdlib.h>
#include <string.h>
#include <inttypes.h>

#ifndef NDEBUG
#include <signal.h>
#endif

#include "cache.h"

#ifndef NDEBUG
const uint64_t redzone_pattern = 0xdeadbeefcafebabe;
int cache_error = 0;
#endif

const int initial_pool_size = 64;

cache_t* cache_create(const char *name, size_t bufsize, size_t align,
cache_constructor_t* constructor,
cache_destructor_t* destructor) {
cache_t* ret = calloc(1, sizeof(cache_t));
char* nm = strdup(name);
void** ptr = calloc(initial_pool_size, bufsize);
if (ret == NULL || nm == NULL || ptr == NULL ||
pthread_mutex_init(&ret->mutex, NULL) == -1) {
free(ret);
free(nm);
free(ptr);
return NULL;
}

ret->name = nm;
ret->ptr = ptr;
ret->freetotal = initial_pool_size;
ret->constructor = constructor;
ret->destructor = destructor;

#ifndef NDEBUG
ret->bufsize = bufsize + 2 * sizeof(redzone_pattern);
#else
ret->bufsize = bufsize;
#endif

return ret;
}

static inline void* get_object(void *ptr) {
#ifndef NDEBUG
uint64_t *pre = ptr;
return pre + 1;
#endif
return ptr;
}

void cache_destroy(cache_t *cache) {
while (cache->freecurr > 0) {
void *ptr = cache->ptr[--cache->freecurr];
if (cache->destructor) {
cache->destructor(get_object(ptr), NULL);
}
free(ptr);
}
free(cache->name);
free(cache->ptr);
pthread_mutex_destroy(&cache->mutex);
}

void* cache_alloc(cache_t *cache) {
void *ret;
void *object;
pthread_mutex_lock(&cache->mutex);
if (cache->freecurr > 0) {
ret = cache->ptr[--cache->freecurr];
object = get_object(ret);
} else {
object = ret = malloc(cache->bufsize);
if (ret != NULL) {
object = get_object(ret);

if (cache->constructor != NULL &&
cache->constructor(object, NULL, 0) != 0) {
free(ret);
object = NULL;
}
}
}
pthread_mutex_unlock(&cache->mutex);

#ifndef NDEBUG
if (object != NULL) {
/* add a simple form of buffer-check */
uint64_t *pre = ret;
*pre = redzone_pattern;
ret = pre+1;
memcpy(((char*)ret) + cache->bufsize - (2 * sizeof(redzone_pattern)),
&redzone_pattern, sizeof(redzone_pattern));
}
#endif

return object;
}

void cache_free(cache_t *cache, void *ptr) {
pthread_mutex_lock(&cache->mutex);

#ifndef NDEBUG
/* validate redzone... */
if (memcmp(((char*)ptr) + cache->bufsize - (2 * sizeof(redzone_pattern)),
&redzone_pattern, sizeof(redzone_pattern)) != 0) {
raise(SIGABRT);
cache_error = 1;
pthread_mutex_unlock(&cache->mutex);
return;
}
uint64_t *pre = ptr;
--pre;
if (*pre != redzone_pattern) {
raise(SIGABRT);
cache_error = -1;
pthread_mutex_unlock(&cache->mutex);
return;
}
ptr = pre;
#endif
if (cache->freecurr < cache->freetotal) {
cache->ptr[cache->freecurr++] = ptr;
} else {
/* try to enlarge free connections array */
size_t newtotal = cache->freetotal * 2;
void **new_free = realloc(cache->ptr, sizeof(char *) * newtotal);
if (new_free) {
cache->freetotal = newtotal;
cache->ptr = new_free;
cache->ptr[cache->freecurr++] = ptr;
} else {
if (cache->destructor) {
cache->destructor(ptr, NULL);
}
free(ptr);

}
}
pthread_mutex_unlock(&cache->mutex);
}

44 changes: 44 additions & 0 deletions cache.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
/* -*- Mode: C; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
#ifndef CACHE_H
#define CACHE_H
#include <pthread.h>

#ifdef HAVE_UMEM_H
#include <umem.h>
#define cache_t umem_cache_t
#define cache_alloc(a) umem_cache_alloc(a, UMEM_DEFAULT)
#define cache_free(a, b) umem_cache_free(a, b)
#define cache_create(a,b,c,d,e) umem_cache_create((char*)a, b, c, d, e, NULL, NULL, NULL, 0)
#define cache_destroy(a) umem_cache_destroy(a);

#else

#ifndef NDEBUG
/* may be used for debug purposes */
extern int cache_error;
#endif

typedef int cache_constructor_t(void *, void *, int);
typedef void cache_destructor_t(void *, void *);

typedef struct {
pthread_mutex_t mutex;
char *name;
void **ptr;
size_t bufsize;
int freetotal;
int freecurr;
cache_constructor_t* constructor;
cache_destructor_t* destructor;
} cache_t;


cache_t* cache_create(const char *name, size_t bufsize, size_t align,
cache_constructor_t* constructor,
cache_destructor_t* destructor);
void cache_destroy(cache_t*);
void* cache_alloc(cache_t*);
void cache_free(cache_t*, void*);
#endif

#endif
9 changes: 8 additions & 1 deletion configure.ac
Original file line number Diff line number Diff line change
Expand Up @@ -230,7 +230,6 @@ dnl ----------------------------------------------------------------------------
AC_SEARCH_LIBS(socket, socket)
AC_SEARCH_LIBS(gethostbyname, nsl)
AC_SEARCH_LIBS(umem_cache_create, umem)

AC_HEADER_STDBOOL
AC_C_CONST

Expand Down Expand Up @@ -336,6 +335,14 @@ AC_CHECK_FUNCS(setppriv, [

AM_CONDITIONAL([BUILD_SOLARIS_PRIVS],[test "$build_solaris_privs" = "yes"])

AC_CHECK_HEADER(umem.h, [
AC_DEFINE([HAVE_UMEM_H], 1,
[Define this if you have umem.h])
build_cache=no
], [build_cache=yes])

AM_CONDITIONAL([BUILD_CACHE], [test "x$build_cache" = "xyes"])

AC_ARG_ENABLE(docs,
[AS_HELP_STRING([--disable-docs],[Disable documentation generation])])

Expand Down
Loading

0 comments on commit 4c86fa5

Please sign in to comment.