Memcached Slabs

来源:互联网 发布:数据侠客行 笔趣阁 编辑:程序博客网 时间:2024/05/01 13:59

1. slabs.h

/* slabs memory allocation */

view plaincopy to clipboardprint?
  1. /** Init the subsystem. 1st argument is the limit on no. of bytes to allocate, 
  2.     0 if no limit. 2nd argument is the growth factor; each slab will use a chunk 
  3.     size equal to the previous slab's chunk size times this factor. 
  4.     3rd argument specifies if the slab allocator should allocate all memory 
  5.     up front (if true), or allocate memory in chunks as it is needed (if false) 
  6. */  
  7. void slabs_init(const size_t limit, const double factor, const bool prealloc);  
  8. /** 
  9.  * Given object size, return id to use when allocating/freeing memory for object 
  10.  * 0 means error: can't store such a large object 
  11.  */  
  12. unsigned int slabs_clsid(const size_t size);  
  13. /** Allocate object of given length. 0 on error */ /*@null@*/  
  14. void *do_slabs_alloc(const size_t size, unsigned int id);  
  15. /** Free previously allocated object */  
  16. void do_slabs_free(void *ptr, size_t size, unsigned int id);  

 

2. slabs.c

view plaincopy to clipboardprint?
  1. /* -*- Mode: C; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */  
  2. /* 
  3.  * Slabs memory allocation, based on powers-of-N. Slabs are up to 1MB in size 
  4.  * and are divided into chunks. The chunk sizes start off at the size of the 
  5.  * "item" structure plus space for a small key and value. They increase by 
  6.  * a multiplier factor from there, up to half the maximum slab size. The last 
  7.  * slab size is always 1MB, since that's the maximum item size allowed by the 
  8.  * memcached protocol. 
  9.  * 
  10.  */  
  11.   
  12. #define POWER_SMALLEST 1  
  13. #define POWER_LARGEST  200  
  14. #define POWER_BLOCK 1048576  
  15. #define CHUNK_ALIGN_BYTES 8  
  16. #define DONT_PREALLOC_SLABS  
  17. /* powers-of-N allocation structures */  
  18. typedef struct {  
  19.     unsigned int size;      /* sizes of items */  
  20.     unsigned int perslab;   /* how many items per slab */  
  21.     void **slots;           /* list of item ptrs */  
  22.     unsigned int sl_total;  /* size of previous array */  
  23.     unsigned int sl_curr;   /* first free slot */  
  24.     void *end_page_ptr;         /* pointer to next free item at end of page, or 0 */  
  25.     unsigned int end_page_free; /* number of items remaining at end of last alloced page */  
  26.     unsigned int slabs;     /* how many slabs were allocated for this class */  
  27.     void **slab_list;       /* array of slab pointers */  
  28.     unsigned int list_size; /* size of prev array */  
  29.     unsigned int killing;  /* index+1 of dying slab, or zero if none */  
  30. } slabclass_t;  
  31. static slabclass_t slabclass[POWER_LARGEST + 1];  
  32. static size_t mem_limit = 0;  
  33. static size_t mem_malloced = 0;  
  34. static int power_largest;  
  35. static void *mem_base = NULL;  
  36. static void *mem_current = NULL;  
  37. static size_t mem_avail = 0;  
  38. /* 
  39.  * Forward Declarations 
  40.  */  
  41. static int do_slabs_newslab(const unsigned int id);  
  42. static void *memory_allocate(size_t size);  
  43. #ifndef DONT_PREALLOC_SLABS  
  44. /* Preallocate as many slab pages as possible (called from slabs_init) 
  45.    on start-up, so users don't get confused out-of-memory errors when 
  46.    they do have free (in-slab) space, but no space to make new slabs. 
  47.    if maxslabs is 18 (POWER_LARGEST - POWER_SMALLEST + 1), then all 
  48.    slab types can be made.  if max memory is less than 18 MB, only the 
  49.    smaller ones will be made.  */  
  50. static void slabs_preallocate (const unsigned int maxslabs);  
  51. #endif  

 

view plaincopy to clipboardprint?
  1. /* 
  2.  * Figures out which slab class (chunk size) is required to store an item of 
  3.  * a given size. 
  4.  * 
  5.  * Given object size, return id to use when allocating/freeing memory for object 
  6.  * 0 means error: can't store such a large object 
  7.  */  
  8. unsigned int slabs_clsid(const size_t size) {  
  9.     int res = POWER_SMALLEST;  
  10.     if (size == 0)  
  11.         return 0;  
  12.     while (size > slabclass[res].size)  
  13.         if (res++ == power_largest)     /* won't fit in the biggest slab */  
  14.             return 0;  
  15.     return res;  
  16. }  

 

view plaincopy to clipboardprint?
  1. /** 
  2.  * Determines the chunk sizes and initializes the slab class descriptors 
  3.  * accordingly. 
  4.  */  
  5. void slabs_init(const size_t limit, const double factor, const bool prealloc) {  
  6.     int i = POWER_SMALLEST - 1;  
  7.     unsigned int size = sizeof(item) + settings.chunk_size;  
  8.     /* Factor of 2.0 means use the default memcached behavior */  
  9.     if (factor == 2.0 && size < 128)  
  10.         size = 128;  
  11.     mem_limit = limit;  
  12.     if (prealloc) {  
  13.         /* Allocate everything in a big chunk with malloc */  
  14.         mem_base = malloc(mem_limit);  
  15.         if (mem_base != NULL) {  
  16.             mem_current = mem_base;  
  17.             mem_avail = mem_limit;  
  18.         } else {  
  19.             fprintf(stderr, "Warning: Failed to allocate requested memory in"  
  20.                     " one large chunk./nWill allocate in smaller chunks/n");  
  21.         }  
  22.     }  
  23.     memset(slabclass, 0, sizeof(slabclass));  
  24.     while (++i < POWER_LARGEST && size <= POWER_BLOCK / 2) {  
  25.         /* Make sure items are always n-byte aligned */  
  26.         if (size % CHUNK_ALIGN_BYTES)  
  27.             size += CHUNK_ALIGN_BYTES - (size % CHUNK_ALIGN_BYTES);  
  28.         slabclass[i].size = size;  
  29.         slabclass[i].perslab = POWER_BLOCK / slabclass[i].size;  
  30.         size *= factor;  
  31.         if (settings.verbose > 1) {  
  32.             fprintf(stderr, "slab class %3d: chunk size %6u perslab %5u/n",  
  33.                     i, slabclass[i].size, slabclass[i].perslab);  
  34.         }  
  35.     }  
  36.     power_largest = i;  
  37.     slabclass[power_largest].size = POWER_BLOCK;  
  38.     slabclass[power_largest].perslab = 1;  
  39.     /* for the test suite:  faking of how much we've already malloc'd */  
  40.     {  
  41.         char *t_initial_malloc = getenv("T_MEMD_INITIAL_MALLOC");  
  42.         if (t_initial_malloc) {  
  43.             mem_malloced = (size_t)atol(t_initial_malloc);  
  44.         }  
  45.     }  
  46. #ifndef DONT_PREALLOC_SLABS  
  47.     {  
  48.         char *pre_alloc = getenv("T_MEMD_SLABS_ALLOC");  
  49.         if (pre_alloc == NULL || atoi(pre_alloc) != 0) {  
  50.             slabs_preallocate(power_largest);  
  51.         }  
  52.     }  
  53. #endif  
  54. }  

 

view plaincopy to clipboardprint?
  1. #ifndef DONT_PREALLOC_SLABS  
  2. static void slabs_preallocate (const unsigned int maxslabs) {  
  3.     int i;  
  4.     unsigned int prealloc = 0;  
  5.     /* pre-allocate a 1MB slab in every size class so people don't get 
  6.        confused by non-intuitive "SERVER_ERROR out of memory" 
  7.        messages.  this is the most common question on the mailing 
  8.        list.  if you really don't want this, you can rebuild without 
  9.        these three lines.  */  
  10.     for (i = POWER_SMALLEST; i <= POWER_LARGEST; i++) {  
  11.         if (++prealloc > maxslabs)  
  12.             return;  
  13.         do_slabs_newslab(i);  
  14.     }  
  15. }  
  16. #endif  

 

view plaincopy to clipboardprint?
  1. static int grow_slab_list (const unsigned int id) {  
  2.     slabclass_t *p = &slabclass[id];  
  3.     if (p->slabs == p->list_size) {  
  4.         size_t new_size =  (p->list_size != 0) ? p->list_size * 2 : 16;  
  5.         void *new_list = realloc(p->slab_list, new_size * sizeof(void *));  
  6.         if (new_list == 0) return 0;  
  7.         p->list_size = new_size;  
  8.         p->slab_list = new_list;  
  9.     }  
  10.     return 1;  
  11. }  


view plaincopy to clipboardprint?
  1. static int do_slabs_newslab(const unsigned int id) {  
  2.     slabclass_t *p = &slabclass[id];  
  3. #ifdef ALLOW_SLABS_REASSIGN  
  4.     int len = POWER_BLOCK;  
  5. #else  
  6.     int len = p->size * p->perslab;  
  7. #endif  
  8.     char *ptr;  
  9.     if (mem_limit && mem_malloced + len > mem_limit && p->slabs > 0)  
  10.         return 0;  
  11.     if (grow_slab_list(id) == 0) return 0;  
  12.     ptr = memory_allocate((size_t)len);  
  13.     if (ptr == 0) return 0;  
  14.     memset(ptr, 0, (size_t)len);  
  15.     p->end_page_ptr = ptr;  
  16.     p->end_page_free = p->perslab;  
  17.     p->slab_list[p->slabs++] = ptr;  
  18.     mem_malloced += len;  
  19.     return 1;  
  20. }  

 

view plaincopy to clipboardprint?
  1. /*@null@*/  
  2. void *do_slabs_alloc(const size_t size, unsigned int id) {  
  3.     slabclass_t *p;  
  4.     if (id < POWER_SMALLEST || id > power_largest)  
  5.         return NULL;  
  6.     p = &slabclass[id];  
  7.     assert(p->sl_curr == 0 || ((item *)p->slots[p->sl_curr - 1])->slabs_clsid == 0);  
  8. #ifdef USE_SYSTEM_MALLOC  
  9.     if (mem_limit && mem_malloced + size > mem_limit)  
  10.         return 0;  
  11.     mem_malloced += size;  
  12.     return malloc(size);  
  13. #endif  
  14.     /* fail unless we have space at the end of a recently allocated page, 
  15.        we have something on our freelist, or we could allocate a new page */  
  16.     if (! (p->end_page_ptr != 0 || p->sl_curr != 0 || do_slabs_newslab(id) != 0))  
  17.         return 0;  
  18.     /* return off our freelist, if we have one */  
  19.     if (p->sl_curr != 0)  
  20.         return p->slots[--p->sl_curr];  
  21.     /* if we recently allocated a whole page, return from that */  
  22.     if (p->end_page_ptr) {  
  23.         void *ptr = p->end_page_ptr;  
  24.         if (--p->end_page_free != 0) {  
  25.             p->end_page_ptr += p->size;  
  26.         } else {  
  27.             p->end_page_ptr = 0;  
  28.         }  
  29.         return ptr;  
  30.     }  
  31.     return NULL;  /* shouldn't ever get here */  
  32. }  

 

view plaincopy to clipboardprint?
  1. void do_slabs_free(void *ptr, const size_t size, unsigned int id) {  
  2.     slabclass_t *p;  
  3.     assert(((item *)ptr)->slabs_clsid == 0);  
  4.     assert(id >= POWER_SMALLEST && id <= power_largest);  
  5.     if (id < POWER_SMALLEST || id > power_largest)  
  6.         return;  
  7.     p = &slabclass[id];  
  8. #ifdef USE_SYSTEM_MALLOC  
  9.     mem_malloced -= size;  
  10.     free(ptr);  
  11.     return;  
  12. #endif  
  13.     if (p->sl_curr == p->sl_total) { /* need more space on the free list */  
  14.         int new_size = (p->sl_total != 0) ? p->sl_total * 2 : 16;  /* 16 is arbitrary */  
  15.         void **new_slots = realloc(p->slots, new_size * sizeof(void *));  
  16.         if (new_slots == 0)  
  17.             return;  
  18.         p->slots = new_slots;  
  19.         p->sl_total = new_size;  
  20.     }  
  21.     p->slots[p->sl_curr++] = ptr;  
  22.     return;  
  23. }  

 

view plaincopy to clipboardprint?
  1. static void *memory_allocate(size_t size) {  
  2.     void *ret;  
  3.     if (mem_base == NULL) {  
  4.         /* We are not using a preallocated large memory chunk */  
  5.         ret = malloc(size);  
  6.     } else {  
  7.         ret = mem_current;  
  8.         if (size > mem_avail) {  
  9.             return NULL;  
  10.         }  
  11.         /* mem_current pointer _must_ be aligned!!! */  
  12.         if (size % CHUNK_ALIGN_BYTES) {  
  13.             size += CHUNK_ALIGN_BYTES - (size % CHUNK_ALIGN_BYTES);  
  14.         }  
  15.         mem_current += size;  
  16.         if (size < mem_avail) {  
  17.             mem_avail -= size;  
  18.         } else {  
  19.             mem_avail = 0;  
  20.         }  
  21.     }  
  22.     return ret;  

http://blog.developers.api.sina.com.cn/?p=124