↑ 1 #include <stdlib.h>
↑ 2 #include <stdio.h>
↑ 3 #include "memcache.h"
↑ 4 #include "rh_string.h"
↑ 5
↑ 6 #ifndef MEMCACHE_TIMEOUT
↑ 7 # define MEMCACHE_TIMEOUT 5
↑ 8 #endif
↑ 9
↑ 10 #ifndef MEMCACHE_TIMEOUT_INTERVAL
↑ 11 # define MEMCACHE_TIMEOUT_INTERVAL 2
↑ 12 #endif
↑ 13
↑ 14 #ifndef MEMCACHE_RESET_INTERVAL
↑ 15 # define MEMCACHE_RESET_INTERVAL 60
↑ 16 #endif
↑ 17
↑ 18 static int memcache_resize (memcache_t *cache, int grow);
↑ 19
↑ 20
↑ 21 void memcache_init (memcache_t *cache, time_t *current_time)
↑ 22 {
↑ 23 TYPE_ZERO(cache);
↑ 24
↑ 25 cache->time = current_time;
↑ 26 TAILQ_INIT(&cache->timeout);
↑ 27
↑ 28 cache->limit = 1024 * 1024 * 100; /* 100 mb */
↑ 29 }
↑ 30
↑ 31 void memcache_destroy (memcache_t *cache)
↑ 32 {
↑ 33 size_t i;
↑ 34
↑ 35 if (NULL == cache->buckets)
↑ 36 return;
↑ 37
↑ 38 for (i=0; i<cache->nbuckets; ++i) {
↑ 39 struct memcache_entry_list *list;
↑ 40 memcache_entry_t *entry;
↑ 41
↑ 42 list = &cache->buckets[i];
↑ 43
↑ 44 while ( (entry = TAILQ_FIRST(list)) ) {
↑ 45 TAILQ_REMOVE(list, entry, buckets);
↑ 46 TAILQ_REMOVE(&cache->timeout, entry, timeout);
↑ 47 free (entry);
↑ 48 }
↑ 49 }
↑ 50
↑ 51 free (cache->buckets);
↑ 52
↑ 53 TYPE_ZERO(cache);
↑ 54 }
↑ 55
↑ 56 void * memcache_pop (memcache_t *cache, size_t size)
↑ 57 {
↑ 58 struct memcache_entry_list *list;
↑ 59 memcache_entry_t *entry;
↑ 60
↑ 61 if (0 == cache->nelements || size < sizeof(*entry))
↑ 62 goto out_malloc;
↑ 63
↑ 64 list = &cache->buckets[size % cache->nbuckets];
↑ 65
↑ 66 TAILQ_FOREACH(entry, list, buckets) {
↑ 67 if (entry->size != size)
↑ 68 continue;
↑ 69
↑ 70 TAILQ_REMOVE(list, entry, buckets);
↑ 71 TAILQ_REMOVE(&cache->timeout, entry, timeout);
↑ 72
↑ 73 --cache->nelements;
↑ 74 cache->usage -= size;
↑ 75
↑ 76 return (void *) entry;
↑ 77 }
↑ 78
↑ 79 out_malloc:
↑ 80 #if 0
↑ 81 printf ("%s(): malloc size(%zu) usage(%zu/%zu)\n",
↑ 82 __FUNCTION__,
↑ 83 size, cache->usage, cache->limit );
↑ 84 #endif
↑ 85 return malloc (size);
↑ 86 }
↑ 87
↑ 88 void memcache_push (memcache_t *cache, void *ptr, size_t size)
↑ 89 {
↑ 90 time_t atime;
↑ 91 #if 0
↑ 92 printf ("%s(%p, %p): usage(%zu/%zu)\n",
↑ 93 __FUNCTION__,
↑ 94 (void*)cache, ptr,
↑ 95 cache->usage, cache->limit );
↑ 96 #endif
↑ 97
↑ 98 if (size < sizeof(memcache_entry_t))
↑ 99 goto out_free;
↑100
↑101 if (0 == cache->nbuckets || cache->nelements / cache->nbuckets > 5) {
↑102 if (0 != memcache_resize (cache, 1))
↑103 goto out_free;
↑104 }
↑105
↑106 atime = *(cache->time);
↑107
↑108 if (cache->usage + size > cache->limit) {
↑109 free (ptr);
↑110 } else {
↑111 memcache_entry_t *entry;
↑112 struct memcache_entry_list *list;
↑113
↑114 list = &cache->buckets[size % cache->nbuckets];
↑115
↑116 entry = ptr;
↑117 entry->size = size;
↑118 entry->atime = atime;
↑119 cache->usage += size;
↑120
↑121 ++cache->nelements;
↑122
↑123 TAILQ_INSERT_TAIL(list, entry, buckets);
↑124 TAILQ_INSERT_TAIL(&cache->timeout, entry, timeout);
↑125 }
↑126
↑127 /* timeout test */
↑128 if (atime - cache->last_timeout_test > MEMCACHE_TIMEOUT_INTERVAL) {
↑129 memcache_entry_t *entry;
↑130 struct memcache_entry_list *list;
↑131
↑132 for (;;) {
↑133 entry = TAILQ_FIRST(&cache->timeout);
↑134 if (NULL == entry)
↑135 break;
↑136
↑137 if (atime - entry->atime < MEMCACHE_TIMEOUT)
↑138 break;
↑139 #if 0
↑140 printf ("%s(): free(%p) size(%zu) usage(%zu/%zu)\n",
↑141 __FUNCTION__,
↑142 (void *)entry,
↑143 entry->size,
↑144 cache->usage, cache->limit);
↑145 #endif
↑146
↑147 list = &cache->buckets[entry->size % cache->nbuckets];
↑148
↑149 TAILQ_REMOVE(list, entry, buckets);
↑150 TAILQ_REMOVE(&cache->timeout, entry, timeout);
↑151
↑152 cache->usage -= entry->size;
↑153 --cache->nelements;
↑154
↑155 free (entry);
↑156 }
↑157
↑158
↑159 cache->last_timeout_test = atime;
↑160
↑161 }
↑162
↑163 if (atime - cache->last_reset > MEMCACHE_RESET_INTERVAL) {
↑164 #if 0
↑165 printf ("%s(): reset() usage(%zu/%zu)\n",
↑166 __FUNCTION__,
↑167 cache->usage, cache->limit);
↑168 #endif
↑169
↑170 if (cache->nbuckets > 15) {
↑171 if (0 != memcache_resize (cache, 0)) {
↑172 }
↑173 }
↑174
↑175 cache->last_reset = atime;
↑176 }
↑177
↑178 return;
↑179
↑180 out_free:
↑181 free (ptr);
↑182 return;
↑183 }
↑184
↑185 static int memcache_resize (memcache_t *cache, int grow)
↑186 {
↑187 size_t nbuckets;
↑188 struct memcache_entry_list *buckets;
↑189 size_t i;
↑190
↑191 if (cache->nbuckets) {
↑192 if (grow)
↑193 nbuckets = cache->nbuckets * 2;
↑194 else
↑195 nbuckets = 15;
↑196 } else {
↑197 nbuckets = 15;
↑198 }
↑199
↑200 #if 0
↑201 printf ("%s(): %zu -> %zu\n", __FUNCTION__, cache->nbuckets, nbuckets);
↑202 #endif
↑203
↑204 /*
↑205 *
↑206 * init new buckets
↑207 *
↑208 */
↑209
↑210 buckets = malloc (nbuckets * sizeof(*buckets) );
↑211 if (NULL == buckets)
↑212 return -1;
↑213
↑214 for (i=0; i<nbuckets; ++i) {
↑215 TAILQ_INIT(&buckets[i]);
↑216 }
↑217
↑218 /*
↑219 *
↑220 * rehash old buckets
↑221 *
↑222 */
↑223
↑224 if (cache->buckets) {
↑225 for (i=0; i<cache->nbuckets; ++i) {
↑226 struct memcache_entry_list *list_src, *list_dst;
↑227 struct memcache_entry *entry;
↑228
↑229 list_src = &cache->buckets[i];
↑230
↑231 for (;;) {
↑232 entry = TAILQ_FIRST(list_src);
↑233
↑234 if (NULL == entry)
↑235 break;
↑236
↑237 TAILQ_REMOVE (list_src,entry,buckets);
↑238
↑239 list_dst = &(buckets[entry->size % nbuckets]);
↑240
↑241 TAILQ_INSERT_TAIL (list_dst,entry,buckets);
↑242 }
↑243 }
↑244
↑245 free (cache->buckets);
↑246 }
↑247
↑248 cache->buckets = buckets;
↑249 cache->nbuckets = nbuckets;
↑250
↑251 return 0;
↑252 }
syntax highlighted by Code2HTML, v. 0.9.1