~brianaker/libmemcached/1164440

« back to all changes in this revision

Viewing changes to memcached/cache.c

Merge working tree with build tree.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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