redmine

Added "--pre-exit-hook"

... ... @@ -155,6 +155,7 @@ enum state_enum {
STATE_STARTING,
STATE_RUNNING,
STATE_REHASH,
STATE_PREEXIT,
STATE_TERM,
STATE_THREAD_GC,
STATE_INITSYNC,
... ...
... ... @@ -84,23 +84,24 @@ enum flags_enum {
EXITONNOEVENTS = 8|OPTION_LONGOPTONLY,
STANDBYFILE = 9|OPTION_LONGOPTONLY,
EXITHOOK = 10|OPTION_LONGOPTONLY,
PREEXITHOOK = 12|OPTION_LONGOPTONLY,
SOCKETAUTH = 12|OPTION_LONGOPTONLY,
SOCKETMOD = 13|OPTION_LONGOPTONLY,
SOCKETOWN = 14|OPTION_LONGOPTONLY,
SOCKETAUTH = 13|OPTION_LONGOPTONLY,
SOCKETMOD = 14|OPTION_LONGOPTONLY,
SOCKETOWN = 15|OPTION_LONGOPTONLY,
MAXITERATIONS = 15|OPTION_LONGOPTONLY,
MAXITERATIONS = 16|OPTION_LONGOPTONLY,
IGNOREFAILURES = 16|OPTION_LONGOPTONLY,
IGNOREFAILURES = 17|OPTION_LONGOPTONLY,
DUMPDIR = 17|OPTION_LONGOPTONLY,
DUMPDIR = 18|OPTION_LONGOPTONLY,
CONFIGBLOCKINHERITS = 18|OPTION_LONGOPTONLY,
CONFIGBLOCKINHERITS = 19|OPTION_LONGOPTONLY,
MONITOR = 19|OPTION_LONGOPTONLY,
MONITOR = 20|OPTION_LONGOPTONLY,
SYNCHANDLERARGS0 = 20|OPTION_LONGOPTONLY,
SYNCHANDLERARGS1 = 21|OPTION_LONGOPTONLY,
SYNCHANDLERARGS0 = 21|OPTION_LONGOPTONLY,
SYNCHANDLERARGS1 = 22|OPTION_LONGOPTONLY,
};
typedef enum flags_enum flags_t;
... ... @@ -221,6 +222,7 @@ struct ctx {
char *pidfile;
char *standbyfile;
char *exithookfile;
char *preexithookfile;
char *destdir;
char *destproto;
char *watchdirwslash;
... ...
... ... @@ -96,6 +96,7 @@ static const struct option long_options[] =
{"skip-initialsync", optional_argument, NULL, SKIPINITSYNC},
{"exit-on-no-events", optional_argument, NULL, EXITONNOEVENTS},
{"exit-hook", required_argument, NULL, EXITHOOK},
{"pre-exit-hook", required_argument, NULL, PREEXITHOOK},
{"verbose", optional_argument, NULL, VERBOSE},
{"debug", optional_argument, NULL, DEBUG},
{"dump-dir", required_argument, NULL, DUMPDIR},
... ... @@ -648,13 +649,22 @@ int parse_parameter(ctx_t *ctx_p, uint16_t param_id, char *arg, paramsource_t pa
case SYNCTIMEOUT:
ctx_p->synctimeout = (unsigned int)atol(arg);
break;
case PREEXITHOOK:
if (strlen(arg)) {
ctx_p->preexithookfile = arg;
ctx_p->flags[PREEXITHOOK] = 1;
} else {
ctx_p->preexithookfile = NULL;
ctx_p->flags[PREEXITHOOK] = 0;
}
break;
case EXITHOOK:
if(strlen(arg)) {
if (strlen(arg)) {
ctx_p->exithookfile = arg;
ctx_p->flags[EXITHOOK] = 1;
ctx_p->flags[EXITHOOK] = 1;
} else {
ctx_p->exithookfile = NULL;
ctx_p->flags[EXITHOOK] = 0;
ctx_p->flags[EXITHOOK] = 0;
}
break;
case IGNOREEXITCODE: {
... ... @@ -1499,6 +1509,10 @@ int main(int argc, char *argv[]) {
ret = errno = EINVAL;
error("Conflicting options: This value of \"--threading\" cannot be used in conjunction with \"--max-iterations\".");
}
if(ctx_p->flags[THREADING] && ctx_p->flags[PREEXITHOOK]) {
ret = errno = EINVAL;
error("Conflicting options: This value of \"--threading\" cannot be used in conjunction with \"--pre-exit-hook\".");
}
if(ctx_p->flags[SKIPINITSYNC] && ctx_p->flags[EXITONNOEVENTS]) {
ret = errno = EINVAL;
error("Conflicting options: \"--skip-initialsync\" and \"--exit-on-no-events\" cannot be used together.");
... ...
... ... @@ -250,6 +250,10 @@ running threads' garbage collector
.RS
received signal to die, preparing to die
.RE
.IR preexit
.RS
waiting for the last iteration
.RE
.IR exiting
.RS
cleaning up [for
... ... @@ -818,7 +822,24 @@ If this parameter is set, clsync will exec on exit:
.I path\-of\-exit\-hook\-program label
.RE
The execution will be skipped if syncing process wasn't started.
The execution will be skipped if initial sync wasn't complete.
Is not set by default.
.RE
.PP
.B \-\-pre\-exit\-hook
.I path\-of\-pre\-exit\-hook\-program
.RS 8
Sets path of program to be executed before the last sync iteration (see
.IR "\-\-max\-iterations" " and " "\-\-exit\-on\-no\-events" ")."
If this parameter is set, clsync will exec on exit:
.RS
.I path\-of\-pre\-exit\-hook\-program label
.RE
The execution will be skipped if initial sync wasn't complete.
Is not set by default.
.RE
... ... @@ -1511,18 +1532,25 @@ Syncing /srv/lxc tree (rsync case):
.RE
.SH SIGNALS
1 \- to reread filter rules
1 \- (HUP) rereads filter rules
2 \- (INT) exits without waiting of syncing processes
10 \- runs threads' GC function
12 \- runs full resync
15 \- (TERM) waits for current syncing processes and exit ("soft kill")
16 \- interrupts sleep()/select() and wait() [for debugging and internal uses]
29 \- dump information to
.IR dump-dir
[for debugging]
If you need to kill clsync but leave children then you can use 9-th (KILL)
signal.
.SH DIAGNOSTICS
Initial rsync process works very slow on clsync start
... ...
... ... @@ -3041,6 +3041,18 @@ int notify_wait(ctx_t *ctx_p, indexes_t *indexes_p) {
continue;\
}
void hook_preexit(ctx_t *ctx_p) {
#ifdef VERYPARANOID
if (ctx_p->preexithookfile == NULL)
critical("ctx_p->preexithookfile == NULL");
#endif
char *argv[] = { ctx_p->preexithookfile, ctx_p->label, NULL};
exec_argv(argv, NULL);
return;
}
int sync_loop(ctx_t *ctx_p, indexes_t *indexes_p) {
int state = ctx_p->flags[SKIPINITSYNC] ? STATE_RUNNING : STATE_INITSYNC;
int ret;
... ... @@ -3084,17 +3096,28 @@ int sync_loop(ctx_t *ctx_p, indexes_t *indexes_p) {
state = STATE_RUNNING;
continue;
case STATE_PREEXIT:
case STATE_RUNNING:
if(!ctx_p->flags[THREADING])
if (ctx_p->flags[MAXITERATIONS] &&
ctx_p->flags[MAXITERATIONS] <= ctx_p->iteration_num)
state = STATE_EXIT;
if((!ctx_p->flags[THREADING]) && ctx_p->flags[MAXITERATIONS]) {
if (ctx_p->flags[MAXITERATIONS] == ctx_p->iteration_num-1)
state = STATE_PREEXIT;
else
if (ctx_p->flags[MAXITERATIONS] <= ctx_p->iteration_num)
state = STATE_EXIT;
}
if(state == STATE_RUNNING)
events = notify_wait(ctx_p, indexes_p);
switch (state) {
case STATE_PREEXIT:
main_status_update(ctx_p, state);
if (ctx_p->flags[PREEXITHOOK])
hook_preexit(ctx_p);
case STATE_RUNNING:
events = notify_wait(ctx_p, indexes_p);
break;
default:
SYNC_LOOP_CONTINUE_UNLOCK;
}
if(state != STATE_RUNNING)
SYNC_LOOP_CONTINUE_UNLOCK;
break;
case STATE_REHASH:
main_status_update(ctx_p, state);
... ... @@ -3112,24 +3135,24 @@ int sync_loop(ctx_t *ctx_p, indexes_t *indexes_p) {
pthread_cond_broadcast(&threadsinfo_p->cond[PTHREAD_MUTEX_STATE]);
pthread_mutex_unlock(&threadsinfo_p->mutex[PTHREAD_MUTEX_STATE]);
if(events == 0) {
if (events == 0) {
debug(2, "sync_x_wait(ctx_p, indexes_p) timed-out.");
SYNC_LOOP_IDLE;
continue; // Timeout
}
if(events < 0) {
if (events < 0) {
error("Got error while waiting for event from notify subsystem.");
return errno;
}
int count = ctx_p->notifyenginefunct.handle(ctx_p, indexes_p);
if(count <= 0) {
if (count <= 0) {
error("Cannot handle with notify events.");
return errno;
}
main_status_update(ctx_p, state);
if(ctx_p->flags[EXITONNOEVENTS]) // clsync exits on no events, so sync_idle() is never called. We have to force the calling of it.
if (ctx_p->flags[EXITONNOEVENTS]) // clsync exits on no events, so sync_idle() is never called. We have to force the calling of it.
SYNC_LOOP_IDLE;
}
... ... @@ -3469,10 +3492,15 @@ int sync_sighandler(sighandler_arg_t *sighandler_arg_p) {
case SIGALRM:
*exitcode_p = ETIME;
case SIGTERM:
if (ctx_p->flags[PREEXITHOOK])
sync_switch_state(pthread_parent, STATE_PREEXIT);
else
sync_switch_state(pthread_parent, STATE_TERM);
break;
case SIGINT:
sync_switch_state(pthread_parent, STATE_TERM);
// bugfix of https://github.com/xaionaro/clsync/issues/44
while(ctx_p->children) { // Killing children if non-pthread mode or/and (mode=="so" or mode=="rsyncso")
while (ctx_p->children) { // Killing children if non-pthread mode or/and (mode=="so" or mode=="rsyncso")
pid_t child_pid = ctx_p->child_pid[--ctx_p->children];
if(waitpid(child_pid, NULL, WNOHANG)>=0) {
debug(3, "Sending signal %u to child process with pid %u.",
... ...