+ return (handle_request_flush (sock, buffer_ptr, buffer_size));
+ else if (strcasecmp (command, "flushall") == 0)
+ return (handle_request_flushall(sock));
+ else if (strcasecmp (command, "pending") == 0)
+ return (handle_request_pending(sock, buffer_ptr, buffer_size));
+ else if (strcasecmp (command, "forget") == 0)
+ return (handle_request_forget(sock, buffer_ptr, buffer_size));
+ else if (strcasecmp (command, "queue") == 0)
+ return (handle_request_queue(sock));
+ else if (strcasecmp (command, "stats") == 0)
+ return (handle_request_stats (sock));
+ else if (strcasecmp (command, "help") == 0)
+ return (handle_request_help (sock, buffer_ptr, buffer_size));
+ else if (strcasecmp (command, "batch") == 0 && sock != NULL)
+ return batch_start(sock);
+ else if (strcasecmp (command, ".") == 0 && sock != NULL && sock->batch_start)
+ return batch_done(sock);
+ else if (strcasecmp (command, "quit") == 0)
+ return -1;
+ else
+ return send_response(sock, RESP_ERR, "Unknown command: %s\n", command);
+
+ /* NOTREACHED */
+ assert(1==0);
+} /* }}} int handle_request */
+
+/* MUST NOT hold journal_lock before calling this */
+static void journal_rotate(void) /* {{{ */
+{
+ FILE *old_fh = NULL;
+ int new_fd;
+
+ if (journal_cur == NULL || journal_old == NULL)
+ return;
+
+ pthread_mutex_lock(&journal_lock);
+
+ /* we rotate this way (rename before close) so that the we can release
+ * the journal lock as fast as possible. Journal writes to the new
+ * journal can proceed immediately after the new file is opened. The
+ * fclose can then block without affecting new updates.
+ */
+ if (journal_fh != NULL)
+ {
+ old_fh = journal_fh;
+ journal_fh = NULL;
+ rename(journal_cur, journal_old);
+ ++stats_journal_rotate;
+ }
+
+ new_fd = open(journal_cur, O_WRONLY|O_CREAT|O_APPEND,
+ S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH);
+ if (new_fd >= 0)
+ {
+ journal_fh = fdopen(new_fd, "a");
+ if (journal_fh == NULL)
+ close(new_fd);
+ }
+
+ pthread_mutex_unlock(&journal_lock);
+
+ if (old_fh != NULL)
+ 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) /* {{{ */
+{
+ if (journal_cur == NULL)
+ return;
+
+ pthread_mutex_lock(&journal_lock);
+ if (journal_fh != NULL)
+ {
+ fclose(journal_fh);
+ journal_fh = NULL;
+ }
+
+ 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");
+ }
+
+ pthread_mutex_unlock(&journal_lock);
+
+} /* }}} static void journal_done */
+
+static int journal_write(char *cmd, char *args) /* {{{ */
+{
+ int chars;
+
+ if (journal_fh == NULL)
+ return 0;
+
+ pthread_mutex_lock(&journal_lock);
+ chars = fprintf(journal_fh, "%s %s\n", cmd, args);
+ pthread_mutex_unlock(&journal_lock);
+
+ if (chars > 0)