From 39c155ea0d8b24895017fd5cf48508924ce2016d Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 4 Apr 2013 20:07:48 +0200 Subject: [PATCH] journal: add sd_journal_get_timeout() call to public API Let's do the wake-up logic on NFS internally, making things simpler for users. --- man/sd_journal_get_fd.xml | 130 ++++++++++++++++++++--------- src/journal/journal-internal.h | 2 + src/journal/libsystemd-journal.sym | 1 + src/journal/sd-journal.c | 43 ++++++++-- src/systemd/sd-journal.h | 3 +- 5 files changed, 134 insertions(+), 45 deletions(-) diff --git a/man/sd_journal_get_fd.xml b/man/sd_journal_get_fd.xml index f29aeaab23e..33d2980b3b4 100644 --- a/man/sd_journal_get_fd.xml +++ b/man/sd_journal_get_fd.xml @@ -45,9 +45,10 @@ sd_journal_get_fd sd_journal_get_events - sd_journal_reliable_fd + sd_journal_get_timeout sd_journal_process sd_journal_wait + sd_journal_reliable_fd SD_JOURNAL_NOP SD_JOURNAL_APPEND SD_JOURNAL_INVALIDATE @@ -70,8 +71,9 @@ - int sd_journal_reliable_fd + int sd_journal_get_timeout sd_journal* j + uint64_t* timeout_usec @@ -85,6 +87,11 @@ uint64_t timeout_usec + + int sd_journal_reliable_fd + sd_journal* j + + @@ -103,16 +110,15 @@ events mask to watch for. The call takes one argument: the journal context object. Note that not all file systems are capable of generating the necessary events - for wakeups from this file descriptor to be enirely - reliable. In particular network files systems do not - generate suitable file change events in all cases. In - such a case an application should not rely alone on - wake-ups from this file descriptor but wake up and - recheck the journal in regular time intervals, for - example every 2s. To detect cases where this is - necessary, use + for wakeups from this file descriptor for changes to + be noticed immediately. In particular network files + systems do not generate suitable file change events in + all cases. Cases like this can be detected with sd_journal_reliable_fd(), - below. + below. sd_journal_get_timeout() + will ensure in these cases that wake-ups happen + frequently enough for changes to be noticed, although + with a certain latency. sd_journal_get_events() will return the poll() mask to @@ -122,17 +128,36 @@ the .events field of struct pollfd. - sd_journal_reliable_fd() - may be used to check whether the wakeup events from - the file descriptor returned by - sd_journal_get_fd are sufficient - to track changes to the journal. If this call returns - 0, it is necessary to regularly recheck for journal - changes (suggestion: every 2s). If this call returns a - positive integer this is not necessary, and wakeups - from the file descriptor returned by - sd_journal_get_fd() are - sufficient as only source for wake-ups. + sd_journal_get_timeout() + will return a timeout value for usage in poll(). This returns a value in microseconds since the epoch of CLOCK_MONOTONIC for timing out poll() in timeout_usec. See + clock_gettime2 + for details about + CLOCK_MONOTONIC. If there's no + timeout to wait for this will fill in + (uint64_t) -1 instead. Note that + poll() takes a relative timeout + in milliseconds rather than an absolute timeout in + microseconds. To convert the absolute 'us' timeout into + relative 'ms', use code like the following: + + uint64_t t; +int msec; +sd_journal_get_timeout(m, &t); +if (t == (uint64_t) -1) + msec = -1; +else { + struct timespec ts; + uint64_t n; + clock_getttime(CLOCK_MONOTONIC, &ts); + n = (uint64_t) ts.tv_sec * 1000000 + ts.tv_nsec / 1000; + msec = t > n ? (int) ((t - n + 999) / 1000) : 0; +} + + The code above does not do any error checking + for brevity's sake. The calculated msec + integer can be passed directly as + poll()'s timeout + parameter. After each poll() wake-up sd_journal_process() needs to be @@ -143,22 +168,37 @@ A synchronous alternative for using sd_journal_get_fd(), sd_journal_get_events(), - sd_journal_reliable_fd() and + sd_journal_get_timeout() and sd_journal_process() is sd_journal_wait(). It will - synchronously wait until the journal gets changed, - possibly using a 2s time-out if this is necessary (see - above). In either way the maximum time this call - sleeps may be controlled with the - timeout_usec parameter. Pass - (uint64_t) -1 to wait - indefinitely. Internally this call simply combines - sd_journal_get_fd(), + synchronously wait until the journal gets changed. The + maximum time this call sleeps may be controlled with + the timeout_usec + parameter. Pass (uint64_t) -1 to + wait indefinitely. Internally this call simply + combines sd_journal_get_fd(), sd_journal_get_events(), - sd_journal_reliable_fd(), + sd_journal_get_timeout(), poll() and sd_journal_process() into one. + + sd_journal_reliable_fd() + may be used to check whether the wakeup events from + the file descriptor returned by + sd_journal_get_fd() are known to + be immediately triggered. On certain file systems + where file change events from the OS are not available + (such as NFS) changes need to be polled for + repeatedly, and hence are detected only with a certain + latency. This call will return a positive value if the + journal changes are detected immediately and zero when + they need to be polled for and hence might be noticed + only with a certain latency. Note that there's usually + no need to invoke this function directly as + sd_journal_get_timeout() on these + file systems will ask for timeouts explicitly + anyway. @@ -176,11 +216,9 @@ sd_journal_reliable_fd() returns a positive integer if the file descriptor returned by sd_journal_get_fd() - is sufficient as sole wake-up source for journal - change events. Returns 0 if it is not sufficient and - the journal needs to be checked manually in regular - time intervals for changes. Returns a negative - errno-style error code on failure. + will generate wake-ups immediately for all journal + changes. Returns 0 if there might be a latency + involved. sd_journal_process() and sd_journal_wait() return one of @@ -270,9 +308,22 @@ int main(int argc, char *argv[]) { int wait_for_changes(sd_journal *j) { struct pollfd pollfd; + int msec; + + sd_journal_get_timeout(m, &t); + if (t == (uint64_t) -1) + msec = -1; + else { + struct timespec ts; + uint64_t n; + clock_getttime(CLOCK_MONOTONIC, &ts); + n = (uint64_t) ts.tv_sec * 1000000 + ts.tv_nsec / 1000; + msec = t > n ? (int) ((t - n + 999) / 1000) : 0; + } + pollfd.fd = sd_journal_get_fd(j); pollfd.events = sd_journal_get_events(j); - poll(&pollfd, 1, sd_journal_reliable_fd(j) > 0 ? -1 : 2000); + poll(&pollfd, 1, msec); return sd_journal_process(j); } @@ -286,7 +337,8 @@ int wait_for_changes(sd_journal *j) { sd-journal3, sd_journal_open3, sd_journal_next3, - poll2 + poll2, + clock_gettime2 diff --git a/src/journal/journal-internal.h b/src/journal/journal-internal.h index bc9e44d42d3..3accf14c05e 100644 --- a/src/journal/journal-internal.h +++ b/src/journal/journal-internal.h @@ -126,6 +126,8 @@ struct sd_journal { size_t data_threshold; Set *errors; + + usec_t last_process_usec; }; char *journal_make_match_string(sd_journal *j); diff --git a/src/journal/libsystemd-journal.sym b/src/journal/libsystemd-journal.sym index e241318cb03..cdebf10dedc 100644 --- a/src/journal/libsystemd-journal.sym +++ b/src/journal/libsystemd-journal.sym @@ -97,4 +97,5 @@ global: LIBSYSTEMD_JOURNAL_201 { global: sd_journal_get_events; + sd_journal_get_timeout; } LIBSYSTEMD_JOURNAL_198; diff --git a/src/journal/sd-journal.c b/src/journal/sd-journal.c index 3eba4cd0d1e..c1f69827e98 100644 --- a/src/journal/sd-journal.c +++ b/src/journal/sd-journal.c @@ -1994,6 +1994,30 @@ _public_ int sd_journal_get_events(sd_journal *j) { return POLLIN; } +_public_ int sd_journal_get_timeout(sd_journal *j, uint64_t *timeout_usec) { + int fd; + + if (!j) + return -EINVAL; + if (!timeout_usec) + return -EINVAL; + + fd = sd_journal_get_fd(j); + if (fd < 0) + return fd; + + if (!j->on_network) { + *timeout_usec = (uint64_t) -1; + return 0; + } + + /* If we are on the network we need to regularly check for + * changes manually */ + + *timeout_usec = j->last_process_usec + JOURNAL_FILES_RECHECK_USEC; + return 1; +} + static void process_inotify_event(sd_journal *j, struct inotify_event *e) { Directory *d; int r; @@ -2076,6 +2100,8 @@ _public_ int sd_journal_process(sd_journal *j) { if (!j) return -EINVAL; + j->last_process_usec = now(CLOCK_MONOTONIC); + for (;;) { struct inotify_event *e; ssize_t l; @@ -2109,6 +2135,7 @@ _public_ int sd_journal_process(sd_journal *j) { _public_ int sd_journal_wait(sd_journal *j, uint64_t timeout_usec) { int r; + uint64_t t; assert(j); @@ -2127,12 +2154,18 @@ _public_ int sd_journal_wait(sd_journal *j, uint64_t timeout_usec) { return determine_change(j); } - if (j->on_network) { - /* If we are on the network we need to regularly check - * for changes manually */ + r = sd_journal_get_timeout(j, &t); + if (r < 0) + return r; - if (timeout_usec == (uint64_t) -1 || timeout_usec > JOURNAL_FILES_RECHECK_USEC) - timeout_usec = JOURNAL_FILES_RECHECK_USEC; + if (t != (uint64_t) -1) { + usec_t n; + + n = now(CLOCK_MONOTONIC); + t = t > n ? t - n : 0; + + if (timeout_usec == (uint64_t) -1 || timeout_usec > t) + timeout_usec = t; } do { diff --git a/src/systemd/sd-journal.h b/src/systemd/sd-journal.h index aa7693af70b..afafee2d827 100644 --- a/src/systemd/sd-journal.h +++ b/src/systemd/sd-journal.h @@ -128,9 +128,10 @@ void sd_journal_restart_unique(sd_journal *j); int sd_journal_get_fd(sd_journal *j); int sd_journal_get_events(sd_journal *j); -int sd_journal_reliable_fd(sd_journal *j); +int sd_journal_get_timeout(sd_journal *j, uint64_t *timeout_usec); int sd_journal_process(sd_journal *j); int sd_journal_wait(sd_journal *j, uint64_t timeout_usec); +int sd_journal_reliable_fd(sd_journal *j); int sd_journal_get_catalog(sd_journal *j, char **text); int sd_journal_get_catalog_for_message_id(sd_id128_t id, char **ret);