7dcf2fbb4468136ab79b4288a0b2e42216aeee7c
[awesomized/libmemcached] / memcached / cache.c
1 /* -*- Mode: C; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2 #include "memcached.h"
3
4 #include <stdlib.h>
5 #include <string.h>
6 #include <inttypes.h>
7 #include <string.h>
8
9 #ifndef NDEBUG
10 #include <signal.h>
11 #endif
12
13 #include "cache.h"
14
15 #ifndef NDEBUG
16 const uint64_t redzone_pattern = 0xdeadbeefcafebabe;
17 int cache_error = 0;
18 #endif
19
20 const int initial_pool_size = 64;
21
22 cache_t* cache_create(const char *name, size_t bufsize, size_t align,
23 cache_constructor_t* constructor,
24 cache_destructor_t* destructor) {
25 cache_t* ret = calloc(1, sizeof(cache_t));
26 char* nm = strdup(name);
27 void** ptr = calloc(initial_pool_size, sizeof(void*));
28 if (ret == NULL || nm == NULL || ptr == NULL ||
29 pthread_mutex_init(&ret->mutex, NULL) == -1) {
30 free(ret);
31 free(nm);
32 free(ptr);
33 return NULL;
34 }
35
36 ret->name = nm;
37 ret->ptr = ptr;
38 ret->freetotal = initial_pool_size;
39 ret->constructor = constructor;
40 ret->destructor = destructor;
41
42 #ifndef NDEBUG
43 ret->bufsize = bufsize + 2 * sizeof(redzone_pattern);
44 #else
45 ret->bufsize = bufsize;
46 #endif
47
48 return ret;
49 }
50
51 static inline void* get_object(void *ptr) {
52 #ifndef NDEBUG
53 uint64_t *pre = ptr;
54 return pre + 1;
55 #else
56 return ptr;
57 #endif
58 }
59
60 void cache_destroy(cache_t *cache) {
61 while (cache->freecurr > 0) {
62 void *ptr = cache->ptr[--cache->freecurr];
63 if (cache->destructor) {
64 cache->destructor(get_object(ptr), NULL);
65 }
66 free(ptr);
67 }
68 free(cache->name);
69 free(cache->ptr);
70 pthread_mutex_destroy(&cache->mutex);
71 }
72
73 void* cache_alloc(cache_t *cache) {
74 void *ret;
75 void *object;
76 pthread_mutex_lock(&cache->mutex);
77 if (cache->freecurr > 0) {
78 ret = cache->ptr[--cache->freecurr];
79 object = get_object(ret);
80 } else {
81 object = ret = malloc(cache->bufsize);
82 if (ret != NULL) {
83 object = get_object(ret);
84
85 if (cache->constructor != NULL &&
86 cache->constructor(object, NULL, 0) != 0) {
87 free(ret);
88 object = NULL;
89 }
90 }
91 }
92 pthread_mutex_unlock(&cache->mutex);
93
94 #ifndef NDEBUG
95 if (object != NULL) {
96 /* add a simple form of buffer-check */
97 uint64_t *pre = ret;
98 *pre = redzone_pattern;
99 ret = pre+1;
100 memcpy(((char*)ret) + cache->bufsize - (2 * sizeof(redzone_pattern)),
101 &redzone_pattern, sizeof(redzone_pattern));
102 }
103 #endif
104
105 return object;
106 }
107
108 void cache_free(cache_t *cache, void *ptr) {
109 pthread_mutex_lock(&cache->mutex);
110
111 #ifndef NDEBUG
112 /* validate redzone... */
113 if (memcmp(((char*)ptr) + cache->bufsize - (2 * sizeof(redzone_pattern)),
114 &redzone_pattern, sizeof(redzone_pattern)) != 0) {
115 raise(SIGABRT);
116 cache_error = 1;
117 pthread_mutex_unlock(&cache->mutex);
118 return;
119 }
120 uint64_t *pre = ptr;
121 --pre;
122 if (*pre != redzone_pattern) {
123 raise(SIGABRT);
124 cache_error = -1;
125 pthread_mutex_unlock(&cache->mutex);
126 return;
127 }
128 ptr = pre;
129 #endif
130 if (cache->freecurr < cache->freetotal) {
131 cache->ptr[cache->freecurr++] = ptr;
132 } else {
133 /* try to enlarge free connections array */
134 size_t newtotal = cache->freetotal * 2;
135 void **new_free = realloc(cache->ptr, sizeof(char *) * newtotal);
136 if (new_free) {
137 cache->freetotal = newtotal;
138 cache->ptr = new_free;
139 cache->ptr[cache->freecurr++] = ptr;
140 } else {
141 if (cache->destructor) {
142 cache->destructor(ptr, NULL);
143 }
144 free(ptr);
145
146 }
147 }
148 pthread_mutex_unlock(&cache->mutex);
149 }
150