From a6cc8f5fcbcbf4c707149940de2ee9a33220c34d Mon Sep 17 00:00:00 2001 From: Sergey Poznyakoff Date: Thu, 16 Apr 2020 19:54:23 +0300 Subject: Rewrite as a multi-threaded program. * NEWS: Update. * configure.ac: Version 3.1.95 * src/Makefile.am (wydawca_SOURCES): Remove job.c (LDADD): Link with libpthread. * src/job.c: Remove. * src/config.c: Remove the wakeup-interval statement. * src/net.c (wydawca_listener): Rewrite as a thread function wy_thr_listen. * src/timer.c (timer_get): Use thread-specific storage. (timer_get_count): Remove. * src/triplet.c: Rewrite using multi-thread model. * src/wydawca.c: Likewise. * src/wydawca.h: Update. * tests/check-fail.at: Update expected output. * tests/check-notify.at: Likewise. * tests/inotify-ok.at: Likewise. * tests/inotify-rmsymlink.at: Likewise. * tests/inotify-symlink.at: Likewise. * tests/inotify-unatt00.at: Likewise. * tests/inotify-unatt01.at: Likewise. * tests/upl12f.at: Likewise. * tests/upload-dry.at: Likewise. ` --- NEWS | 4 +- configure.ac | 2 +- doc/wydawca.texi | 14 -- src/Makefile.am | 3 +- src/config.c | 3 - src/job.c | 441 --------------------------------------------- src/net.c | 43 +---- src/timer.c | 43 +++-- src/triplet.c | 393 +++++++++++++++++++++++++++------------- src/wydawca.c | 108 +++++++---- src/wydawca.h | 63 +++---- tests/check-fail.at | 6 +- tests/check-notify.at | 6 +- tests/inotify-ok.at | 1 + tests/inotify-rmsymlink.at | 1 + tests/inotify-symlink.at | 1 + tests/inotify-unatt00.at | 1 + tests/inotify-unatt01.at | 1 + tests/upl12f.at | 6 +- tests/upload-dry.at | 3 - 20 files changed, 416 insertions(+), 727 deletions(-) delete mode 100644 src/job.c diff --git a/NEWS b/NEWS index 9324194..2789798 100644 --- a/NEWS +++ b/NEWS @@ -1,9 +1,9 @@ -Wydawca NEWS -- history of user-visible changes. 2020-04-09 +Wydawca NEWS -- history of user-visible changes. 2020-04-16 See the end of file for copying conditions. Please send Wydawca bug reports to . -Version 3.1.90 (git) +Version 3.1.95 (git) * Configuration file name changed to "wydawca.conf" diff --git a/configure.ac b/configure.ac index 26ae9ac..f99f49f 100644 --- a/configure.ac +++ b/configure.ac @@ -15,7 +15,7 @@ # along with wydawca. If not, see . AC_PREREQ(2.63) -AC_INIT([wydawca], 3.1.90, [bug-wydawca@gnu.org.ua], [wydawca], +AC_INIT([wydawca], 3.1.95, [bug-wydawca@gnu.org.ua], [wydawca], [http://www.gnu.org.ua/software/wydawca]) AC_CONFIG_SRCDIR([src/wydawca.c]) AC_CONFIG_AUX_DIR([build-aux]) diff --git a/doc/wydawca.texi b/doc/wydawca.texi index e4365ec..430e300 100644 --- a/doc/wydawca.texi +++ b/doc/wydawca.texi @@ -1129,16 +1129,6 @@ Declare a special service name, which will be treated as a request to process all spools. @end deffn -@deffn {Config} wakeup-interval time -Specifies the wake-up interval for the daemon. If no connections -are requested during @var{time}, the server will wake up -and sweep all the configured spools. It is useful for periodical -removal of expired triplets. See also @code{file-sweep-time} -statement (@pxref{general, file-sweep-time}). - -@xref{time interval specification}, for the syntax of @var{time}. -@end deffn - @deffn {Config} pidfile file Store master process @acronym{PID} in @var{file}. Default pidfile location is @file{@var{localstatedir}/run/wydawca.pid}. @@ -3361,10 +3351,6 @@ foreground @var{arg:@i{boolean}}; # @xref{general, single-process}. single-process @var{arg:@i{boolean}}; -# @r{Set wake-up interval.} -# @xref{general, wakeup-interval}. -wakeup-interval @var{time:@i{string}}; - # @r{Set pid file name.} # @xref{general, pidfile}. pidfile @var{file:@i{string}}; diff --git a/src/Makefile.am b/src/Makefile.am index 6e67c9c..9d9d4d9 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -33,7 +33,6 @@ wydawca_SOURCES=\ event.c\ gpg.c\ interval.c\ - job.c\ lock.c\ module.c\ net.c\ @@ -61,7 +60,7 @@ SUFFIXES=.opt .c .h .opt.h: $(AM_V_GEN)m4 -s $(top_srcdir)/@GRECS_SUBDIR@/build-aux/getopt.m4 $< > $@ -LDADD=@GRECS_LDADD@ @SQLLIB@ @GPGMELIB@ @LIBLTDL@ +LDADD=@GRECS_LDADD@ @SQLLIB@ @GPGMELIB@ @LIBLTDL@ -lpthread AM_CPPFLAGS= \ -I$(top_srcdir)/include\ @GRECS_INCLUDES@ @MAILUTILS_INCLUDES@\ diff --git a/src/config.c b/src/config.c index c928431..7d0e760 100644 --- a/src/config.c +++ b/src/config.c @@ -1440,9 +1440,6 @@ static struct grecs_keyword wydawca_kw[] = { { "single-process", NULL, N_("Do not spawn subprocesses"), grecs_type_bool, GRECS_DFLT, &single_process }, - { "wakeup-interval", N_("time"), - N_("Set wake-up interval"), - grecs_type_string, GRECS_CONST, &wakeup_interval, 0, cb_interval }, { "pidfile", N_("file"), N_("Set pid file name"), grecs_type_string, GRECS_CONST, &pidfile}, diff --git a/src/job.c b/src/job.c deleted file mode 100644 index 84d3bb5..0000000 --- a/src/job.c +++ /dev/null @@ -1,441 +0,0 @@ -/* wydawca - automatic release submission daemon - Copyright (C) 2009-2013, 2017, 2019-2020 Sergey Poznyakoff - - 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 . */ - -#include "wydawca.h" - -enum { - STATE_FINISHED, - STATE_QUEUED, - STATE_ACTIVE -}; - -#define STATE_MASK(s) (1<<(s)) - -#define STATE_ANY \ - (STATE_MASK(STATE_FINISHED) |\ - STATE_MASK(STATE_QUEUED) | \ - STATE_MASK(STATE_ACTIVE)) - -struct job { - enum job_type type; - struct job *next, *prev; - int state; - pid_t pid; - time_t timestamp; - int exit_status; - char *printable; - union { - struct wy_triplet *triplet; /* JOB_TRIPLET */ - struct spool *spool; /* JOB_SPOOL */ - } v; -}; - -struct job *queue; -size_t jobmax; -size_t jobcnt; - -static int wakeup; - -RETSIGTYPE -queue_signal(int sig) -{ - wakeup = 1; - signal(sig, queue_signal); -} - -void -set_timer(time_t interval) -{ - wakeup = 0; - if (interval) - alarm(interval); -} - - -char const * -job_printable(struct job *job) -{ - if (!job->printable) { - size_t s = 0; - - switch (job->type) { - case JOB_TRIPLET: - if (grecs_asprintf(&job->printable, &s, - "triplet(%s,%s)", - job->v.triplet->spool->tag, - job->v.triplet->name)) - grecs_alloc_die(); - break; - - case JOB_SPOOL: - if (grecs_asprintf(&job->printable, &s, - "spool(%s)", - job->v.spool->tag)) - grecs_alloc_die(); - break; - - case JOB_ALL_SPOOLS: - job->printable = grecs_strdup("all spools"); - } - } - return job->printable; -} - -struct job * -job_locate(int type, int mask, void *data) -{ - struct job *p; - for (p = queue; p; p = p->next) - if (p->type == type && (STATE_MASK(p->state) & mask)) { - switch (p->type) { - case JOB_TRIPLET: - if (p->v.triplet == data) - return p; - break; - - case JOB_SPOOL: - if (p->v.spool == data) - return p; - break; - - case JOB_ALL_SPOOLS: - return p; - } - } - return p; -} - -size_t -job_active_count() -{ - struct job *job; - size_t count = 0; - for (job = queue; job; job = job->next) - if (job->state == STATE_ACTIVE) - count++; - return count; -} - -int -wydawca_scanner(struct job *job) -{ - int rc; - initstats(); - timer_start("wydawca"); - spool_create_timers(); - switch (job->type) { - case JOB_TRIPLET: - triplet_commit(job->v.triplet); - rc = 0; - break; - - case JOB_ALL_SPOOLS: - rc = scan_all_spools(); - break; - - case JOB_SPOOL: - rc = scan_spool(job->v.spool); - notify_flush(job->v.spool); - } - timer_stop("wydawca"); - if (!single_process) - logstats(); - return rc; -} - -int -job_start(struct job *job) -{ - pid_t pid; - - if (jobmax && jobcnt == jobmax) { - wy_log(LOG_NOTICE, "maximum number of processes active"); - return 1; - } - - wy_debug(1, (_("starting job: %s"), job_printable(job))); - - if (single_process) { - if (wydawca_scanner(job)) - job->state = STATE_QUEUED; - else - job->state = STATE_FINISHED; - wakeup = 1; - return 0; - } - - pid = fork(); - if (pid == 0) { - signal(SIGHUP, SIG_DFL); - signal(SIGTERM, SIG_DFL); - signal(SIGQUIT, SIG_DFL); - signal(SIGINT, SIG_DFL); - signal(SIGCHLD, SIG_DFL); - signal(SIGALRM, SIG_DFL); - alarm(0); - exit(wydawca_scanner(job) ? WYDAWCA_EX_AGAIN : 0); - } else if (pid == -1) { - wy_log(LOG_CRIT, "fork: %s", strerror(errno)); - return -1; - } else { - job->state = STATE_ACTIVE; - job->pid = pid; - jobcnt++; - } - return 0; -} - -void -job_remove(struct job *job) -{ - struct job *p; - - wy_debug(1, (_("removing job: %s"), job_printable(job))); - p = job->prev; - if (p) - p->next = job->next; - else - queue = job->next; - - p = job->next; - if (p) - p->prev = job->prev; -} - -void -job_destroy(struct job *job) -{ - free(job->printable); - free(job); -} - -void -job_insert(struct job *job, struct job *elt) -{ - struct job *p; - - job->prev = elt; - if (!elt) { - if (queue) - queue->prev = job; - job->next = queue; - queue = job; - return; - } - - p = elt->next; - elt->next = job; - - if (p) - p->prev = job; -} - -void -job_schedule(int type, void *data) -{ - struct job *job; - - job = job_locate(type, - type == JOB_TRIPLET - ? STATE_MASK(STATE_QUEUED) : STATE_ANY, - data); - if (!job) { - job = grecs_zalloc(sizeof(*job)); - job->type = type; - job->pid = -1; - time(&job->timestamp); - - switch (type) { - case JOB_TRIPLET:{ - struct wy_triplet *tp = data; - job->v.triplet = tp; - tp->job = job; - break; - } - - case JOB_SPOOL: - job->v.spool = data; - break; - - case JOB_ALL_SPOOLS: - break; - } - wy_debug(1, (_("scheduling job %s"), job_printable(job))); - job_insert(job, NULL); - } - - job->state = STATE_QUEUED; - job_start(job); -} - -static void -print_status(struct job *job, int expect_term) -{ - int status = job->exit_status; - - if (WIFEXITED(status)) { - int exit_code = WEXITSTATUS(status); - if (exit_code == 0) { - wy_debug(1, (_("%lu (job %s) exited successfully"), - (unsigned long) job->pid, job_printable(job))); - } else if (exit_code == WYDAWCA_EX_AGAIN) { - wy_debug(1, (_("%lu (job %s) reported tempfail"), - (unsigned long) job->pid, job_printable(job))); - } else - wy_log(LOG_ERR, - _("%lu (job %s) failed with status %d"), - (unsigned long) job->pid, - job_printable(job), exit_code); - } else if (WIFSIGNALED(status)) { - int prio; - if (expect_term && WTERMSIG(status) == SIGTERM) { - if (!wy_debug_level) - return; - prio = LOG_DEBUG; - } else - prio = LOG_ERR; - - wy_log(prio, - _("%lu (job %s) terminated on signal %d"), - (unsigned long) job->pid, job_printable(job), - WTERMSIG(status)); - } else if (WIFSTOPPED(status)) - wy_log(LOG_NOTICE, - _("%lu (job %s) stopped on signal %d"), - (unsigned long) job->pid, job_printable(job), - WSTOPSIG(status)); -#ifdef WCOREDUMP - else if (WCOREDUMP(status)) - wy_log(LOG_NOTICE, - _("%lu (job %s) dumped core"), - (unsigned long) job->pid, job_printable(job)); -#endif - else - wy_log(LOG_ERR, - _("%lu (job %s) terminated with unrecognized status"), - (unsigned long) job->pid, job_printable(job)); -} - -void -job_queue_runner(time_t min_interval) -{ - struct job *job; - time_t now = time(NULL); - - if (wakeup) { - wakeup = 0; - - for (;;) { - int status; - - pid_t pid = waitpid((pid_t) - 1, &status, WNOHANG); - if (pid <= 0) - break; - for (job = queue; job; job = job->next) { - if (job->state == STATE_ACTIVE && job->pid == pid) { - remove_triplet(job->v.triplet, 1); - job->v.triplet = NULL; - job->exit_status = status; - job->state = STATE_FINISHED; - jobcnt--; - } - } - } - - for (job = queue; job;) { - struct job *next = job->next; - if (job->state == STATE_FINISHED) { - print_status(job, 0); - if (WIFEXITED(job->exit_status) && - WEXITSTATUS(job->exit_status) == WYDAWCA_EX_AGAIN) { - time_t interval = lock_timeout; - if (interval == 0) - interval = lock_expire_time; - /* Re-queue the job */ - job->state = STATE_QUEUED; - job->timestamp = now + interval; - } else { - job_remove(job); - job_destroy(job); - job = next; - continue; - } - } - - if (job->state == STATE_QUEUED) { - if (job->timestamp >= now) { - if (job_start(job)) - pause(); - now = time(NULL); - } else { - time_t interval = job->timestamp - now; - if (min_interval == 0 || interval < min_interval) - min_interval = interval; - } - } - - job = next; - } - } - - if (min_interval) { - wy_debug(2, (_("computed interval: %lu"), min_interval)); - set_timer(min_interval); - } -} - -void -job_queue_wait(void) -{ - while (queue) { - int status; - struct job *job; - - pid_t pid = waitpid((pid_t) - 1, &status, 0); - if (pid <= 0) - break; - for (job = queue; job; job = job->next) { - if (job->state == STATE_ACTIVE && job->pid == pid) { - remove_triplet(job->v.triplet, 1); - job->v.triplet = NULL; - job->exit_status = status; - job->state = STATE_FINISHED; - jobcnt--; - } - } - - for (job = queue; job;) { - struct job *next = job->next; - if (job->state == STATE_FINISHED) { - print_status(job, 0); - job_remove(job); - job_destroy(job); - } else if (job->state == STATE_QUEUED) { - job_remove(job); - job_destroy(job); - } - job = next; - } - } - logstats(); -} - -void -job_init(void) -{ - signal(SIGCHLD, queue_signal); - signal(SIGALRM, queue_signal); -} diff --git a/src/net.c b/src/net.c index 4a0900e..3f8d291 100644 --- a/src/net.c +++ b/src/net.c @@ -129,28 +129,12 @@ handle_connection(FILE * in, FILE * out) } if (spool) - job_schedule_spool(spool); + scan_spool(spool); else - job_schedule_all(); + scan_all_spools(); free(buf); } -int reconfigure; -static int terminate; - -RETSIGTYPE -sig_hup(int sig) -{ - reconfigure = 1; - terminate = 1; -} - -RETSIGTYPE -sig_term(int sig) -{ - terminate = 1; -} - static inline int notify_parent(void) { @@ -158,8 +142,8 @@ notify_parent(void) return (p && strcmp(p, "1") == 0); } -void -wydawca_listener(void) +void * +wy_thr_listen(void *ptr) { int ctlfd = open_listener(); int wfd = watcher_init(); @@ -181,16 +165,9 @@ wydawca_listener(void) if (notify_parent()) kill(getppid(), SIGUSR1); - signal(SIGHUP, sig_hup); - signal(SIGTERM, sig_term); - signal(SIGQUIT, sig_term); - signal(SIGINT, sig_term); - while (!terminate) { + while (1) { int rc; fd_set rset; - struct timeval to, *pto; - - job_queue_runner(triplet_sweep()); FD_ZERO(&rset); if (ctlfd != -1) @@ -198,14 +175,7 @@ wydawca_listener(void) if (wfd != -1) FD_SET(wfd, &rset); - if (wakeup_interval) { - to.tv_sec = wakeup_interval; - to.tv_usec = 0; - *pto = to; - } else - pto = NULL; - - rc = select(maxfd + 1, &rset, NULL, NULL, pto); + rc = select(maxfd + 1, &rset, NULL, NULL, NULL); if (rc == 0) continue; else if (rc < 0) { @@ -250,4 +220,5 @@ wydawca_listener(void) fclose(out); } } + return NULL; } diff --git a/src/timer.c b/src/timer.c index 162ae7d..f5d7c93 100644 --- a/src/timer.c +++ b/src/timer.c @@ -33,9 +33,6 @@ struct timer_slot { struct rusage children_mark; }; -static struct grecs_symtab *timer_table; -static size_t _timer_count; - static unsigned hash_string_ci(const char *string, unsigned long n_buckets) { @@ -54,28 +51,43 @@ timer_hasher(void *ptr, unsigned long n_buckets) return hash_string_ci(tp->name, n_buckets); } +static pthread_key_t key; +static pthread_once_t key_once = PTHREAD_ONCE_INIT; + +static void +timer_free(void *f) +{ + grecs_symtab_free(f); +} + +static void +make_key(void) +{ + pthread_key_create(&key, timer_free); +} + /* Lookup a timer by its name. If it does not exist, create it. */ wydawca_timer_t timer_get(const char *name) { - struct timer_slot key, *ret; + struct timer_slot slot, *ret; int install = 1; - - key.name = (char *) name; - - if (!timer_table) { - timer_table = grecs_symtab_create(sizeof(key), + struct grecs_symtab *timer_table; + + pthread_once(&key_once, make_key); + if ((timer_table = pthread_getspecific(key)) == NULL) { + timer_table = grecs_symtab_create(sizeof(slot), timer_hasher, NULL, NULL, NULL, NULL); if (!timer_table) grecs_alloc_die(); + pthread_setspecific(key, timer_table); } - - ret = grecs_symtab_lookup_or_install(timer_table, &key, &install); + + slot.name = (char *)name; + ret = grecs_symtab_lookup_or_install(timer_table, &slot, &install); if (!ret) grecs_alloc_die(); - if (install) - _timer_count++; return ret; } @@ -182,8 +194,3 @@ timer_format_time(double t) return str; } -size_t -timer_get_count() -{ - return _timer_count; -} diff --git a/src/triplet.c b/src/triplet.c index e41da07..797a09e 100644 --- a/src/triplet.c +++ b/src/triplet.c @@ -19,14 +19,106 @@ /* Triplets are stored in a symtab: */ static struct grecs_symtab *triplet_table; +static pthread_mutex_t triplet_table_mutex = PTHREAD_MUTEX_INITIALIZER; + /* ... and are organized into a doubly-linked list, using the prev and - next members of struct wy_triplet. The list is ordered so that + next members of struct wy_triplet: */ +struct triplet_list { + struct wy_triplet *head, *tail; + pthread_mutex_t mutex; + pthread_cond_t cond; +}; + +#define TRIPLET_LIST_INITIALIZER \ + { NULL, NULL, PTHREAD_MUTEX_INITIALIZER, PTHREAD_COND_INITIALIZER } + +/* Two such lists are maintained. The pending list is ordered so that prev points to a triplet older than this one, and next points to a - newer triplet. The triplet_list variable points to the root of the - list, i.e. the oldest triplet available. */ -static struct wy_triplet *triplet_list; + newer triplet. Its head member points to the oldest triplet available. */ +static struct triplet_list triplet_pending_list = TRIPLET_LIST_INITIALIZER; + +/* The running list contains triplets which are processed by running + threads */ +static struct triplet_list triplet_running_list = TRIPLET_LIST_INITIALIZER; /* Functions for building the ordered doubly-linked list of triplets */ + +static inline void +triplet_list_lock(struct triplet_list *list) +{ + pthread_mutex_lock(&list->mutex); +} + +static inline void +triplet_list_unlock(struct triplet_list *list) +{ + pthread_mutex_unlock(&list->mutex); +} + +void +triplet_list_unlink(struct triplet_list *list, struct wy_triplet *tp) +{ + int head_changed = 0; + + if (tp->prev) + tp->prev->next = tp->next; + else if (tp == list->head) { + list->head = tp->next; + head_changed = 1; + } + + if (tp->next) + tp->next->prev = tp->prev; + else + list->tail = tp->prev; + + tp->next = tp->prev = NULL; + if (head_changed) + pthread_cond_broadcast(&list->cond); + tp->list = NULL; +} + +static void +triplet_list_insert(struct triplet_list *list, + struct wy_triplet *newp, struct wy_triplet *anchor, + int after) +{ + int head_changed = 0; + + if (!anchor) { + newp->prev = NULL; + newp->next = list->head; + if (list->head) + list->head->prev = newp; + else + list->tail = newp; + list->head = newp; + head_changed = 1; + } else if (after) { + if (anchor->next) + anchor->next->prev = newp; + else + list->tail = newp; + newp->prev = anchor; + newp->next = anchor->next; + anchor->next = newp; + } else { + if (anchor->prev) + anchor->prev->next = newp; + else { + list->head = newp; + head_changed = 1; + } + newp->prev = anchor->prev; + newp->next = anchor; + anchor->prev = newp; + } + newp->list = list; + if (head_changed) + pthread_cond_broadcast(&list->cond); +} + + static time_t triplet_timestamp(struct wy_triplet *tp) { @@ -43,69 +135,35 @@ triplet_timestamp(struct wy_triplet *tp) return t; } -static time_t -triplet_ttl(struct wy_triplet *tp) +static struct timespec * +triplet_ttl(struct wy_triplet *tp, struct timespec *ts) { time_t t; if (!tp) - return 0; + return NULL; t = time(NULL) - triplet_timestamp(tp); if (t < tp->spool->file_sweep_time) - return tp->spool->file_sweep_time - t; - return 0; -} - -void -triplet_list_unlink(struct wy_triplet *tp) -{ - if (tp->prev) - tp->prev->next = tp->next; - else if (tp == triplet_list) - triplet_list = tp->next; - - if (tp->next) - tp->next->prev = tp->prev; - - tp->next = tp->prev = NULL; -} - -static void -triplet_list_insert_before(struct wy_triplet *newp, struct wy_triplet *anchor) -{ - if (!anchor) { - triplet_list = newp; - return; - } - - if (anchor->prev) - anchor->prev->next = newp; + ts->tv_sec += tp->spool->file_sweep_time - t; else - triplet_list = newp; - newp->prev = anchor->prev; - - anchor->prev = newp; - newp->next = anchor; + ts->tv_sec = 0; + ts->tv_nsec = 0; + return ts; } + void -triplet_list_ordered_insert(struct wy_triplet *tp) +triplet_list_ordered_insert(struct triplet_list *list, struct wy_triplet *tp) { time_t t = triplet_timestamp(tp); struct wy_triplet *p, *prev = NULL; - for (p = triplet_list; p && triplet_timestamp(p) < t; + for (p = list->head; p && triplet_timestamp(p) < t; prev = p, p = p->next); if (p) - triplet_list_insert_before(tp, p); - else if (prev) { - prev->next = tp; - tp->prev = prev; - tp->next = NULL; - } else { - tp->next = tp->prev = NULL; - triplet_list = tp; - } + triplet_list_insert(list, tp, p, 0); + else + triplet_list_insert(list, tp, prev ? prev->next : NULL, 1); } static struct wy_user * @@ -190,6 +248,7 @@ register_file(struct file_info *finfo, struct spool *spool) struct wy_triplet key, *ret; int install = 1; + pthread_mutex_lock(&triplet_table_mutex); if (!triplet_table) { triplet_table = grecs_symtab_create(sizeof(struct wy_triplet), @@ -206,16 +265,21 @@ register_file(struct file_info *finfo, struct spool *spool) key.spool = spool; ret = grecs_symtab_lookup_or_install(triplet_table, &key, &install); + pthread_mutex_unlock(&triplet_table_mutex); + if (!ret) grecs_alloc_die(); free(key.name); ret->file[finfo->type] = *finfo; + + triplet_list_lock(&triplet_pending_list); if (install) { ret->spool = spool; ret->acc = grecs_txtacc_create(); - } else - triplet_list_unlink(ret); - triplet_list_ordered_insert(ret); + } else if (ret->list) + triplet_list_unlink(ret->list, ret); + triplet_list_ordered_insert(&triplet_pending_list, ret); + triplet_list_unlock(&triplet_pending_list); return ret; } @@ -236,33 +300,14 @@ triplet_lookup(struct spool *spool, const char *name) key.spool = spool; file_info_cleanup(&finfo); + pthread_mutex_lock(&triplet_table_mutex); ret = grecs_symtab_lookup_or_install(triplet_table, &key, NULL); + pthread_mutex_unlock(&triplet_table_mutex); free(key.name); return ret; } -/* Return true if any part of the triplet TRP was modified more than - TTL seconds ago */ -static int -triplet_expired_p(struct wy_triplet *trp) -{ - int i; - time_t now = time(NULL); - time_t ttl = trp->spool->file_sweep_time; - - if (ttl == 0) - return 0; - - for (i = 0; i < FILE_TYPE_COUNT; i++) { - if (trp->file[i].name && (now - trp->file[i].sb.st_mtime) >= ttl) { - wy_debug(1, (_("file %s expired"), trp->file[i].name)); - return 1; - } - } - return 0; -} - enum triplet_state { triplet_directive, /* Short triplet: only a directive is present, but nothing more is required */ @@ -306,6 +351,8 @@ check_triplet_state(struct wy_triplet *trp) void triplet_enqueue(struct wy_triplet *trp) { + pthread_t tid; + if (!trp) return; if (spool_open_dictionaries(trp->spool)) @@ -313,76 +360,62 @@ triplet_enqueue(struct wy_triplet *trp) switch (check_triplet_state(trp)) { case triplet_directive: case triplet_complete: - if (triplet_expired_p(trp)) - remove_triplet(trp, 0); - else - job_schedule_triplet(trp); + triplet_list_lock(&triplet_pending_list); + triplet_list_unlink(&triplet_pending_list, trp); + triplet_list_unlock(&triplet_pending_list); + + triplet_list_lock(&triplet_running_list); + triplet_list_insert(&triplet_running_list, trp, + triplet_running_list.tail, 1); + triplet_list_unlock(&triplet_running_list); + + pthread_create(&tid, NULL, wy_thr_triplet, trp); break; case triplet_incomplete: break; case triplet_bad: - remove_triplet(trp, 0); + remove_triplet(trp); } } /* Unlink all parts of the triplet TRP */ -int -remove_triplet(struct wy_triplet *trp, int check) +static void +remove_triplet_unlocked(struct wy_triplet *trp) { int i; for (i = 0; i < FILE_TYPE_COUNT; i++) { if (trp->file[i].name) { - if (check) { - struct stat st; - - if (wy_dry_run) - continue; - if (fstatat(trp->spool->source_fd, - trp->file[i].name, &st, 0)) { - if (errno == ENOENT) - continue; - else { + if (!wy_dry_run) { + if (unlinkat(trp->spool->source_fd, trp->file[i].name, 0)) { + if (errno != ENOENT) wy_log(LOG_ERR, - _("can't stat %s/%s: %s"), + _("cannot remove %s/%s: %s"), trp->spool->source_dir, trp->file[i].name, strerror(errno)); - return 1; - } - } else { - wy_log(LOG_NOTICE, - _("%s/%s still exists"), + } else + wy_log(LOG_NOTICE, _("removing %s/%s"), trp->spool->source_dir, trp->file[i].name); - return 1; - } - } else { - wy_log(LOG_NOTICE, _("removing %s/%s"), - trp->spool->source_dir, trp->file[i].name); - if (!wy_dry_run - && unlinkat(trp->spool->source_fd, - trp->file[i].name, 0)) - wy_log(LOG_ERR, - _("cannot remove %s/%s: %s"), - trp->spool->source_dir, - trp->file[i].name, strerror(errno)); } } } - triplet_list_unlink(trp); + triplet_list_unlink(trp->list, trp); triplet_gpgme_ctx_release(trp); - grecs_symtab_remove(triplet_table, trp); - return 0; + pthread_mutex_lock(&triplet_table_mutex); + grecs_symtab_remove(triplet_table, trp); + pthread_mutex_unlock(&triplet_table_mutex); } -time_t -triplet_sweep(void) +void +remove_triplet(struct wy_triplet *trp) { - while (triplet_list && triplet_expired_p(triplet_list)) - remove_triplet(triplet_list, 0); + struct triplet_list *list = trp->list; - return triplet_ttl(triplet_list); + triplet_list_lock(list); + remove_triplet_unlocked(trp); + triplet_list_unlock(list); } void @@ -392,8 +425,7 @@ triplet_commit(struct wy_triplet *trp) if (spool_open_dictionaries(trp->spool) == 0) { timer_start(trp->spool->tag); wy_debug(1, (_("processing triplet `%s'"), trp->name)); - if (process_directives(trp)) - remove_triplet(trp, 0); + process_directives(trp); timer_stop(trp->spool->tag); } timer_stop("spool"); @@ -405,7 +437,7 @@ triplet_remove_file(struct spool *spool, const char *name) struct wy_triplet *tp = triplet_lookup(spool, name); int i, n = 0; - if (!tp) + if (!tp || tp->list == &triplet_running_list) return; for (i = 0; i < FILE_TYPE_COUNT; i++) { @@ -420,9 +452,119 @@ triplet_remove_file(struct spool *spool, const char *name) if (!n) { wy_debug(1, ("deleting empty triplet (%s/%s)", spool->source_dir, name)); - remove_triplet(tp, 0); + remove_triplet(tp); } } + +/* Return true if any part of the triplet TRP was modified more than + TTL seconds ago */ +static int +triplet_expired_p(struct wy_triplet *trp) +{ + int i; + time_t now; + time_t ttl; + + if (!trp) + return 0; + + now = time(NULL); + ttl = trp->spool->file_sweep_time; + + if (ttl == 0) + return 0; + + for (i = 0; i < FILE_TYPE_COUNT; i++) { + if (trp->file[i].name && (now - trp->file[i].sb.st_mtime) >= ttl) { + wy_debug(1, (_("file %s expired"), trp->file[i].name)); + return 1; + } + } + return 0; +} + +void * +wy_thr_cleaner(void *ptr) +{ + triplet_list_lock(&triplet_pending_list); + while (1) { + if (triplet_pending_list.head) { + struct timespec ts; + clock_gettime(CLOCK_REALTIME, &ts); + triplet_ttl(triplet_pending_list.head, &ts); + pthread_cond_timedwait(&triplet_pending_list.cond, + &triplet_pending_list.mutex, &ts); + } else + pthread_cond_wait(&triplet_pending_list.cond, + &triplet_pending_list.mutex); + if (triplet_expired_p(triplet_pending_list.head)) + remove_triplet_unlocked(triplet_pending_list.head); + } +} + +void +wy_triplet_wait(void) +{ + triplet_list_lock(&triplet_running_list); + while (triplet_running_list.head) { + pthread_cond_wait(&triplet_running_list.cond, + &triplet_running_list.mutex); + } + triplet_list_unlock(&triplet_running_list); +} + +static pthread_key_t key; +static pthread_once_t key_once = PTHREAD_ONCE_INIT; + +static void +stat_free(void *f) +{ + free(f); +} + +static void +make_key(void) +{ + pthread_key_create(&key, stat_free); +} + +WY_STAT_COUNTER * +wy_get_stat_array(void) +{ + WY_STAT_COUNTER *stat; + pthread_once(&key_once, make_key); + if ((stat = pthread_getspecific(key)) == NULL) { + stat = grecs_calloc(WY_MAX_STAT, sizeof(stat[0])); + pthread_setspecific(key, stat); + } + return stat; +} + +WY_STAT_COUNTER * +wy_get_stat_ptr(int what) +{ + WY_STAT_COUNTER *stat; + pthread_once(&key_once, make_key); + if ((stat = pthread_getspecific(key)) == NULL) { + stat = grecs_calloc(WY_MAX_STAT, sizeof(stat[0])); + pthread_setspecific(key, stat); + } + return stat + what; +} + +void * +wy_thr_triplet(void *ptr) +{ + struct wy_triplet *trp = ptr; + + timer_start("wydawca"); + spool_create_timers(); + triplet_commit(trp); + timer_stop("wydawca"); + logstats(); + remove_triplet(trp); + return NULL; +} /* FIXME */ #define WY_EXP_DFL 0 @@ -844,10 +986,10 @@ expand_triplet_ls_dir(char **ret, struct wy_triplet *trp) } DECL_TRIPLET_EXP(real_name, uploader->realname) - DECL_TRIPLET_EXP(expand_user_email, uploader->email) +DECL_TRIPLET_EXP(expand_user_email, uploader->email) - static int - expand_email_user(char **ret, struct wy_triplet *trp) +static int +expand_email_user(char **ret, struct wy_triplet *trp) { if (trp && trp->uploader) { size_t size = 0; @@ -860,7 +1002,6 @@ DECL_TRIPLET_EXP(real_name, uploader->realname) return WRDSE_UNDEF; } -//FIXME: static env? static int expand_report(char **ret, struct wy_triplet *trp) { diff --git a/src/wydawca.c b/src/wydawca.c index d948429..240eca1 100644 --- a/src/wydawca.c +++ b/src/wydawca.c @@ -54,18 +54,10 @@ char *wy_gpg_homedir; char *default_check_script; struct grecs_sockaddr listen_sockaddr; -unsigned wydawca_stat[WY_MAX_STAT]; - unsigned min_directive_version = MIN_DIRECTIVE_VERSION; unsigned max_directive_version = MAX_DIRECTIVE_VERSION; int inotify_enable = 1; - -void -initstats() -{ - memset(wydawca_stat, 0, sizeof wydawca_stat); -} /* Logging */ void @@ -185,9 +177,10 @@ int wy_stat_mask_p(unsigned long mask) { int i; - + WY_STAT_COUNTER *stat = wy_get_stat_array(); + for (i = 0; i < WY_MAX_STAT; i++) - if (wydawca_stat[i] != 0 && (mask && WY_STAT_MASK(i))) + if (stat[i] != 0 && (mask && WY_STAT_MASK(i))) return 1; return 0; } @@ -202,7 +195,7 @@ wy_stat_expansion(char **ret, char const *name, size_t len) && memcmp(stat_kwname[i], name, len) == 0) { size_t size = 0; *ret = NULL; - if (grecs_asprintf(ret, &size, "%u", wydawca_stat[i])) + if (grecs_asprintf(ret, &size, "%u", wy_get_stat_counter(i))) return WRDSE_NOSPACE; } } @@ -218,7 +211,7 @@ logstats() for (i = 0; i < WY_MAX_STAT; i++) if (print_stats & WY_STAT_MASK(i)) wy_log(LOG_INFO, "%s: %u", - gettext(stat_name[i]), wydawca_stat[i]); + gettext(stat_name[i]), wy_get_stat_counter(i)); } notify_finish(); @@ -270,9 +263,6 @@ grecs_print_diag(grecs_locus_t * locus, int err, int errcode, } } -char **x_argv; -extern int reconfigure; - void wydawca_daemon() { @@ -285,8 +275,6 @@ wydawca_daemon() } check_pidfile(); - wydawca_listener(); - remove_pidfile(); } #include "cmdline.h" @@ -304,6 +292,75 @@ version_hook(FILE * stream) putchar('\n'); } +int fatal_signals[] = { + SIGHUP, + SIGINT, + SIGQUIT, + SIGTERM, + 0 +}; + +static void +sigign(int sig) +{ +} + +void +wy_main(void) +{ + struct sigaction act; + sigset_t sigs; + int i; + pthread_t tid; + + act.sa_flags = 0; + sigemptyset(&act.sa_mask); + act.sa_handler = sigign; + + /* Block the 'fatal signals' and SIGPIPE in the handling thread */ + sigemptyset(&sigs); + for (i = 0; fatal_signals[i]; i++) { + sigaddset(&sigs, fatal_signals[i]); + sigaction(fatal_signals[i], &act, NULL); + } + + sigaddset(&sigs, SIGPIPE); + sigaddset(&sigs, SIGALRM); + sigaddset(&sigs, SIGCHLD); + pthread_sigmask(SIG_BLOCK, &sigs, NULL); + + scan_all_spools(); + + if (wy_mode == WY_MODE_DAEMON) { + wydawca_daemon(); + + // Start cleaner thread + pthread_create(&tid, NULL, wy_thr_cleaner, NULL); + + // Start listener thread + pthread_create(&tid, NULL, wy_thr_listen, NULL); + + /* Unblock only the fatal signals */ + sigemptyset(&sigs); + for (i = 0; fatal_signals[i]; i++) { + sigaddset(&sigs, fatal_signals[i]); + } + pthread_sigmask(SIG_UNBLOCK, &sigs, NULL); + + /* Wait for signal to arrive */ + sigwait(&sigs, &i); + wy_log(LOG_NOTICE, "shutting down on signal \"%s\"", strsignal(i)); + } else { + /* Unblock only the fatal signals */ + sigemptyset(&sigs); + for (i = 0; fatal_signals[i]; i++) { + sigaddset(&sigs, fatal_signals[i]); + } + pthread_sigmask(SIG_UNBLOCK, &sigs, NULL); + wy_triplet_wait(); + } +} + int main(int argc, char **argv) { @@ -314,7 +371,6 @@ main(int argc, char **argv) proginfo.print_version_hook = version_hook; config_init(); - x_argv = argv; parse_options(argc, argv); wydawca_uid = getuid(); @@ -400,28 +456,16 @@ main(int argc, char **argv) } wydawca_lock_init(); - job_init(); wy_log(LOG_NOTICE, _("wydawca (%s) started"), PACKAGE_STRING); - scan_all_spools(); - if (wy_mode == WY_MODE_DAEMON) - wydawca_daemon(); - else - job_queue_wait(); + wy_main(); dictionaries_close(); modules_close(); + remove_pidfile(); wy_log(LOG_NOTICE, _("wydawca (%s) finished"), PACKAGE_STRING); - if (reconfigure) { - int i; - for (i = getdtablesize(); i > 2; i--) - close(i); - remove_pidfile(); - execv(x_argv[0], x_argv); - } - exit(0); } diff --git a/src/wydawca.h b/src/wydawca.h index 6cc71f1..476f77c 100644 --- a/src/wydawca.h +++ b/src/wydawca.h @@ -44,6 +44,7 @@ #include #include #include +#include #include #include @@ -187,7 +188,7 @@ struct wy_triplet { The prev member points to a triplet older than this one, and next points to a triplet newer than it: */ struct wy_triplet *prev, *next; - struct job *job; + struct triplet_list *list; /* User data */ struct wy_user *uploader_list; struct wy_user *uploader; @@ -305,7 +306,6 @@ extern int syslog_include_prio; /* Syslog priority indication */ extern time_t file_sweep_time; /* Unlink stale file after this amount of time */ extern char *tar_command_name; /* Name of the tar command */ -extern unsigned wydawca_stat[WY_MAX_STAT]; extern unsigned long print_stats; extern int archive_signatures; @@ -324,7 +324,6 @@ enum { }; extern int wy_mode; -extern time_t wakeup_interval; extern int foreground; extern int single_process; extern struct grecs_sockaddr listen_sockaddr; @@ -341,11 +340,26 @@ extern int inotify_enable; extern struct notification *default_notification; +typedef unsigned WY_STAT_COUNTER; +WY_STAT_COUNTER *wy_get_stat_array(void); + +static inline WY_STAT_COUNTER * +wy_get_stat_slot(int what) +{ + return wy_get_stat_array() + what; +} + +static inline WY_STAT_COUNTER +wy_get_stat_counter(int what) +{ + return *wy_get_stat_slot(what); +} + static inline void increase_stat_counter(int what) { if (what >= WY_MAX_STAT) abort(); - wydawca_stat[what]++; + ++*wy_get_stat_slot(what); } int stat_mask_p(unsigned long mask); @@ -394,8 +408,7 @@ char *triplet_expand_dictionary_query(struct dictionary *dict, void triplet_remove_file(struct spool *spool, const char *name); -time_t triplet_sweep(void); -int remove_triplet(struct wy_triplet *trp, int check); +void remove_triplet(struct wy_triplet *trp); void triplet_enqueue(struct wy_triplet *trp); void triplet_commit(struct wy_triplet *trp); void triplet_gpgme_ctx_release(struct wy_triplet *trp); @@ -513,45 +526,12 @@ void report_add(const char *fmt, ...); void report_finish(void); extern char *report_string; -/* job.c */ -/* Wydawca job types */ -enum job_type { - JOB_TRIPLET, /* Process a list of complete triplets */ - JOB_SPOOL, /* Scan single spool */ - JOB_ALL_SPOOLS /* Scan all spools */ -}; - -void job_schedule(int type, void *data); - -static inline void -job_schedule_all(void) -{ - job_schedule(JOB_ALL_SPOOLS, NULL); -} - -static inline void -job_schedule_triplet(struct wy_triplet *tp) -{ - job_schedule(JOB_TRIPLET, tp); -} - -static inline void -job_schedule_spool(struct spool *spool) -{ - job_schedule(JOB_SPOOL, spool); -} - -void job_init(void); -void job_queue_runner(time_t min_timeout); -void job_queue_wait(void); - - /* profile.c */ void check_pidfile(void); void remove_pidfile(void); /* net.c */ -void wydawca_listener(void); +void *wy_thr_listen(void *); void trim_crlf(char *s); #define LOCK_OK 0 @@ -583,3 +563,6 @@ int watcher_run(int); int wy_stat_expansion(char **ret, char const *name, size_t len); FILE *fopenat_ro(int dirfd, char const *name); +void *wy_thr_triplet(void *ptr); +void *wy_thr_cleaner(void *ptr); +void wy_triplet_wait(void); diff --git a/tests/check-fail.at b/tests/check-fail.at index 268ca47..400e2e5 100644 --- a/tests/check-fail.at +++ b/tests/check-fail.at @@ -22,9 +22,6 @@ AT_DATA([experr], wydawca: [[NOTICE]] file.directive.asc: VERSION: 1.1 wydawca: [[NOTICE]] file.directive.asc: COMMENT: Gnupload for Wydawca testsuite wydawca: [[ERR]] spool check script for file@ckfail returned 1 -wydawca: [[NOTICE]] removing ./source/fail/file -wydawca: [[NOTICE]] removing ./source/fail/file.sig -wydawca: [[NOTICE]] removing ./source/fail/file.directive.asc wydawca: [[INFO]] errors: 1 wydawca: [[INFO]] warnings: 0 wydawca: [[INFO]] bad signatures: 0 @@ -39,6 +36,9 @@ wydawca: [[INFO]] files archived: 0 wydawca: [[INFO]] symlinks created: 0 wydawca: [[INFO]] symlinks removed: 0 wydawca: [[INFO]] check failures: 1 +wydawca: [[NOTICE]] removing ./source/fail/file +wydawca: [[NOTICE]] removing ./source/fail/file.sig +wydawca: [[NOTICE]] removing ./source/fail/file.directive.asc wydawca: [[NOTICE]] AT_PACKAGE_TARNAME (AT_PACKAGE_NAME AT_PACKAGE_VERSION) finished ]) diff --git a/tests/check-notify.at b/tests/check-notify.at index 298ebd0..b064412 100644 --- a/tests/check-notify.at +++ b/tests/check-notify.at @@ -22,9 +22,6 @@ AT_DATA([experr], wydawca: [[NOTICE]] file.directive.asc: VERSION: 1.1 wydawca: [[NOTICE]] file.directive.asc: COMMENT: Gnupload for Wydawca testsuite wydawca: [[ERR]] spool check script for file@ckfail returned 1 -wydawca: [[NOTICE]] removing ./source/fail/file -wydawca: [[NOTICE]] removing ./source/fail/file.sig -wydawca: [[NOTICE]] removing ./source/fail/file.directive.asc wydawca: [[INFO]] errors: 1 wydawca: [[INFO]] warnings: 0 wydawca: [[INFO]] bad signatures: 0 @@ -39,6 +36,9 @@ wydawca: [[INFO]] files archived: 0 wydawca: [[INFO]] symlinks created: 0 wydawca: [[INFO]] symlinks removed: 0 wydawca: [[INFO]] check failures: 1 +wydawca: [[NOTICE]] removing ./source/fail/file +wydawca: [[NOTICE]] removing ./source/fail/file.sig +wydawca: [[NOTICE]] removing ./source/fail/file.directive.asc wydawca: [[NOTICE]] AT_PACKAGE_TARNAME (AT_PACKAGE_NAME AT_PACKAGE_VERSION) finished ]) diff --git a/tests/inotify-ok.at b/tests/inotify-ok.at index 5593225..bfe7301 100644 --- a/tests/inotify-ok.at +++ b/tests/inotify-ok.at @@ -35,6 +35,7 @@ wydawca: [[INFO]] files archived: 0 wydawca: [[INFO]] symlinks created: 0 wydawca: [[INFO]] symlinks removed: 0 wydawca: [[INFO]] check failures: 0 +wydawca: [[NOTICE]] shutting down on signal "Terminated" wydawca: [[NOTICE]] AT_PACKAGE_TARNAME (AT_PACKAGE_NAME AT_PACKAGE_VERSION) finished ]) diff --git a/tests/inotify-rmsymlink.at b/tests/inotify-rmsymlink.at index fa806ac..67819ba 100644 --- a/tests/inotify-rmsymlink.at +++ b/tests/inotify-rmsymlink.at @@ -35,6 +35,7 @@ wydawca: [[INFO]] files archived: 0 wydawca: [[INFO]] symlinks created: 0 wydawca: [[INFO]] symlinks removed: 2 wydawca: [[INFO]] check failures: 0 +wydawca: [[NOTICE]] shutting down on signal "Terminated" wydawca: [[NOTICE]] AT_PACKAGE_TARNAME (AT_PACKAGE_NAME AT_PACKAGE_VERSION) finished ]) diff --git a/tests/inotify-symlink.at b/tests/inotify-symlink.at index 409804b..dd690ee 100644 --- a/tests/inotify-symlink.at +++ b/tests/inotify-symlink.at @@ -35,6 +35,7 @@ wydawca: [[INFO]] files archived: 0 wydawca: [[INFO]] symlinks created: 2 wydawca: [[INFO]] symlinks removed: 0 wydawca: [[INFO]] check failures: 0 +wydawca: [[NOTICE]] shutting down on signal "Terminated" wydawca: [[NOTICE]] AT_PACKAGE_TARNAME (AT_PACKAGE_NAME AT_PACKAGE_VERSION) finished ]) diff --git a/tests/inotify-unatt00.at b/tests/inotify-unatt00.at index 1b6dedd..aaba627 100644 --- a/tests/inotify-unatt00.at +++ b/tests/inotify-unatt00.at @@ -35,6 +35,7 @@ wydawca: [[INFO]] files archived: 0 wydawca: [[INFO]] symlinks created: 0 wydawca: [[INFO]] symlinks removed: 0 wydawca: [[INFO]] check failures: 0 +wydawca: [[NOTICE]] shutting down on signal "Terminated" wydawca: [[NOTICE]] AT_PACKAGE_TARNAME (AT_PACKAGE_NAME AT_PACKAGE_VERSION) finished ]) diff --git a/tests/inotify-unatt01.at b/tests/inotify-unatt01.at index c8c6da6..b198a6e 100644 --- a/tests/inotify-unatt01.at +++ b/tests/inotify-unatt01.at @@ -35,6 +35,7 @@ wydawca: [[INFO]] files archived: 0 wydawca: [[INFO]] symlinks created: 0 wydawca: [[INFO]] symlinks removed: 0 wydawca: [[INFO]] check failures: 0 +wydawca: [[NOTICE]] shutting down on signal "Terminated" wydawca: [[NOTICE]] AT_PACKAGE_TARNAME (AT_PACKAGE_NAME AT_PACKAGE_VERSION) finished ]) diff --git a/tests/upl12f.at b/tests/upl12f.at index 51d02e9..900b221 100644 --- a/tests/upl12f.at +++ b/tests/upl12f.at @@ -22,9 +22,6 @@ AT_DATA([experr], wydawca: [[NOTICE]] file.directive.asc: VERSION: 1.2 wydawca: [[NOTICE]] file.directive.asc: COMMENT: Gnupload for Wydawca testsuite wydawca: [[ERR]] refusing to upload file because it already exists and replace is not allowed -wydawca: [[NOTICE]] removing ./source/test/file -wydawca: [[NOTICE]] removing ./source/test/file.sig -wydawca: [[NOTICE]] removing ./source/test/file.directive.asc wydawca: [[INFO]] errors: 1 wydawca: [[INFO]] warnings: 0 wydawca: [[INFO]] bad signatures: 0 @@ -39,6 +36,9 @@ wydawca: [[INFO]] files archived: 0 wydawca: [[INFO]] symlinks created: 0 wydawca: [[INFO]] symlinks removed: 0 wydawca: [[INFO]] check failures: 0 +wydawca: [[NOTICE]] removing ./source/test/file +wydawca: [[NOTICE]] removing ./source/test/file.sig +wydawca: [[NOTICE]] removing ./source/test/file.directive.asc wydawca: [[NOTICE]] AT_PACKAGE_TARNAME (AT_PACKAGE_NAME AT_PACKAGE_VERSION) finished ]) diff --git a/tests/upload-dry.at b/tests/upload-dry.at index 7a53e4f..805dc33 100644 --- a/tests/upload-dry.at +++ b/tests/upload-dry.at @@ -25,8 +25,6 @@ wydawca: [[DEBUG]] ./source/test -> ./dest wydawca: [[DEBUG]] Good signature from Wydawca (Testsuite) wydawca: [[DEBUG]] file: directive file signature OK wydawca: [[NOTICE]] file.directive.asc: VERSION: 1.1 -wydawca: [[DEBUG]] scheduling job triplet(test,file) -wydawca: [[DEBUG]] starting job: triplet(test,file) wydawca: [[DEBUG]] processing triplet `file' wydawca: [[NOTICE]] file.directive.asc: COMMENT: Gnupload for Wydawca testsuite wydawca: [[DEBUG]] good detached signature for file @@ -46,7 +44,6 @@ wydawca: [[INFO]] files archived: 0 wydawca: [[INFO]] symlinks created: 0 wydawca: [[INFO]] symlinks removed: 0 wydawca: [[INFO]] check failures: 0 -wydawca: [[DEBUG]] removing job: triplet(test,file) wydawca: [[NOTICE]] AT_PACKAGE_TARNAME (AT_PACKAGE_NAME AT_PACKAGE_VERSION) finished ]) -- cgit v1.2.1