Skip to content

Commit b5ea901

Browse files
committed
restartable cache
"-e /path/to/tmpfsmnt/file" SIGUSR1 for graceful stop restart requires the same memory limit, slab sizes, and some other infrequently changed details. Most other options and features can change between restarts. Binary can be upgraded between restarts. Restart does some fixup work on start for every item in cache. Can take over a minute with more than a few hundred million items in cache. Keep in mind when a cache is down it may be missing invalidations, updates, and so on.
1 parent 554b566 commit b5ea901

22 files changed

+1290
-59
lines changed

Makefile.am

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,8 @@ memcached_SOURCES = memcached.c memcached.h \
2424
crawler.c crawler.h \
2525
itoa_ljust.c itoa_ljust.h \
2626
slab_automove.c slab_automove.h \
27-
authfile.c authfile.h
27+
authfile.c authfile.h \
28+
restart.c restart.h
2829

2930
if BUILD_CACHE
3031
memcached_SOURCES += cache.c

assoc.c

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -255,11 +255,14 @@ static void *assoc_maintenance_thread(void *arg) {
255255
* allow dynamic hash table expansion without causing significant
256256
* wait times.
257257
*/
258-
pause_threads(PAUSE_ALL_THREADS);
259-
assoc_expand();
260-
pause_threads(RESUME_ALL_THREADS);
258+
if (do_run_maintenance_thread) {
259+
pause_threads(PAUSE_ALL_THREADS);
260+
assoc_expand();
261+
pause_threads(RESUME_ALL_THREADS);
262+
}
261263
}
262264
}
265+
mutex_unlock(&maintenance_lock);
263266
return NULL;
264267
}
265268

configure.ac

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -613,6 +613,7 @@ fi
613613

614614
AC_CHECK_FUNCS(mlockall)
615615
AC_CHECK_FUNCS(getpagesizes)
616+
AC_CHECK_FUNCS(sysconf)
616617
AC_CHECK_FUNCS(memcntl)
617618
AC_CHECK_FUNCS(sigignore)
618619
AC_CHECK_FUNCS(clock_gettime)

crawler.c

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -460,23 +460,27 @@ static void *item_crawler_thread(void *arg) {
460460
pthread_mutex_unlock(&lru_crawler_lock);
461461
if (settings.verbose > 2)
462462
fprintf(stderr, "LRU crawler thread stopping\n");
463+
settings.lru_crawler = false;
463464

464465
return NULL;
465466
}
466467

467468
static pthread_t item_crawler_tid;
468469

469-
int stop_item_crawler_thread(void) {
470+
int stop_item_crawler_thread(bool wait) {
470471
int ret;
471472
pthread_mutex_lock(&lru_crawler_lock);
473+
if (do_run_lru_crawler_thread == 0) {
474+
pthread_mutex_unlock(&lru_crawler_lock);
475+
return 0;
476+
}
472477
do_run_lru_crawler_thread = 0;
473478
pthread_cond_signal(&lru_crawler_cond);
474479
pthread_mutex_unlock(&lru_crawler_lock);
475-
if ((ret = pthread_join(item_crawler_tid, NULL)) != 0) {
480+
if (wait && (ret = pthread_join(item_crawler_tid, NULL)) != 0) {
476481
fprintf(stderr, "Failed to stop LRU crawler thread: %s\n", strerror(ret));
477482
return -1;
478483
}
479-
settings.lru_crawler = false;
480484
return 0;
481485
}
482486

@@ -584,6 +588,11 @@ int lru_crawler_start(uint8_t *ids, uint32_t remaining,
584588
STATS_LOCK();
585589
is_running = stats_state.lru_crawler_running;
586590
STATS_UNLOCK();
591+
if (do_run_lru_crawler_thread == 0) {
592+
pthread_mutex_unlock(&lru_crawler_lock);
593+
return -2;
594+
}
595+
587596
if (is_running &&
588597
!(type == CRAWLER_AUTOEXPIRE && active_crawler_type == CRAWLER_AUTOEXPIRE)) {
589598
pthread_mutex_unlock(&lru_crawler_lock);

crawler.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,9 @@ enum crawler_result_type {
2828
CRAWLER_OK=0, CRAWLER_RUNNING, CRAWLER_BADCLASS, CRAWLER_NOTSTARTED, CRAWLER_ERROR
2929
};
3030
int start_item_crawler_thread(void);
31-
int stop_item_crawler_thread(void);
31+
#define CRAWLER_WAIT true
32+
#define CRAWLER_NOWAIT false
33+
int stop_item_crawler_thread(bool wait);
3234
int init_lru_crawler(void *arg);
3335
enum crawler_result_type lru_crawler_crawl(char *slabs, enum crawler_run_type,
3436
void *c, const int sfd, unsigned int remaining);

items.c

Lines changed: 33 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ static uint64_t sizes_bytes[LARGEST_ID];
6060
static unsigned int *stats_sizes_hist = NULL;
6161
static uint64_t stats_sizes_cas_min = 0;
6262
static int stats_sizes_buckets = 0;
63+
static uint64_t cas_id = 0;
6364

6465
static volatile int do_run_lru_maintainer_thread = 0;
6566
static int lru_maintainer_initialized = 0;
@@ -109,13 +110,18 @@ static uint64_t lru_total_bumps_dropped(void);
109110
/* Get the next CAS id for a new item. */
110111
/* TODO: refactor some atomics for this. */
111112
uint64_t get_cas_id(void) {
112-
static uint64_t cas_id = 0;
113113
pthread_mutex_lock(&cas_id_lock);
114114
uint64_t next_id = ++cas_id;
115115
pthread_mutex_unlock(&cas_id_lock);
116116
return next_id;
117117
}
118118

119+
void set_cas_id(uint64_t new_cas) {
120+
pthread_mutex_lock(&cas_id_lock);
121+
cas_id = new_cas;
122+
pthread_mutex_unlock(&cas_id_lock);
123+
}
124+
119125
int item_is_flushed(item *it) {
120126
rel_time_t oldest_live = settings.oldest_live;
121127
uint64_t cas = ITEM_get_cas(it);
@@ -293,7 +299,7 @@ item *do_item_alloc(char *key, const size_t nkey, const unsigned int flags,
293299
return NULL;
294300
}
295301

296-
assert(it->slabs_clsid == 0);
302+
assert(it->it_flags == 0 || it->it_flags == ITEM_CHUNKED);
297303
//assert(it != heads[id]);
298304

299305
/* Refcount is seeded to 1 by slabs_alloc() */
@@ -373,6 +379,31 @@ bool item_size_ok(const size_t nkey, const int flags, const int nbytes) {
373379
return slabs_clsid(ntotal) != 0;
374380
}
375381

382+
/* fixing stats/references during warm start */
383+
void do_item_link_fixup(item *it) {
384+
item **head, **tail;
385+
int ntotal = ITEM_ntotal(it);
386+
uint32_t hv = hash(ITEM_key(it), it->nkey);
387+
assoc_insert(it, hv);
388+
389+
head = &heads[it->slabs_clsid];
390+
tail = &tails[it->slabs_clsid];
391+
if (it->prev == 0 && *head == 0) *head = it;
392+
if (it->next == 0 && *tail == 0) *tail = it;
393+
sizes[it->slabs_clsid]++;
394+
sizes_bytes[it->slabs_clsid] += ntotal;
395+
396+
STATS_LOCK();
397+
stats_state.curr_bytes += ntotal;
398+
stats_state.curr_items += 1;
399+
stats.total_items += 1;
400+
STATS_UNLOCK();
401+
402+
item_stats_sizes_add(it);
403+
404+
return;
405+
}
406+
376407
static void do_item_link_q(item *it) { /* item is the new head */
377408
item **head, **tail;
378409
assert((it->it_flags & ITEM_SLABBED) == 0);

items.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88

99
/* See items.c */
1010
uint64_t get_cas_id(void);
11+
void set_cas_id(uint64_t new_cas);
1112

1213
/*@null@*/
1314
item *do_item_alloc(char *key, const size_t nkey, const unsigned int flags, const rel_time_t exptime, const int nbytes);
@@ -23,6 +24,7 @@ void do_item_remove(item *it);
2324
void do_item_update(item *it); /** update LRU time to current and reposition */
2425
void do_item_update_nolock(item *it);
2526
int do_item_replace(item *it, item *new_it, const uint32_t hv);
27+
void do_item_link_fixup(item *it);
2628

2729
int item_is_flushed(item *it);
2830
unsigned int do_get_lru_size(uint32_t id);

logger.c

Lines changed: 22 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -88,8 +88,8 @@ static int logger_thread_poll_watchers(int force_poll, int watcher);
8888

8989
/* Logger GID's can be used by watchers to put logs back into strict order
9090
*/
91-
static uint64_t logger_get_gid(void) {
92-
static uint64_t logger_gid = 0;
91+
static uint64_t logger_gid = 0;
92+
uint64_t logger_get_gid(void) {
9393
#ifdef HAVE_GCC_64ATOMICS
9494
return __sync_add_and_fetch(&logger_gid, 1);
9595
#elif defined(__sun)
@@ -102,6 +102,18 @@ static uint64_t logger_get_gid(void) {
102102
#endif
103103
}
104104

105+
void logger_set_gid(uint64_t gid) {
106+
#ifdef HAVE_GCC_64ATOMICS
107+
__sync_add_and_fetch(&logger_gid, gid);
108+
#elif defined(__sun)
109+
atomic_add_64(&logger_gid);
110+
#else
111+
mutex_lock(&logger_atomics_mutex);
112+
logger_gid = gid;
113+
mutex_unlock(&logger_atomics_mutex);
114+
#endif
115+
}
116+
105117
/* TODO: genericize lists. would be nice to import queue.h if the impact is
106118
* studied... otherwise can just write a local one.
107119
*/
@@ -505,6 +517,8 @@ static void logger_thread_sum_stats(struct logger_stats *ls) {
505517
static void *logger_thread(void *arg) {
506518
useconds_t to_sleep = MIN_LOGGER_SLEEP;
507519
L_DEBUG("LOGGER: Starting logger thread\n");
520+
// TODO: If we ever have item references in the logger code, will need to
521+
// ensure everything is dequeued before stopping the thread.
508522
while (do_run_logger_thread) {
509523
int found_logs = 0;
510524
logger *l;
@@ -553,12 +567,11 @@ static int start_logger_thread(void) {
553567
return 0;
554568
}
555569

556-
// future.
557-
/*static int stop_logger_thread(void) {
570+
static int stop_logger_thread(void) {
558571
do_run_logger_thread = 0;
559572
pthread_join(logger_tid, NULL);
560573
return 0;
561-
}*/
574+
}
562575

563576
/*************************
564577
* Public functions for submitting logs and starting loggers from workers.
@@ -578,19 +591,16 @@ void logger_init(void) {
578591
abort();
579592
}
580593

581-
/* This can be removed once the global stats initializer is improved */
582-
STATS_LOCK();
583-
stats.log_worker_dropped = 0;
584-
stats.log_worker_written = 0;
585-
stats.log_watcher_skipped = 0;
586-
stats.log_watcher_sent = 0;
587-
STATS_UNLOCK();
588594
/* This is what adding a STDERR watcher looks like. should replace old
589595
* "verbose" settings. */
590596
//logger_add_watcher(NULL, 0);
591597
return;
592598
}
593599

600+
void logger_stop(void) {
601+
stop_logger_thread();
602+
}
603+
594604
/* called *from* the thread using a logger.
595605
* initializes the per-thread bipbuf, links it into the list of loggers
596606
*/

logger.h

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,9 @@ struct logentry_item_store {
100100

101101
/* end intermediary structures */
102102

103+
/* WARNING: cuddled items aren't compatible with warm restart. more code
104+
* necessary to ensure log streams are all flushed/processed before stopping
105+
*/
103106
typedef struct _logentry {
104107
enum log_entry_subtype event;
105108
uint8_t pad;
@@ -108,7 +111,6 @@ typedef struct _logentry {
108111
struct timeval tv; /* not monotonic! */
109112
int size;
110113
union {
111-
void *entry; /* probably an item */
112114
char end;
113115
} data[];
114116
} logentry;
@@ -165,6 +167,7 @@ extern pthread_key_t logger_key;
165167
/* public functions */
166168

167169
void logger_init(void);
170+
void logger_stop(void);
168171
logger *logger_create(void);
169172

170173
#define LOGGER_LOG(l, flag, type, ...) \
@@ -186,4 +189,8 @@ enum logger_add_watcher_ret {
186189

187190
enum logger_add_watcher_ret logger_add_watcher(void *c, const int sfd, uint16_t f);
188191

192+
/* functions used by restart system */
193+
uint64_t logger_get_gid(void);
194+
void logger_set_gid(uint64_t gid);
195+
189196
#endif

0 commit comments

Comments
 (0)