xref: /memcached-1.4.29/items.c (revision 74e80c7b)
1 /* -*- Mode: C; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2 /* $Id$ */
3 #include "memcached.h"
4 #include <sys/stat.h>
5 #include <sys/socket.h>
6 #include <sys/signal.h>
7 #include <sys/resource.h>
8 #include <fcntl.h>
9 #include <netinet/in.h>
10 #include <errno.h>
11 #include <stdlib.h>
12 #include <stdio.h>
13 #include <string.h>
14 #include <time.h>
15 #include <assert.h>
16 
17 /* Forward Declarations */
18 static void item_link_q(item *it);
19 static void item_unlink_q(item *it);
20 
21 /*
22  * We only reposition items in the LRU queue if they haven't been repositioned
23  * in this many seconds. That saves us from churning on frequently-accessed
24  * items.
25  */
26 #define ITEM_UPDATE_INTERVAL 60
27 
28 #define LARGEST_ID 255
29 typedef struct {
30     unsigned int evicted;
31     rel_time_t evicted_time;
32     unsigned int outofmemory;
33 } itemstats_t;
34 
35 static item *heads[LARGEST_ID];
36 static item *tails[LARGEST_ID];
37 static itemstats_t itemstats[LARGEST_ID];
38 static unsigned int sizes[LARGEST_ID];
39 
40 void item_init(void) {
41     int i;
42     memset(itemstats, 0, sizeof(itemstats_t) * LARGEST_ID);
43     for(i = 0; i < LARGEST_ID; i++) {
44         heads[i] = NULL;
45         tails[i] = NULL;
46         sizes[i] = 0;
47     }
48 }
49 
50 /* Get the next CAS id for a new item. */
51 uint64_t get_cas_id(void) {
52     static uint64_t cas_id = 0;
53     return ++cas_id;
54 }
55 
56 /* Enable this for reference-count debugging. */
57 #if 0
58 # define DEBUG_REFCNT(it,op) \
59                 fprintf(stderr, "item %x refcnt(%c) %d %c%c%c\n", \
60                         it, op, it->refcount, \
61                         (it->it_flags & ITEM_LINKED) ? 'L' : ' ', \
62                         (it->it_flags & ITEM_SLABBED) ? 'S' : ' ')
63 #else
64 # define DEBUG_REFCNT(it,op) while(0)
65 #endif
66 
67 /**
68  * Generates the variable-sized part of the header for an object.
69  *
70  * key     - The key
71  * nkey    - The length of the key
72  * flags   - key flags
73  * nbytes  - Number of bytes to hold value and addition CRLF terminator
74  * suffix  - Buffer for the "VALUE" line suffix (flags, size).
75  * nsuffix - The length of the suffix is stored here.
76  *
77  * Returns the total size of the header.
78  */
79 static size_t item_make_header(const uint8_t nkey, const int flags, const int nbytes,
80                      char *suffix, uint8_t *nsuffix) {
81     /* suffix is defined at 40 chars elsewhere.. */
82     *nsuffix = (uint8_t) snprintf(suffix, 40, " %d %d\r\n", flags, nbytes - 2);
83     return sizeof(item) + nkey + *nsuffix + nbytes;
84 }
85 
86 /*@null@*/
87 item *do_item_alloc(char *key, const size_t nkey, const int flags, const rel_time_t exptime, const int nbytes) {
88     uint8_t nsuffix;
89     item *it;
90     char suffix[40];
91     size_t ntotal = item_make_header(nkey + 1, flags, nbytes, suffix, &nsuffix);
92     if (settings.use_cas) {
93         ntotal += sizeof(uint64_t);
94     }
95 
96     unsigned int id = slabs_clsid(ntotal);
97     if (id == 0)
98         return 0;
99 
100     it = slabs_alloc(ntotal, id);
101     if (it == 0) {
102         int tries = 50;
103         item *search;
104 
105         /* If requested to not push old items out of cache when memory runs out,
106          * we're out of luck at this point...
107          */
108 
109         if (settings.evict_to_free == 0) {
110             itemstats[id].outofmemory++;
111             return NULL;
112         }
113 
114         /*
115          * try to get one off the right LRU
116          * don't necessariuly unlink the tail because it may be locked: refcount>0
117          * search up from tail an item with refcount==0 and unlink it; give up after 50
118          * tries
119          */
120 
121         if (tails[id] == 0) {
122             itemstats[id].outofmemory++;
123             return NULL;
124         }
125 
126         for (search = tails[id]; tries > 0 && search != NULL; tries--, search=search->prev) {
127             if (search->refcount == 0) {
128                 if (search->exptime == 0 || search->exptime > current_time) {
129                     itemstats[id].evicted++;
130                     itemstats[id].evicted_time = current_time - search->time;
131                     STATS_LOCK();
132                     stats.evictions++;
133                     STATS_UNLOCK();
134                 }
135                 do_item_unlink(search);
136                 break;
137             }
138         }
139         it = slabs_alloc(ntotal, id);
140         if (it == 0) {
141             itemstats[id].outofmemory++;
142             return NULL;
143         }
144     }
145 
146     assert(it->slabs_clsid == 0);
147 
148     it->slabs_clsid = id;
149 
150     assert(it != heads[it->slabs_clsid]);
151 
152     it->next = it->prev = it->h_next = 0;
153     it->refcount = 1;     /* the caller will have a reference */
154     DEBUG_REFCNT(it, '*');
155     it->it_flags = settings.use_cas ? ITEM_CAS : 0;
156     it->nkey = nkey;
157     it->nbytes = nbytes;
158     memcpy(ITEM_key(it), key, nkey);
159     it->exptime = exptime;
160     memcpy(ITEM_suffix(it), suffix, (size_t)nsuffix);
161     it->nsuffix = nsuffix;
162     return it;
163 }
164 
165 void item_free(item *it) {
166     size_t ntotal = ITEM_ntotal(it);
167     unsigned int clsid;
168     assert((it->it_flags & ITEM_LINKED) == 0);
169     assert(it != heads[it->slabs_clsid]);
170     assert(it != tails[it->slabs_clsid]);
171     assert(it->refcount == 0);
172 
173     /* so slab size changer can tell later if item is already free or not */
174     clsid = it->slabs_clsid;
175     it->slabs_clsid = 0;
176     it->it_flags |= ITEM_SLABBED;
177     DEBUG_REFCNT(it, 'F');
178     slabs_free(it, ntotal, clsid);
179 }
180 
181 /**
182  * Returns true if an item will fit in the cache (its size does not exceed
183  * the maximum for a cache entry.)
184  */
185 bool item_size_ok(const size_t nkey, const int flags, const int nbytes) {
186     char prefix[40];
187     uint8_t nsuffix;
188 
189     return slabs_clsid(item_make_header(nkey + 1, flags, nbytes,
190                                         prefix, &nsuffix)) != 0;
191 }
192 
193 static void item_link_q(item *it) { /* item is the new head */
194     item **head, **tail;
195     /* always true, warns: assert(it->slabs_clsid <= LARGEST_ID); */
196     assert((it->it_flags & ITEM_SLABBED) == 0);
197 
198     head = &heads[it->slabs_clsid];
199     tail = &tails[it->slabs_clsid];
200     assert(it != *head);
201     assert((*head && *tail) || (*head == 0 && *tail == 0));
202     it->prev = 0;
203     it->next = *head;
204     if (it->next) it->next->prev = it;
205     *head = it;
206     if (*tail == 0) *tail = it;
207     sizes[it->slabs_clsid]++;
208     return;
209 }
210 
211 static void item_unlink_q(item *it) {
212     item **head, **tail;
213     /* always true, warns: assert(it->slabs_clsid <= LARGEST_ID); */
214     head = &heads[it->slabs_clsid];
215     tail = &tails[it->slabs_clsid];
216 
217     if (*head == it) {
218         assert(it->prev == 0);
219         *head = it->next;
220     }
221     if (*tail == it) {
222         assert(it->next == 0);
223         *tail = it->prev;
224     }
225     assert(it->next != it);
226     assert(it->prev != it);
227 
228     if (it->next) it->next->prev = it->prev;
229     if (it->prev) it->prev->next = it->next;
230     sizes[it->slabs_clsid]--;
231     return;
232 }
233 
234 int do_item_link(item *it) {
235     MEMCACHED_ITEM_LINK(ITEM_key(it), it->nkey, it->nbytes);
236     assert((it->it_flags & (ITEM_LINKED|ITEM_SLABBED)) == 0);
237     assert(it->nbytes < (1024 * 1024));  /* 1MB max size */
238     it->it_flags |= ITEM_LINKED;
239     it->time = current_time;
240     assoc_insert(it);
241 
242     STATS_LOCK();
243     stats.curr_bytes += ITEM_ntotal(it);
244     stats.curr_items += 1;
245     stats.total_items += 1;
246     STATS_UNLOCK();
247 
248     /* Allocate a new CAS ID on link. */
249     ITEM_set_cas(it, (settings.use_cas) ? get_cas_id() : 0);
250 
251     item_link_q(it);
252 
253     return 1;
254 }
255 
256 void do_item_unlink(item *it) {
257     MEMCACHED_ITEM_UNLINK(ITEM_key(it), it->nkey, it->nbytes);
258     if ((it->it_flags & ITEM_LINKED) != 0) {
259         it->it_flags &= ~ITEM_LINKED;
260         STATS_LOCK();
261         stats.curr_bytes -= ITEM_ntotal(it);
262         stats.curr_items -= 1;
263         STATS_UNLOCK();
264         assoc_delete(ITEM_key(it), it->nkey);
265         item_unlink_q(it);
266         if (it->refcount == 0) item_free(it);
267     }
268 }
269 
270 void do_item_remove(item *it) {
271     MEMCACHED_ITEM_REMOVE(ITEM_key(it), it->nkey, it->nbytes);
272     assert((it->it_flags & ITEM_SLABBED) == 0);
273     if (it->refcount != 0) {
274         it->refcount--;
275         DEBUG_REFCNT(it, '-');
276     }
277     if (it->refcount == 0 && (it->it_flags & ITEM_LINKED) == 0) {
278         item_free(it);
279     }
280 }
281 
282 void do_item_update(item *it) {
283     MEMCACHED_ITEM_UPDATE(ITEM_key(it), it->nkey, it->nbytes);
284     if (it->time < current_time - ITEM_UPDATE_INTERVAL) {
285         assert((it->it_flags & ITEM_SLABBED) == 0);
286 
287         if ((it->it_flags & ITEM_LINKED) != 0) {
288             item_unlink_q(it);
289             it->time = current_time;
290             item_link_q(it);
291         }
292     }
293 }
294 
295 int do_item_replace(item *it, item *new_it) {
296     MEMCACHED_ITEM_REPLACE(ITEM_key(it), it->nkey, it->nbytes,
297                            ITEM_key(new_it), new_it->nkey, new_it->nbytes);
298     assert((it->it_flags & ITEM_SLABBED) == 0);
299 
300     do_item_unlink(it);
301     return do_item_link(new_it);
302 }
303 
304 /*@null@*/
305 char *do_item_cachedump(const unsigned int slabs_clsid, const unsigned int limit, unsigned int *bytes) {
306     unsigned int memlimit = 2 * 1024 * 1024;   /* 2MB max response size */
307     char *buffer;
308     unsigned int bufcurr;
309     item *it;
310     unsigned int len;
311     unsigned int shown = 0;
312     char key_temp[KEY_MAX_LENGTH + 1];
313     char temp[512];
314 
315     if (slabs_clsid > LARGEST_ID) return NULL;
316     it = heads[slabs_clsid];
317 
318     buffer = malloc((size_t)memlimit);
319     if (buffer == 0) return NULL;
320     bufcurr = 0;
321 
322     while (it != NULL && (limit == 0 || shown < limit)) {
323         assert(it->nkey <= KEY_MAX_LENGTH);
324         /* Copy the key since it may not be null-terminated in the struct */
325         strncpy(key_temp, ITEM_key(it), it->nkey);
326         key_temp[it->nkey] = 0x00; /* terminate */
327         len = snprintf(temp, sizeof(temp), "ITEM %s [%d b; %lu s]\r\n",
328                        key_temp, it->nbytes - 2,
329                        (unsigned long)it->exptime + stats.started);
330         if (bufcurr + len + 6 > memlimit)  /* 6 is END\r\n\0 */
331             break;
332         strcpy(buffer + bufcurr, temp);
333         bufcurr += len;
334         shown++;
335         it = it->next;
336     }
337 
338     memcpy(buffer + bufcurr, "END\r\n", 6);
339     bufcurr += 5;
340 
341     *bytes = bufcurr;
342     return buffer;
343 }
344 
345 char *do_item_stats(uint32_t (*add_stats)(char *buf,
346                     const char *key, const uint16_t klen, const char *val,
347                     const uint32_t vlen, void *cookie), void *c, int *bytes) {
348 
349     size_t bufleft = (size_t) LARGEST_ID * 240;
350     char *buffer = malloc(bufleft);
351     char *bufcurr = buffer;
352     rel_time_t now = current_time;
353     protocol_binary_response_header *header;
354     int hdrsiz = sizeof(header->response);
355     int i, linelen = 0;
356 
357     if (buffer == NULL) {
358         *bytes = -1;
359         return NULL;
360     }
361 
362     for (i = 0; i < LARGEST_ID; i++) {
363         if (tails[i] != NULL) {
364             char key[128];
365             char val[256];
366             uint32_t nbytes = 0;
367 
368             sprintf(key, "items:%d:number", i);
369             sprintf(val, "%u", sizes[i]);
370             nbytes = add_stats(bufcurr, key, strlen(key), val, strlen(val), c);
371             linelen += nbytes;
372             bufcurr += nbytes;
373 
374             sprintf(key, "items:%d:age", i);
375             sprintf(val, "%u", now - tails[i]->time);
376             nbytes = add_stats(bufcurr, key, strlen(key), val, strlen(val), c);
377             linelen += nbytes;
378             bufcurr += nbytes;
379 
380             sprintf(key, "items:%d:evicted", i);
381             sprintf(val, "%u", itemstats[i].evicted);
382             nbytes = add_stats(bufcurr, key, strlen(key), val, strlen(val), c);
383             linelen += nbytes;
384             bufcurr += nbytes;
385 
386             sprintf(key, "items:%d:evicted_time", i);
387             sprintf(val, "%u", itemstats[i].evicted_time);
388             nbytes = add_stats(bufcurr, key, strlen(key), val, strlen(val), c);
389             linelen += nbytes;
390             bufcurr += nbytes;
391 
392             sprintf(key, "items:%d:outofmemory", i);
393             sprintf(val, "%u", itemstats[i].outofmemory);
394             nbytes = add_stats(bufcurr, key, strlen(key), val, strlen(val), c);
395             linelen += nbytes;
396             bufcurr += nbytes;
397 
398             /* check whether binary protocol terminator will fit */
399             if (linelen + hdrsiz < bufleft) {
400                 bufleft -= linelen;
401             } else {
402                 free(buffer);
403                 return NULL;
404             }
405         }
406     }
407 
408     /* getting here means both ascii and binary terminators fit */
409     linelen += add_stats(bufcurr, NULL, 0, NULL, 0, c);
410     *bytes = linelen;
411 
412     return buffer;
413 }
414 
415 /** dumps out a list of objects of each size, with granularity of 32 bytes */
416 /*@null@*/
417 char *do_item_stats_sizes(uint32_t (*add_stats)(char *buf,
418                           const char *key, const uint16_t klen, const char *val,
419                           const uint32_t vlen, void *cookie), void *c, int *bytes) {
420 
421     const int num_buckets = 32768;   /* max 1MB object, divided into 32 bytes size buckets */
422     unsigned int *histogram = (unsigned int *)malloc((size_t)num_buckets * sizeof(int));
423     char *buf = (char *)malloc(2 * 1024 * 1024); /* 2MB max response size */
424     char *ptr = buf;
425     uint32_t nbytes, linelen = 0;
426     int i;
427 
428     if (histogram == 0 || buf == 0) {
429         if (histogram) free(histogram);
430         if (buf) free(buf);
431         *bytes = -1;
432         return NULL;
433     }
434 
435     /* build the histogram */
436     memset(histogram, 0, (size_t)num_buckets * sizeof(int));
437     for (i = 0; i < LARGEST_ID; i++) {
438         item *iter = heads[i];
439         while (iter) {
440             int ntotal = ITEM_ntotal(iter);
441             int bucket = ntotal / 32;
442             if ((ntotal % 32) != 0) bucket++;
443             if (bucket < num_buckets) histogram[bucket]++;
444             iter = iter->next;
445         }
446     }
447 
448     /* write the buffer */
449     *bytes = 0;
450     char key[128];
451     char val[128];
452 
453     for (i = 0; i < num_buckets; i++) {
454         if (histogram[i] != 0) {
455             sprintf(key, "%d", i * 32);
456             sprintf(val, "%u", histogram[i]);
457             nbytes = add_stats(ptr, key, strlen(key), val, strlen(val), c);
458             linelen += nbytes;
459             ptr += nbytes;
460         }
461     }
462 
463     nbytes = add_stats(ptr, NULL, 0, NULL, 0, c);
464     *bytes = linelen + nbytes;
465 
466     free(histogram);
467     return buf;
468 }
469 
470 /** wrapper around assoc_find which does the lazy expiration logic */
471 item *do_item_get(const char *key, const size_t nkey) {
472     item *it = assoc_find(key, nkey);
473     if (it != NULL && settings.oldest_live != 0 && settings.oldest_live <= current_time &&
474         it->time <= settings.oldest_live) {
475         do_item_unlink(it);           /* MTSAFE - cache_lock held */
476         it = NULL;
477     }
478     if (it != NULL && it->exptime != 0 && it->exptime <= current_time) {
479         do_item_unlink(it);           /* MTSAFE - cache_lock held */
480         it = NULL;
481     }
482 
483     if (it != NULL) {
484         it->refcount++;
485         DEBUG_REFCNT(it, '+');
486     }
487     return it;
488 }
489 
490 /** returns an item whether or not it's expired. */
491 item *do_item_get_nocheck(const char *key, const size_t nkey) {
492     item *it = assoc_find(key, nkey);
493     if (it) {
494         it->refcount++;
495         DEBUG_REFCNT(it, '+');
496     }
497     return it;
498 }
499 
500 /* expires items that are more recent than the oldest_live setting. */
501 void do_item_flush_expired(void) {
502     int i;
503     item *iter, *next;
504     if (settings.oldest_live == 0)
505         return;
506     for (i = 0; i < LARGEST_ID; i++) {
507         /* The LRU is sorted in decreasing time order, and an item's timestamp
508          * is never newer than its last access time, so we only need to walk
509          * back until we hit an item older than the oldest_live time.
510          * The oldest_live checking will auto-expire the remaining items.
511          */
512         for (iter = heads[i]; iter != NULL; iter = next) {
513             if (iter->time >= settings.oldest_live) {
514                 next = iter->next;
515                 if ((iter->it_flags & ITEM_SLABBED) == 0) {
516                     do_item_unlink(iter);
517                 }
518             } else {
519                 /* We've hit the first old item. Continue to the next queue. */
520                 break;
521             }
522         }
523     }
524 }
525