* tailing reliable realtime streaming feeder for inn
* statemc.c - state machine core (see README.states).
*
- * Copyright (C) 2010 Ian Jackson <ijackson@chiark.greenend.org.uk>
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- *
- * (I believe that when you compile and link this as part of the inn2
- * build, with the Makefile runes I have provided, all the libraries
- * and files which end up included in innduct are licence-compatible
- * with GPLv3. If not then please let me know. -Ian Jackson.)
+ * Copyright Ian Jackson <ijackson@chiark.greenend.org.uk>
+ * and contributors; see LICENCE.txt.
+ * SPDX-License-Identifier: GPL-3.0-or-later
*/
#include "innduct.h"
StateMachineState sms;
int until_flush;
InputFile *main_input_file, *flushing_input_file, *backlog_input_file;
+Counts backlog_counts;
+int backlog_counts_report;
FILE *defer;
/* initialisation to 0 is good */
dbg("startup: ductdefer ENOENT");
} else {
dbg("startup: ductdefer nlink=%ld", (long)stabdefer.st_nlink);
- switch (stabdefer.st_nlink==1) {
+ switch (stabdefer.st_nlink) {
case 1:
open_defer(); /* so that we will later close it and rename it */
break;
" (presumably hardlink to backlog file)");
break;
default:
- crash("defer file %s has unexpected link count %d",
- path_defer, stabdefer.st_nlink);
+ crash("defer file %s has unexpected link count %ld",
+ path_defer, (long)stabdefer.st_nlink);
}
}
case sm_SEPARATED:
case sm_DROPPING:
- warn("abandoning old feedfile after flush (%s), autodeferring",
- why ? why : "took too long to complete");
+ if (conns.count)
+ warn("abandoning old feedfile after flush (%s), autodeferring",
+ why ? why : "took too long to complete");
+ else
+ info("autodeferring after flush (%s)",
+ why ? why : "no connections");
assert(flushing_input_file);
autodefer_input_file(flushing_input_file);
return 1;
return 1;
}
-static void notice_processed(InputFile *ipf, int completed,
- const char *what, const char *spec) {
- if (!ipf) return; /* allows preterminate to be lazy */
+static void notice_processed_counts(Counts *counts, int completed,
+ InputFile *ipf_xtra, const char *what) {
#define RCI_NOTHING(x) /* nothing */
#define RCI_TRIPLE_FMT(x) " " #x "=" RCI_TRIPLE_FMT_BASE
-#define RCI_TRIPLE_VALS(x) , RCI_TRIPLE_VALS_BASE(ipf->counts.counts, [RC_##x])
+#define RCI_TRIPLE_VALS(x) , RCI_TRIPLE_VALS_BASE(counts->results, [RC_##x])
-#define CNT(art,rc) (ipf->counts.counts[art_##art][RC_##rc])
+#define CNT(art,rc) (counts->results[art_##art][RC_##rc])
- char *inprog= completed
- ? xasprintf("%s","") /* GCC produces a stupid warning for printf("") ! */
- : xasprintf(" inprogress=%ld", ipf->inprogress);
- char *autodefer= ipf->autodefer >= 0
- ? xasprintf(" autodeferred=%ld", ipf->autodefer)
- : xasprintf("%s","");
+ char *inprog= ipf_xtra && !completed
+ ? masprintf(" inprogress=%ld", ipf_xtra->inprogress)
+ : masprintf("%s",""); /* GCC produces a stupid warning for printf("") ! */
+ char *autodefer= ipf_xtra && ipf_xtra->autodefer >= 0
+ ? masprintf(" autodeferred=%ld", ipf_xtra->autodefer)
+ : masprintf("%s","");
- info("%s %s%s read=%d (+bl=%d,+err=%d)%s%s"
- " missing=%d offered=%d (ch=%d,nc=%d) accepted=%d (ch=%d,nc=%d)"
+ notice("%s %s read=%d (+bl=%d,+err=%d)%s%s missing=%d"
+ " offered=%d (ch=%d,nc=%d)"
+ " accepted=%d (ch=%d,nc=%d)"
RESULT_COUNTS(RCI_NOTHING, RCI_TRIPLE_FMT)
,
- completed?"completed":"processed", what, spec,
- ipf->counts.read_ok, ipf->counts.read_blank, ipf->counts.read_err,
- inprog, autodefer, ipf->counts.nooffer_missing,
+ completed?"completed":"processed", what,
+ counts->events[read_ok], counts->events[read_blank],
+ counts->events[read_err],
+ inprog, autodefer, counts->events[nooffer_missing],
CNT(Unchecked,sent) + CNT(Unsolicited,sent)
, CNT(Unchecked,sent), CNT(Unsolicited,sent),
- CNT(Wanted,accepted) + CNT(Unsolicited,accepted)
- , CNT(Wanted,accepted), CNT(Unsolicited,accepted)
+ CNT(Wanted,accepted) + CNT(Wanted,accepted)
+ , CNT(Wanted,accepted), CNT(Wanted,accepted)
RESULT_COUNTS(RCI_NOTHING, RCI_TRIPLE_VALS)
);
- memset(&ipf->counts, 0, sizeof(ipf->counts));
+ memset(counts, 0, sizeof(*counts));
free(inprog);
free(autodefer);
#undef CNT
}
+static void notice_processed_inputfile(InputFile *ipf, int completed,
+ const char *what) {
+ if (!ipf) return; /* allows showstats to be lazy */
+ notice_processed_counts(&ipf->counts, completed, ipf, what);
+}
+
+static void backlog_accumulate_counts(InputFile *ipf) {
+ int i,j;
+ if (!ipf) return;
+
+ for (i=0; i<art_MaxState; i++)
+ for (j=0; j<RCI_max; j++)
+ backlog_counts.results[i][j] += ipf->counts.results[i][j];
+
+ for (i=0; i<ECI_max; i++)
+ backlog_counts.events[i] += ipf->counts.events[i];
+
+ memset(&ipf->counts, 0, sizeof(ipf->counts));
+ backlog_counts_report= 1;
+}
+
void statemc_check_backlog_done(void) {
InputFile *ipf= backlog_input_file;
if (!inputfile_is_done(ipf)) return;
- const char *slash= strrchr(ipf->path, '/');
- const char *leaf= slash ? slash+1 : ipf->path;
- const char *under= strchr(slash, '_');
- const char *rest= under ? under+1 : leaf;
- if (!strncmp(rest,"backlog",7)) rest += 7;
- notice_processed(ipf,1,"backlog ",rest);
-
+ dbg("backlog file %p %s complete", ipf, ipf->path);
+ backlog_accumulate_counts(ipf);
close_input_file(ipf);
if (unlink(ipf->path)) {
if (errno != ENOENT)
assert(sms==sm_SEPARATED || sms==sm_DROPPING);
- notice_processed(ipf,1,"feedfile","");
+ notice_processed_inputfile(ipf,1,"batch");
close_defer();
}
void showstats(void) {
- notice_processed(main_input_file,0,"feedfile","");
- notice_processed(flushing_input_file,0,"flushing","");
- if (backlog_input_file)
- notice_processed(backlog_input_file,0, "backlog file ",
- backlog_input_file->path);
+ notice_conns_stats();
+ notice_processed_inputfile(main_input_file, 0, "feedfile");
+ notice_processed_inputfile(flushing_input_file, 0, "flushing");
+
+ backlog_accumulate_counts(backlog_input_file);
+ if (backlog_counts_report) {
+ notice_processed_counts(&backlog_counts, 0,
+ backlog_input_file, "backlogs");
+ backlog_counts_report= 0;
+ }
until_stats_log= stats_log_periods;
}
static int signal_self_pipe[2];
static void *sigarrived_event(oop_source *lp, int fd, oop_event e, void *u) {
- assert(fd=signal_self_pipe[0]);
+ assert(fd==signal_self_pipe[0]);
char buf[PIPE_BUF];
int r= read(signal_self_pipe[0], buf, sizeof(buf));
if (r<0 && !isewouldblock(errno))
}
static void sigarrived_handler(int signum) {
+ int esave = errno;
static char x;
switch (signum) {
case SIGTERM:
default:
abort();
}
- write(signal_self_pipe[1],&x,1);
+ int r = write(signal_self_pipe[1],&x,1);
+ if (!(r==1 || isewouldblock(errno))) abort();
+ errno = esave;
}
void init_signals(void) {