Commit 39c155ea authored by Lennart Poettering's avatar Lennart Poettering

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.
parent 667c24a6
......@@ -45,9 +45,10 @@
<refnamediv>
<refname>sd_journal_get_fd</refname>
<refname>sd_journal_get_events</refname>
<refname>sd_journal_reliable_fd</refname>
<refname>sd_journal_get_timeout</refname>
<refname>sd_journal_process</refname>
<refname>sd_journal_wait</refname>
<refname>sd_journal_reliable_fd</refname>
<refname>SD_JOURNAL_NOP</refname>
<refname>SD_JOURNAL_APPEND</refname>
<refname>SD_JOURNAL_INVALIDATE</refname>
......@@ -70,8 +71,9 @@
</funcprototype>
<funcprototype>
<funcdef>int <function>sd_journal_reliable_fd</function></funcdef>
<funcdef>int <function>sd_journal_get_timeout</function></funcdef>
<paramdef>sd_journal* <parameter>j</parameter></paramdef>
<paramdef>uint64_t* <parameter>timeout_usec</parameter></paramdef>
</funcprototype>
<funcprototype>
......@@ -85,6 +87,11 @@
<paramdef>uint64_t <parameter>timeout_usec</parameter></paramdef>
</funcprototype>
<funcprototype>
<funcdef>int <function>sd_journal_reliable_fd</function></funcdef>
<paramdef>sd_journal* <parameter>j</parameter></paramdef>
</funcprototype>
</funcsynopsis>
</refsynopsisdiv>
......@@ -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
<function>sd_journal_reliable_fd()</function>,
below.</para>
below. <function>sd_journal_get_timeout()</function>
will ensure in these cases that wake-ups happen
frequently enough for changes to be noticed, although
with a certain latency.</para>
<para><function>sd_journal_get_events()</function>
will return the <function>poll()</function> mask to
......@@ -122,17 +128,36 @@
the <literal>.events</literal> field of
<literal>struct pollfd</literal>.</para>
<para><function>sd_journal_reliable_fd()</function>
may be used to check whether the wakeup events from
the file descriptor returned by
<function>sd_journal_get_fd</function> 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
<function>sd_journal_get_fd()</function> are
sufficient as only source for wake-ups.</para>
<para><function>sd_journal_get_timeout()</function>
will return a timeout value for usage in <function>poll()</function>. This returns a value in microseconds since the epoch of CLOCK_MONOTONIC for timing out <function>poll()</function> in <literal>timeout_usec</literal>. See
<citerefentry><refentrytitle>clock_gettime</refentrytitle><manvolnum>2</manvolnum></citerefentry>
for details about
<literal>CLOCK_MONOTONIC</literal>. If there's no
timeout to wait for this will fill in
<literal>(uint64_t) -1</literal> instead. Note that
<function>poll()</function> 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:</para>
<programlisting>uint64_t t;
int msec;
sd_journal_get_timeout(m, &amp;t);
if (t == (uint64_t) -1)
msec = -1;
else {
struct timespec ts;
uint64_t n;
clock_getttime(CLOCK_MONOTONIC, &amp;ts);
n = (uint64_t) ts.tv_sec * 1000000 + ts.tv_nsec / 1000;
msec = t > n ? (int) ((t - n + 999) / 1000) : 0;
}</programlisting>
<para>The code above does not do any error checking
for brevity's sake. The calculated <literal>msec</literal>
integer can be passed directly as
<function>poll()</function>'s timeout
parameter.</para>
<para>After each <function>poll()</function> wake-up
<function>sd_journal_process()</function> needs to be
......@@ -143,22 +168,37 @@
<para>A synchronous alternative for using
<function>sd_journal_get_fd()</function>,
<function>sd_journal_get_events()</function>,
<function>sd_journal_reliable_fd()</function> and
<function>sd_journal_get_timeout()</function> and
<function>sd_journal_process()</function> is
<function>sd_journal_wait()</function>. 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
<parameter>timeout_usec</parameter> parameter. Pass
<literal>(uint64_t) -1</literal> to wait
indefinitely. Internally this call simply combines
<function>sd_journal_get_fd()</function>,
synchronously wait until the journal gets changed. The
maximum time this call sleeps may be controlled with
the <parameter>timeout_usec</parameter>
parameter. Pass <literal>(uint64_t) -1</literal> to
wait indefinitely. Internally this call simply
combines <function>sd_journal_get_fd()</function>,
<function>sd_journal_get_events()</function>,
<function>sd_journal_reliable_fd()</function>,
<function>sd_journal_get_timeout()</function>,
<function>poll()</function> and
<function>sd_journal_process()</function> into
one.</para>
<para><function>sd_journal_reliable_fd()</function>
may be used to check whether the wakeup events from
the file descriptor returned by
<function>sd_journal_get_fd()</function> 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
<function>sd_journal_get_timeout()</function> on these
file systems will ask for timeouts explicitly
anyway.</para>
</refsect1>
<refsect1>
......@@ -176,11 +216,9 @@
<para><function>sd_journal_reliable_fd()</function>
returns a positive integer if the file descriptor
returned by <function>sd_journal_get_fd()</function>
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.</para>
will generate wake-ups immediately for all journal
changes. Returns 0 if there might be a latency
involved.</para>
<para><function>sd_journal_process()</function> and
<function>sd_journal_wait()</function> 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, &amp;t);
if (t == (uint64_t) -1)
msec = -1;
else {
struct timespec ts;
uint64_t n;
clock_getttime(CLOCK_MONOTONIC, &amp;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(&amp;pollfd, 1, sd_journal_reliable_fd(j) &gt; 0 ? -1 : 2000);
poll(&amp;pollfd, 1, msec);
return sd_journal_process(j);
}
</programlisting>
......@@ -286,7 +337,8 @@ int wait_for_changes(sd_journal *j) {
<citerefentry><refentrytitle>sd-journal</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
<citerefentry><refentrytitle>sd_journal_open</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
<citerefentry><refentrytitle>sd_journal_next</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
<citerefentry><refentrytitle>poll</refentrytitle><manvolnum>2</manvolnum></citerefentry>
<citerefentry><refentrytitle>poll</refentrytitle><manvolnum>2</manvolnum></citerefentry>,
<citerefentry><refentrytitle>clock_gettime</refentrytitle><manvolnum>2</manvolnum></citerefentry>
</para>
</refsect1>
......
......@@ -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);
......
......@@ -97,4 +97,5 @@ global:
LIBSYSTEMD_JOURNAL_201 {
global:
sd_journal_get_events;
sd_journal_get_timeout;
} LIBSYSTEMD_JOURNAL_198;
......@@ -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 (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 > JOURNAL_FILES_RECHECK_USEC)
timeout_usec = JOURNAL_FILES_RECHECK_USEC;
if (timeout_usec == (uint64_t) -1 || timeout_usec > t)
timeout_usec = t;
}
do {
......
......@@ -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);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment