From: oetiker Date: Sun, 28 Sep 2008 19:26:39 +0000 (+0000) Subject: This patch introduces "fast shutdown" mode and two new signals. X-Git-Url: https://git.octo.it/?p=rrdtool.git;a=commitdiff_plain;h=e1597899f28b7fed13a029c84d9b36bbe5f16505;ds=sidebyside This patch introduces "fast shutdown" mode and two new signals. -- kevin brintnall git-svn-id: svn://svn.oetiker.ch/rrdtool/trunk/program@1540 a5681a0c-68f1-0310-ab6d-d61299d08faa --- diff --git a/doc/rrdcached.pod b/doc/rrdcached.pod index d8d88c5..8ed2979 100644 --- a/doc/rrdcached.pod +++ b/doc/rrdcached.pod @@ -6,7 +6,7 @@ rrdcached - Data caching daemon for rrdtool =head1 SYNOPSIS -B [B<-l> I
] [B<-w> I] [B<-z> I] [B<-f> I] [B<-j> I] +B [B<-l> I
] [B<-w> I] [B<-z> I] [B<-f> I] [B<-j> I] [-F] =head1 DESCRIPTION @@ -87,7 +87,20 @@ found, all updates therein will be read into memory before the daemon starts accepting new connections. The journal will be rotated with the same frequency as the flush timer -given by B<-f>. On clean shutdown, the journal files are removed. +given by B<-f>. + +When journaling is enabled, the daemon will use a fast shutdown procedure. +Rather than flushing all files to disk, it will make sure the journal is +properly written and exit immediately. Although the RRD data files are +not fully up-to-date, no information is lost; all pending updates will be +replayed from the journal next time the daemon starts up. + +To disable fast shutdown, use the B<-F> option. + +=item B<-F> + +ALWAYS flush all updates to the RRD data files when the daemon is shut +down, regardless of journal setting. =item B<-b> I @@ -421,6 +434,29 @@ Number of times the journal has been rotated since startup. =item SIGINT and SIGTERM +The daemon exits normally on receipt of either of these signals. Pending +updates are handled in accordance with the B<-j> and B<-F> options. + +=item SIGUSR1 + +The daemon exits AFTER flushing all updates out to disk. This may take a +while. + +=item SIGUSR2 + +The daemon exits immediately, without flushing updates out to disk. +Pending updates will be replayed from the journal when the daemon starts +up again. B. + +=back + +=head1 SIGNALS + +=over 4 + +=item SIGINT and SIGTERM + The daemon exits normally on receipt of either of these signals. =back diff --git a/src/rrd_daemon.c b/src/rrd_daemon.c index a0b8364..e0e373a 100644 --- a/src/rrd_daemon.c +++ b/src/rrd_daemon.c @@ -168,6 +168,7 @@ static pthread_cond_t cache_cond = PTHREAD_COND_INITIALIZER; static int config_write_interval = 300; static int config_write_jitter = 0; static int config_flush_interval = 3600; +static int config_flush_at_shutdown = 0; static char *config_pid_file = NULL; static char *config_base_dir = NULL; @@ -212,6 +213,18 @@ static void sig_term_handler (int s __attribute__((unused))) /* {{{ */ sig_common("TERM"); } /* }}} void sig_term_handler */ +static void sig_usr1_handler (int s __attribute__((unused))) /* {{{ */ +{ + config_flush_at_shutdown = 1; + sig_common("USR1"); +} /* }}} void sig_usr1_handler */ + +static void sig_usr2_handler (int s __attribute__((unused))) /* {{{ */ +{ + config_flush_at_shutdown = 0; + sig_common("USR2"); +} /* }}} void sig_usr2_handler */ + static void install_signal_handlers(void) /* {{{ */ { /* These structures are static, because `sigaction' behaves weird if the are @@ -219,6 +232,8 @@ static void install_signal_handlers(void) /* {{{ */ static struct sigaction sa_int; static struct sigaction sa_term; static struct sigaction sa_pipe; + static struct sigaction sa_usr1; + static struct sigaction sa_usr2; /* Install signal handlers */ memset (&sa_int, 0, sizeof (sa_int)); @@ -233,6 +248,14 @@ static void install_signal_handlers(void) /* {{{ */ sa_pipe.sa_handler = SIG_IGN; sigaction (SIGPIPE, &sa_pipe, NULL); + memset (&sa_pipe, 0, sizeof (sa_usr1)); + sa_usr1.sa_handler = sig_usr1_handler; + sigaction (SIGUSR1, &sa_usr1, NULL); + + memset (&sa_usr2, 0, sizeof (sa_usr2)); + sa_usr2.sa_handler = sig_usr2_handler; + sigaction (SIGUSR2, &sa_usr2, NULL); + } /* }}} void install_signal_handlers */ static int open_pidfile(void) /* {{{ */ @@ -571,6 +594,7 @@ static void *queue_thread_main (void *args __attribute__((unused))) /* {{{ */ { struct timeval now; struct timespec next_flush; + int final_flush = 0; /* make sure we only flush once on shutdown */ gettimeofday (&now, NULL); next_flush.tv_sec = now.tv_sec + config_flush_interval; @@ -608,8 +632,9 @@ static void *queue_thread_main (void *args __attribute__((unused))) /* {{{ */ } /* Now, check if there's something to store away. If not, wait until - * something comes in or it's time to do the cache flush. */ - if (cache_queue_head == NULL) + * something comes in or it's time to do the cache flush. if we are + * shutting down, do not wait around. */ + if (cache_queue_head == NULL && !do_shutdown) { status = pthread_cond_timedwait (&cache_cond, &cache_lock, &next_flush); if ((status != 0) && (status != ETIMEDOUT)) @@ -619,9 +644,14 @@ static void *queue_thread_main (void *args __attribute__((unused))) /* {{{ */ } } - /* We're about to shut down, so lets flush the entire tree. */ - if ((do_shutdown != 0) && (cache_queue_head == NULL)) - flush_old_values (/* max age = */ -1); + /* We're about to shut down */ + if (do_shutdown != 0 && !final_flush++) + { + if (config_flush_at_shutdown) + flush_old_values (-1); /* flush everything */ + else + break; + } /* Check if a value has arrived. This may be NULL if we timed out or there * was an interrupt such as a signal. */ @@ -686,14 +716,23 @@ static void *queue_thread_main (void *args __attribute__((unused))) /* {{{ */ pthread_mutex_lock (&cache_lock); - /* We're about to shut down, so lets flush the entire tree. */ - if ((do_shutdown != 0) && (cache_queue_head == NULL)) - flush_old_values (/* max age = */ -1); + /* We're about to shut down */ + if (do_shutdown != 0 && !final_flush++) + { + if (config_flush_at_shutdown) + flush_old_values (-1); /* flush everything */ + else + break; + } } /* while ((do_shutdown == 0) || (cache_queue_head != NULL)) */ pthread_mutex_unlock (&cache_lock); - assert(cache_queue_head == NULL); - RRDD_LOG(LOG_INFO, "clean shutdown; all RRDs flushed"); + if (config_flush_at_shutdown) + { + assert(cache_queue_head == NULL); + RRDD_LOG(LOG_INFO, "clean shutdown; all RRDs flushed"); + } + journal_done(); return (NULL); @@ -1343,10 +1382,16 @@ static void journal_rotate(void) /* {{{ */ fclose(old_fh); if (journal_fh == NULL) + { RRDD_LOG(LOG_CRIT, "JOURNALING DISABLED: Cannot open journal file '%s' : (%s)", journal_cur, rrd_strerror(errno)); + RRDD_LOG(LOG_ERR, + "JOURNALING DISABLED: All values will be flushed at shutdown"); + config_flush_at_shutdown = 1; + } + } /* }}} static void journal_rotate */ static void journal_done(void) /* {{{ */ @@ -1361,10 +1406,18 @@ static void journal_done(void) /* {{{ */ journal_fh = NULL; } - RRDD_LOG(LOG_INFO, "removing journals"); + if (config_flush_at_shutdown) + { + RRDD_LOG(LOG_INFO, "removing journals"); + unlink(journal_old); + unlink(journal_cur); + } + else + { + RRDD_LOG(LOG_INFO, "expedited shutdown; " + "journals will be used at next startup"); + } - unlink(journal_old); - unlink(journal_cur); pthread_mutex_unlock(&journal_lock); } /* }}} static void journal_done */ @@ -1490,7 +1543,9 @@ static void *connection_thread_main (void *args) /* {{{ */ pollfd.revents = 0; status = poll (&pollfd, 1, /* timeout = */ 500); - if (status == 0) /* timeout */ + if (do_shutdown) + break; + else if (status == 0) /* timeout */ continue; else if (status < 0) /* error */ { @@ -1797,11 +1852,11 @@ static void *listen_thread_main (void *args __attribute__((unused))) /* {{{ */ } status = poll (pollfds, pollfds_num, /* timeout = */ 1000); - if (status == 0) - { - continue; /* timeout */ - } - else if (status < 0) + if (do_shutdown) + break; + else if (status == 0) /* timeout */ + continue; + else if (status < 0) /* error */ { status = errno; if (status != EINTR) @@ -1965,7 +2020,7 @@ static int read_options (int argc, char **argv) /* {{{ */ int option; int status = 0; - while ((option = getopt(argc, argv, "gl:f:w:b:z:p:j:h?")) != -1) + while ((option = getopt(argc, argv, "gl:f:w:b:z:p:j:h?F")) != -1) { switch (option) { @@ -2083,6 +2138,10 @@ static int read_options (int argc, char **argv) /* {{{ */ } break; + case 'F': + config_flush_at_shutdown = 1; + break; + case 'j': { struct stat statbuf; @@ -2133,6 +2192,7 @@ static int read_options (int argc, char **argv) /* {{{ */ " -b Base directory to change to.\n" " -g Do not fork and run in the foreground.\n" " -j Directory in which to create the journal files.\n" + " -F Always flush all updates at shutdown\n" "\n" "For more information and a detailed description of all options " "please refer\n" @@ -2151,6 +2211,9 @@ static int read_options (int argc, char **argv) /* {{{ */ fprintf(stderr, "WARNING: write delay (-z) should NOT be larger than" " write interval (-w) !\n"); + if (journal_cur == NULL) + config_flush_at_shutdown = 1; + return (status); } /* }}} int read_options */