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 #include "memcached.h" 11 #include <sys/stat.h> 12 #include <sys/socket.h> 13 #include <sys/signal.h> 14 #include <sys/resource.h> 15 #include <fcntl.h> 16 #include <netinet/in.h> 17 #include <errno.h> 18 #include <stdlib.h> 19 #include <stdio.h> 20 #include <string.h> 21 #include <assert.h> 22 #include <pthread.h> 23 24 /* powers-of-N allocation structures */ 25 26 typedef struct { 27 unsigned int size; /* sizes of items */ 28 unsigned int perslab; /* how many items per slab */ 29 30 void **slots; /* list of item ptrs */ 31 unsigned int sl_total; /* size of previous array */ 32 unsigned int sl_curr; /* first free slot */ 33 34 void *end_page_ptr; /* pointer to next free item at end of page, or 0 */ 35 unsigned int end_page_free; /* number of items remaining at end of last alloced page */ 36 37 unsigned int slabs; /* how many slabs were allocated for this class */ 38 39 void **slab_list; /* array of slab pointers */ 40 unsigned int list_size; /* size of prev array */ 41 42 unsigned int killing; /* index+1 of dying slab, or zero if none */ 43 size_t requested; /* The number of requested bytes */ 44 } slabclass_t; 45 46 static slabclass_t slabclass[MAX_NUMBER_OF_SLAB_CLASSES]; 47 static size_t mem_limit = 0; 48 static size_t mem_malloced = 0; 49 static int power_largest; 50 51 static void *mem_base = NULL; 52 static void *mem_current = NULL; 53 static size_t mem_avail = 0; 54 55 /** 56 * Access to the slab allocator is protected by this lock 57 */ 58 static pthread_mutex_t slabs_lock = PTHREAD_MUTEX_INITIALIZER; 59 60 /* 61 * Forward Declarations 62 */ 63 static int do_slabs_newslab(const unsigned int id); 64 static void *memory_allocate(size_t size); 65 66 #ifndef DONT_PREALLOC_SLABS 67 /* Preallocate as many slab pages as possible (called from slabs_init) 68 on start-up, so users don't get confused out-of-memory errors when 69 they do have free (in-slab) space, but no space to make new slabs. 70 if maxslabs is 18 (POWER_LARGEST - POWER_SMALLEST + 1), then all 71 slab types can be made. if max memory is less than 18 MB, only the 72 smaller ones will be made. */ 73 static void slabs_preallocate (const unsigned int maxslabs); 74 #endif 75 76 /* 77 * Figures out which slab class (chunk size) is required to store an item of 78 * a given size. 79 * 80 * Given object size, return id to use when allocating/freeing memory for object 81 * 0 means error: can't store such a large object 82 */ 83 84 unsigned int slabs_clsid(const size_t size) { 85 int res = POWER_SMALLEST; 86 87 if (size == 0) 88 return 0; 89 while (size > slabclass[res].size) 90 if (res++ == power_largest) /* won't fit in the biggest slab */ 91 return 0; 92 return res; 93 } 94 95 /** 96 * Determines the chunk sizes and initializes the slab class descriptors 97 * accordingly. 98 */ 99 void slabs_init(const size_t limit, const double factor, const bool prealloc) { 100 int i = POWER_SMALLEST - 1; 101 unsigned int size = sizeof(item) + settings.chunk_size; 102 103 /* Factor of 2.0 means use the default memcached behavior */ 104 if (factor == 2.0 && size < 128) 105 size = 128; 106 107 mem_limit = limit; 108 109 if (prealloc) { 110 /* Allocate everything in a big chunk with malloc */ 111 mem_base = malloc(mem_limit); 112 if (mem_base != NULL) { 113 mem_current = mem_base; 114 mem_avail = mem_limit; 115 } else { 116 fprintf(stderr, "Warning: Failed to allocate requested memory in" 117 " one large chunk.\nWill allocate in smaller chunks\n"); 118 } 119 } 120 121 memset(slabclass, 0, sizeof(slabclass)); 122 123 while (++i < POWER_LARGEST && size <= settings.item_size_max / 2) { 124 /* Make sure items are always n-byte aligned */ 125 if (size % CHUNK_ALIGN_BYTES) 126 size += CHUNK_ALIGN_BYTES - (size % CHUNK_ALIGN_BYTES); 127 128 slabclass[i].size = size; 129 slabclass[i].perslab = settings.item_size_max / slabclass[i].size; 130 size *= factor; 131 if (settings.verbose > 1) { 132 fprintf(stderr, "slab class %3d: chunk size %9u perslab %7u\n", 133 i, slabclass[i].size, slabclass[i].perslab); 134 } 135 } 136 137 power_largest = i; 138 slabclass[power_largest].size = settings.item_size_max; 139 slabclass[power_largest].perslab = 1; 140 if (settings.verbose > 1) { 141 fprintf(stderr, "slab class %3d: chunk size %9u perslab %7u\n", 142 i, slabclass[i].size, slabclass[i].perslab); 143 } 144 145 /* for the test suite: faking of how much we've already malloc'd */ 146 { 147 char *t_initial_malloc = getenv("T_MEMD_INITIAL_MALLOC"); 148 if (t_initial_malloc) { 149 mem_malloced = (size_t)atol(t_initial_malloc); 150 } 151 152 } 153 154 #ifndef DONT_PREALLOC_SLABS 155 { 156 char *pre_alloc = getenv("T_MEMD_SLABS_ALLOC"); 157 158 if (pre_alloc == NULL || atoi(pre_alloc) != 0) { 159 slabs_preallocate(power_largest); 160 } 161 } 162 #endif 163 } 164 165 #ifndef DONT_PREALLOC_SLABS 166 static void slabs_preallocate (const unsigned int maxslabs) { 167 int i; 168 unsigned int prealloc = 0; 169 170 /* pre-allocate a 1MB slab in every size class so people don't get 171 confused by non-intuitive "SERVER_ERROR out of memory" 172 messages. this is the most common question on the mailing 173 list. if you really don't want this, you can rebuild without 174 these three lines. */ 175 176 for (i = POWER_SMALLEST; i <= POWER_LARGEST; i++) { 177 if (++prealloc > maxslabs) 178 return; 179 do_slabs_newslab(i); 180 } 181 182 } 183 #endif 184 185 static int grow_slab_list (const unsigned int id) { 186 slabclass_t *p = &slabclass[id]; 187 if (p->slabs == p->list_size) { 188 size_t new_size = (p->list_size != 0) ? p->list_size * 2 : 16; 189 void *new_list = realloc(p->slab_list, new_size * sizeof(void *)); 190 if (new_list == 0) return 0; 191 p->list_size = new_size; 192 p->slab_list = new_list; 193 } 194 return 1; 195 } 196 197 static int do_slabs_newslab(const unsigned int id) { 198 slabclass_t *p = &slabclass[id]; 199 #ifdef ALLOW_SLABS_REASSIGN 200 int len = settings.item_size_max; 201 #else 202 int len = p->size * p->perslab; 203 #endif 204 char *ptr; 205 206 if ((mem_limit && mem_malloced + len > mem_limit && p->slabs > 0) || 207 (grow_slab_list(id) == 0) || 208 ((ptr = memory_allocate((size_t)len)) == 0)) { 209 210 MEMCACHED_SLABS_SLABCLASS_ALLOCATE_FAILED(id); 211 return 0; 212 } 213 214 memset(ptr, 0, (size_t)len); 215 p->end_page_ptr = ptr; 216 p->end_page_free = p->perslab; 217 218 p->slab_list[p->slabs++] = ptr; 219 mem_malloced += len; 220 MEMCACHED_SLABS_SLABCLASS_ALLOCATE(id); 221 222 return 1; 223 } 224 225 /*@null@*/ 226 static void *do_slabs_alloc(const size_t size, unsigned int id) { 227 slabclass_t *p; 228 void *ret = NULL; 229 230 if (id < POWER_SMALLEST || id > power_largest) { 231 MEMCACHED_SLABS_ALLOCATE_FAILED(size, 0); 232 return NULL; 233 } 234 235 p = &slabclass[id]; 236 assert(p->sl_curr == 0 || ((item *)p->slots[p->sl_curr - 1])->slabs_clsid == 0); 237 238 #ifdef USE_SYSTEM_MALLOC 239 if (mem_limit && mem_malloced + size > mem_limit) { 240 MEMCACHED_SLABS_ALLOCATE_FAILED(size, id); 241 return 0; 242 } 243 mem_malloced += size; 244 ret = malloc(size); 245 MEMCACHED_SLABS_ALLOCATE(size, id, 0, ret); 246 return ret; 247 #endif 248 249 /* fail unless we have space at the end of a recently allocated page, 250 we have something on our freelist, or we could allocate a new page */ 251 if (! (p->end_page_ptr != 0 || p->sl_curr != 0 || 252 do_slabs_newslab(id) != 0)) { 253 /* We don't have more memory available */ 254 ret = NULL; 255 } else if (p->sl_curr != 0) { 256 /* return off our freelist */ 257 ret = p->slots[--p->sl_curr]; 258 } else { 259 /* if we recently allocated a whole page, return from that */ 260 assert(p->end_page_ptr != NULL); 261 ret = p->end_page_ptr; 262 if (--p->end_page_free != 0) { 263 p->end_page_ptr = ((caddr_t)p->end_page_ptr) + p->size; 264 } else { 265 p->end_page_ptr = 0; 266 } 267 } 268 269 if (ret) { 270 p->requested += size; 271 MEMCACHED_SLABS_ALLOCATE(size, id, p->size, ret); 272 } else { 273 MEMCACHED_SLABS_ALLOCATE_FAILED(size, id); 274 } 275 276 return ret; 277 } 278 279 static void do_slabs_free(void *ptr, const size_t size, unsigned int id) { 280 slabclass_t *p; 281 282 assert(((item *)ptr)->slabs_clsid == 0); 283 assert(id >= POWER_SMALLEST && id <= power_largest); 284 if (id < POWER_SMALLEST || id > power_largest) 285 return; 286 287 MEMCACHED_SLABS_FREE(size, id, ptr); 288 p = &slabclass[id]; 289 290 #ifdef USE_SYSTEM_MALLOC 291 mem_malloced -= size; 292 free(ptr); 293 return; 294 #endif 295 296 if (p->sl_curr == p->sl_total) { /* need more space on the free list */ 297 int new_size = (p->sl_total != 0) ? p->sl_total * 2 : 16; /* 16 is arbitrary */ 298 void **new_slots = realloc(p->slots, new_size * sizeof(void *)); 299 if (new_slots == 0) 300 return; 301 p->slots = new_slots; 302 p->sl_total = new_size; 303 } 304 p->slots[p->sl_curr++] = ptr; 305 p->requested -= size; 306 return; 307 } 308 309 static int nz_strcmp(int nzlength, const char *nz, const char *z) { 310 int zlength=strlen(z); 311 return (zlength == nzlength) && (strncmp(nz, z, zlength) == 0) ? 0 : -1; 312 } 313 314 bool get_stats(const char *stat_type, int nkey, ADD_STAT add_stats, void *c) { 315 bool ret = true; 316 317 if (add_stats != NULL) { 318 if (!stat_type) { 319 /* prepare general statistics for the engine */ 320 APPEND_STAT("bytes", "%llu", (unsigned long long)stats.curr_bytes); 321 APPEND_STAT("curr_items", "%u", stats.curr_items); 322 APPEND_STAT("total_items", "%u", stats.total_items); 323 APPEND_STAT("evictions", "%llu", 324 (unsigned long long)stats.evictions); 325 } else if (nz_strcmp(nkey, stat_type, "items") == 0) { 326 item_stats(add_stats, c); 327 } else if (nz_strcmp(nkey, stat_type, "slabs") == 0) { 328 slabs_stats(add_stats, c); 329 } else if (nz_strcmp(nkey, stat_type, "sizes") == 0) { 330 item_stats_sizes(add_stats, c); 331 } else { 332 ret = false; 333 } 334 } else { 335 ret = false; 336 } 337 338 return ret; 339 } 340 341 /*@null@*/ 342 static void do_slabs_stats(ADD_STAT add_stats, void *c) { 343 int i, total; 344 /* Get the per-thread stats which contain some interesting aggregates */ 345 struct thread_stats thread_stats; 346 threadlocal_stats_aggregate(&thread_stats); 347 348 total = 0; 349 for(i = POWER_SMALLEST; i <= power_largest; i++) { 350 slabclass_t *p = &slabclass[i]; 351 if (p->slabs != 0) { 352 uint32_t perslab, slabs; 353 slabs = p->slabs; 354 perslab = p->perslab; 355 356 char key_str[STAT_KEY_LEN]; 357 char val_str[STAT_VAL_LEN]; 358 int klen = 0, vlen = 0; 359 360 APPEND_NUM_STAT(i, "chunk_size", "%u", p->size); 361 APPEND_NUM_STAT(i, "chunks_per_page", "%u", perslab); 362 APPEND_NUM_STAT(i, "total_pages", "%u", slabs); 363 APPEND_NUM_STAT(i, "total_chunks", "%u", slabs * perslab); 364 APPEND_NUM_STAT(i, "used_chunks", "%u", 365 slabs*perslab - p->sl_curr - p->end_page_free); 366 APPEND_NUM_STAT(i, "free_chunks", "%u", p->sl_curr); 367 APPEND_NUM_STAT(i, "free_chunks_end", "%u", p->end_page_free); 368 APPEND_NUM_STAT(i, "mem_requested", "%llu", 369 (unsigned long long)p->requested); 370 APPEND_NUM_STAT(i, "get_hits", "%llu", 371 (unsigned long long)thread_stats.slab_stats[i].get_hits); 372 APPEND_NUM_STAT(i, "cmd_set", "%llu", 373 (unsigned long long)thread_stats.slab_stats[i].set_cmds); 374 APPEND_NUM_STAT(i, "delete_hits", "%llu", 375 (unsigned long long)thread_stats.slab_stats[i].delete_hits); 376 APPEND_NUM_STAT(i, "incr_hits", "%llu", 377 (unsigned long long)thread_stats.slab_stats[i].incr_hits); 378 APPEND_NUM_STAT(i, "decr_hits", "%llu", 379 (unsigned long long)thread_stats.slab_stats[i].decr_hits); 380 APPEND_NUM_STAT(i, "cas_hits", "%llu", 381 (unsigned long long)thread_stats.slab_stats[i].cas_hits); 382 APPEND_NUM_STAT(i, "cas_badval", "%llu", 383 (unsigned long long)thread_stats.slab_stats[i].cas_badval); 384 385 total++; 386 } 387 } 388 389 /* add overall slab stats and append terminator */ 390 391 APPEND_STAT("active_slabs", "%d", total); 392 APPEND_STAT("total_malloced", "%llu", (unsigned long long)mem_malloced); 393 add_stats(NULL, 0, NULL, 0, c); 394 } 395 396 #ifdef ALLOW_SLABS_REASSIGN 397 /* Blows away all the items in a slab class and moves its slabs to another 398 class. This is only used by the "slabs reassign" command, for manual tweaking 399 of memory allocation. It's disabled by default since it requires that all 400 slabs be the same size (which can waste space for chunk size mantissas of 401 other than 2.0). 402 1 = success 403 0 = fail 404 -1 = tried. busy. send again shortly. */ 405 int do_slabs_reassign(unsigned char srcid, unsigned char dstid) { 406 void *slab, *slab_end; 407 slabclass_t *p, *dp; 408 void *iter; 409 bool was_busy = false; 410 411 if (srcid < POWER_SMALLEST || srcid > power_largest || 412 dstid < POWER_SMALLEST || dstid > power_largest) 413 return 0; 414 415 p = &slabclass[srcid]; 416 dp = &slabclass[dstid]; 417 418 /* fail if src still populating, or no slab to give up in src */ 419 if (p->end_page_ptr || ! p->slabs) 420 return 0; 421 422 /* fail if dst is still growing or we can't make room to hold its new one */ 423 if (dp->end_page_ptr || ! grow_slab_list(dstid)) 424 return 0; 425 426 if (p->killing == 0) p->killing = 1; 427 428 slab = p->slab_list[p->killing - 1]; 429 slab_end = (char*)slab + settings.item_size_max; 430 431 for (iter = slab; iter < slab_end; (char*)iter += p->size) { 432 item *it = (item *)iter; 433 if (it->slabs_clsid) { 434 if (it->refcount) was_busy = true; 435 item_unlink(it); 436 } 437 } 438 439 /* go through free list and discard items that are no longer part of this slab */ 440 { 441 int fi; 442 for (fi = p->sl_curr - 1; fi >= 0; fi--) { 443 if (p->slots[fi] >= slab && p->slots[fi] < slab_end) { 444 p->sl_curr--; 445 if (p->sl_curr > fi) p->slots[fi] = p->slots[p->sl_curr]; 446 } 447 } 448 } 449 450 if (was_busy) return -1; 451 452 /* if good, now move it to the dst slab class */ 453 p->slab_list[p->killing - 1] = p->slab_list[p->slabs - 1]; 454 p->slabs--; 455 p->killing = 0; 456 dp->slab_list[dp->slabs++] = slab; 457 dp->end_page_ptr = slab; 458 dp->end_page_free = dp->perslab; 459 /* this isn't too critical, but other parts of the code do asserts to 460 make sure this field is always 0. */ 461 for (iter = slab; iter < slab_end; (char*)iter += dp->size) { 462 ((item *)iter)->slabs_clsid = 0; 463 } 464 return 1; 465 } 466 467 int slabs_reassign(unsigned char srcid, unsigned char dstid) { 468 int ret; 469 470 pthread_mutex_lock(&slabs_lock); 471 ret = do_slabs_reassign(srcid, dstid); 472 pthread_mutex_unlock(&slabs_lock); 473 return ret; 474 } 475 #endif 476 477 static void *memory_allocate(size_t size) { 478 void *ret; 479 480 if (mem_base == NULL) { 481 /* We are not using a preallocated large memory chunk */ 482 ret = malloc(size); 483 } else { 484 ret = mem_current; 485 486 if (size > mem_avail) { 487 return NULL; 488 } 489 490 /* mem_current pointer _must_ be aligned!!! */ 491 if (size % CHUNK_ALIGN_BYTES) { 492 size += CHUNK_ALIGN_BYTES - (size % CHUNK_ALIGN_BYTES); 493 } 494 495 mem_current = ((char*)mem_current) + size; 496 if (size < mem_avail) { 497 mem_avail -= size; 498 } else { 499 mem_avail = 0; 500 } 501 } 502 503 return ret; 504 } 505 506 void *slabs_alloc(size_t size, unsigned int id) { 507 void *ret; 508 509 pthread_mutex_lock(&slabs_lock); 510 ret = do_slabs_alloc(size, id); 511 pthread_mutex_unlock(&slabs_lock); 512 return ret; 513 } 514 515 void slabs_free(void *ptr, size_t size, unsigned int id) { 516 pthread_mutex_lock(&slabs_lock); 517 do_slabs_free(ptr, size, id); 518 pthread_mutex_unlock(&slabs_lock); 519 } 520 521 void slabs_stats(ADD_STAT add_stats, void *c) { 522 pthread_mutex_lock(&slabs_lock); 523 do_slabs_stats(add_stats, c); 524 pthread_mutex_unlock(&slabs_lock); 525 } 526