[systemd-commits] 7 commits - .gitignore Makefile.am TODO src/journal src/login

Lennart Poettering lennart at kemper.freedesktop.org
Tue Nov 26 17:40:18 PST 2013


 .gitignore                       |    1 
 Makefile.am                      |    7 +
 TODO                             |    5 -
 src/journal/journal-file.c       |  157 ++++++++++++++++++++++++++-------------
 src/journal/journald-server.c    |   11 ++
 src/journal/test-journal-flush.c |   71 +++++++++++++++++
 src/login/logind-action.c        |   20 +++-
 src/login/logind-core.c          |    2 
 src/login/logind-dbus.c          |   17 ++--
 src/login/logind-inhibit.c       |    6 +
 src/login/logind-inhibit.h       |    2 
 11 files changed, 231 insertions(+), 68 deletions(-)

New commits:
commit 85a428c69465b047731b6abb5005f01824f1444e
Author: Lennart Poettering <lennart at poettering.net>
Date:   Wed Nov 27 02:38:06 2013 +0100

    logind: log which process is delaying suspend and not closing locks

diff --git a/src/login/logind-action.c b/src/login/logind-action.c
index cb64df0..7744add 100644
--- a/src/login/logind-action.c
+++ b/src/login/logind-action.c
@@ -58,6 +58,7 @@ int manager_handle_action(
 
         _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
         InhibitWhat inhibit_operation;
+        Inhibitor *offending = NULL;
         bool supported;
         int r;
 
@@ -71,7 +72,7 @@ int manager_handle_action(
 
         /* If the key handling is inhibited, don't do anything */
         if (inhibit_key > 0) {
-                if (manager_is_inhibited(m, inhibit_key, INHIBIT_BLOCK, NULL, true, false, 0)) {
+                if (manager_is_inhibited(m, inhibit_key, INHIBIT_BLOCK, NULL, true, false, 0, NULL)) {
                         log_debug("Refusing operation, %s is inhibited.", inhibit_what_to_string(inhibit_key));
                         return 0;
                 }
@@ -109,15 +110,26 @@ int manager_handle_action(
 
         /* If the actual operation is inhibited, warn and fail */
         if (!ignore_inhibited &&
-            manager_is_inhibited(m, inhibit_operation, INHIBIT_BLOCK, NULL, false, false, 0)) {
+            manager_is_inhibited(m, inhibit_operation, INHIBIT_BLOCK, NULL, false, false, 0, &offending)) {
+                _cleanup_free_ char *comm = NULL, *u = NULL;
+
+                get_process_comm(offending->pid, &comm);
+                u = uid_to_name(offending->uid);
 
                 /* If this is just a recheck of the lid switch then don't warn about anything */
                 if (!is_edge) {
-                        log_debug("Refusing operation, %s is inhibited.", inhibit_what_to_string(inhibit_operation));
+                        log_debug("Refusing operation, %s is inhibited by UID %lu/%s, PID %lu/%s.",
+                                  inhibit_what_to_string(inhibit_operation),
+                                  (unsigned long) offending->uid, strna(u),
+                                  (unsigned long) offending->pid, strna(comm));
                         return 0;
                 }
 
-                log_error("Refusing operation, %s is inhibited.", inhibit_what_to_string(inhibit_operation));
+                log_error("Refusing operation, %s is inhibited by UID %lu/%s, PID %lu/%s.",
+                          inhibit_what_to_string(inhibit_operation),
+                          (unsigned long) offending->uid, strna(u),
+                          (unsigned long) offending->pid, strna(comm));
+
                 warn_melody();
                 return -EPERM;
         }
diff --git a/src/login/logind-core.c b/src/login/logind-core.c
index 9c31bf8..72ee9fe 100644
--- a/src/login/logind-core.c
+++ b/src/login/logind-core.c
@@ -389,7 +389,7 @@ int manager_get_idle_hint(Manager *m, dual_timestamp *t) {
 
         assert(m);
 
-        idle_hint = !manager_is_inhibited(m, INHIBIT_IDLE, INHIBIT_BLOCK, t, false, false, 0);
+        idle_hint = !manager_is_inhibited(m, INHIBIT_IDLE, INHIBIT_BLOCK, t, false, false, 0, NULL);
 
         HASHMAP_FOREACH(s, m->sessions, i) {
                 dual_timestamp k;
diff --git a/src/login/logind-dbus.c b/src/login/logind-dbus.c
index a972d93..e0333cd 100644
--- a/src/login/logind-dbus.c
+++ b/src/login/logind-dbus.c
@@ -1399,7 +1399,7 @@ int bus_manager_shutdown_or_sleep_now_or_later(
 
         delayed =
                 m->inhibit_delay_max > 0 &&
-                manager_is_inhibited(m, w, INHIBIT_DELAY, NULL, false, false, 0);
+                manager_is_inhibited(m, w, INHIBIT_DELAY, NULL, false, false, 0, NULL);
 
         if (delayed)
                 /* Shutdown is delayed, keep in mind what we
@@ -1465,7 +1465,7 @@ static int method_do_shutdown_or_sleep(
                 return r;
 
         multiple_sessions = r > 0;
-        blocked = manager_is_inhibited(m, w, INHIBIT_BLOCK, NULL, false, true, uid);
+        blocked = manager_is_inhibited(m, w, INHIBIT_BLOCK, NULL, false, true, uid, NULL);
 
         if (multiple_sessions) {
                 r = bus_verify_polkit_async(m->bus, &m->polkit_registry, message,
@@ -1610,7 +1610,7 @@ static int method_can_shutdown_or_sleep(
                 return r;
 
         multiple_sessions = r > 0;
-        blocked = manager_is_inhibited(m, w, INHIBIT_BLOCK, NULL, false, true, uid);
+        blocked = manager_is_inhibited(m, w, INHIBIT_BLOCK, NULL, false, true, uid, NULL);
 
         if (multiple_sessions) {
                 r = bus_verify_polkit(m->bus, message, action_multiple_sessions, false, &challenge, error);
@@ -2105,6 +2105,7 @@ int manager_send_changed(Manager *manager, const char *property, ...) {
 
 int manager_dispatch_delayed(Manager *manager) {
         _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
+        Inhibitor *offending = NULL;
         int r;
 
         assert(manager);
@@ -2113,12 +2114,18 @@ int manager_dispatch_delayed(Manager *manager) {
                 return 0;
 
         /* Continue delay? */
-        if (manager_is_inhibited(manager, manager->action_what, INHIBIT_DELAY, NULL, false, false, 0)) {
+        if (manager_is_inhibited(manager, manager->action_what, INHIBIT_DELAY, NULL, false, false, 0, &offending)) {
+                _cleanup_free_ char *comm = NULL, *u = NULL;
+
+                get_process_comm(offending->pid, &comm);
+                u = uid_to_name(offending->uid);
 
                 if (manager->action_timestamp + manager->inhibit_delay_max > now(CLOCK_MONOTONIC))
                         return 0;
 
-                log_info("Delay lock is active but inhibitor timeout is reached.");
+                log_info("Delay lock is active (UID %lu/%s, PID %lu/%s) but inhibitor timeout is reached.",
+                         (unsigned long) offending->uid, strna(u),
+                         (unsigned long) offending->pid, strna(comm));
         }
 
         /* Actually do the operation */
diff --git a/src/login/logind-inhibit.c b/src/login/logind-inhibit.c
index 1b6f136..35e1abd 100644
--- a/src/login/logind-inhibit.c
+++ b/src/login/logind-inhibit.c
@@ -372,7 +372,8 @@ bool manager_is_inhibited(
                 dual_timestamp *since,
                 bool ignore_inactive,
                 bool ignore_uid,
-                uid_t uid) {
+                uid_t uid,
+                Inhibitor **offending) {
 
         Inhibitor *i;
         Iterator j;
@@ -400,6 +401,9 @@ bool manager_is_inhibited(
                         ts = i->since;
 
                 inhibited = true;
+
+                if (offending)
+                        *offending = i;
         }
 
         if (since)
diff --git a/src/login/logind-inhibit.h b/src/login/logind-inhibit.h
index da3d7e7..f767876 100644
--- a/src/login/logind-inhibit.h
+++ b/src/login/logind-inhibit.h
@@ -85,7 +85,7 @@ int inhibitor_create_fifo(Inhibitor *i);
 void inhibitor_remove_fifo(Inhibitor *i);
 
 InhibitWhat manager_inhibit_what(Manager *m, InhibitMode mm);
-bool manager_is_inhibited(Manager *m, InhibitWhat w, InhibitMode mm, dual_timestamp *since, bool ignore_inactive, bool ignore_uid, uid_t uid);
+bool manager_is_inhibited(Manager *m, InhibitWhat w, InhibitMode mm, dual_timestamp *since, bool ignore_inactive, bool ignore_uid, uid_t uid, Inhibitor **offending);
 
 const char *inhibit_what_to_string(InhibitWhat k);
 InhibitWhat inhibit_what_from_string(const char *s);

commit fbb634117d0b0ebd5b105e65b141e75ae9af7f8f
Author: Lennart Poettering <lennart at poettering.net>
Date:   Wed Nov 27 01:54:25 2013 +0100

    journald: mention how long we needed to flush to /var in the logs

diff --git a/src/journal/journald-server.c b/src/journal/journald-server.c
index ce419d4..01e75b6 100644
--- a/src/journal/journald-server.c
+++ b/src/journal/journald-server.c
@@ -970,9 +970,12 @@ static int system_journal_open(Server *s) {
 }
 
 int server_flush_to_var(Server *s) {
-        int r;
         sd_id128_t machine;
         sd_journal *j = NULL;
+        char ts[FORMAT_TIMESPAN_MAX];
+        usec_t start;
+        unsigned n = 0;
+        int r;
 
         assert(s);
 
@@ -990,6 +993,8 @@ int server_flush_to_var(Server *s) {
 
         log_debug("Flushing to /var...");
 
+        start = now(CLOCK_MONOTONIC);
+
         r = sd_id128_get_machine(&machine);
         if (r < 0)
                 return r;
@@ -1009,6 +1014,8 @@ int server_flush_to_var(Server *s) {
                 f = j->current_file;
                 assert(f && f->current_offset > 0);
 
+                n++;
+
                 r = journal_file_move_to_object(f, OBJECT_ENTRY, f->current_offset, &o);
                 if (r < 0) {
                         log_error("Can't read entry: %s", strerror(-r));
@@ -1052,6 +1059,8 @@ finish:
 
         sd_journal_close(j);
 
+        server_driver_message(s, SD_ID128_NULL, "Time spent on flushing to /var is %s for %u entries.", format_timespan(ts, sizeof(ts), now(CLOCK_MONOTONIC) - start, 0), n);
+
         return r;
 }
 

commit eda4b58b50509dc8ad0428a46e20f6c5cf516d58
Author: Lennart Poettering <lennart at poettering.net>
Date:   Wed Nov 27 01:44:52 2013 +0100

    journal: simplify pre-allocation logic
    
    let's just do a single fallocate() as far as possible, and don't
    distuingish between allocated space and file size.
    
    This way we can save a syscall for each append, which makes quite some
    benefits.

diff --git a/src/journal/journal-file.c b/src/journal/journal-file.c
index 14eae8f..4009b29 100644
--- a/src/journal/journal-file.c
+++ b/src/journal/journal-file.c
@@ -315,7 +315,7 @@ static int journal_file_verify_header(JournalFile *f) {
 }
 
 static int journal_file_allocate(JournalFile *f, uint64_t offset, uint64_t size) {
-        uint64_t old_size, new_size, file_size;
+        uint64_t old_size, new_size;
         int r;
 
         assert(f);
@@ -356,6 +356,11 @@ static int journal_file_allocate(JournalFile *f, uint64_t offset, uint64_t size)
                 }
         }
 
+        /* Increase by larger blocks at once */
+        new_size = ((new_size+FILE_SIZE_INCREASE-1) / FILE_SIZE_INCREASE) * FILE_SIZE_INCREASE;
+        if (f->metrics.max_size > 0 && new_size > f->metrics.max_size)
+                new_size = f->metrics.max_size;
+
         /* Note that the glibc fallocate() fallback is very
            inefficient, hence we try to minimize the allocation area
            as we can. */
@@ -363,16 +368,8 @@ static int journal_file_allocate(JournalFile *f, uint64_t offset, uint64_t size)
         if (r != 0)
                 return -r;
 
-        /* Increase the file size a bit further than this, so that we
-         * we can create larger memory maps to cache */
-        file_size = ((new_size+FILE_SIZE_INCREASE-1) / FILE_SIZE_INCREASE) * FILE_SIZE_INCREASE;
-        if (file_size > (uint64_t) f->last_stat.st_size) {
-                if (file_size > new_size)
-                        ftruncate(f->fd, file_size);
-
-                if (fstat(f->fd, &f->last_stat) < 0)
-                        return -errno;
-        }
+        if (fstat(f->fd, &f->last_stat) < 0)
+                return -errno;
 
         f->header->arena_size = htole64(new_size - le64toh(f->header->header_size));
 

commit d0767ffd08bbb5c069e266710eb0462315e47e6d
Author: Lennart Poettering <lennart at poettering.net>
Date:   Wed Nov 27 01:01:53 2013 +0100

    journal: add a test case for flushing messages out of a series of journal files into a single new one

diff --git a/.gitignore b/.gitignore
index 8d0d770..f8f6c8a 100644
--- a/.gitignore
+++ b/.gitignore
@@ -123,6 +123,7 @@
 /test-job-type
 /test-journal
 /test-journal-enum
+/test-journal-flush
 /test-journal-interleaving
 /test-journal-match
 /test-journal-send
diff --git a/Makefile.am b/Makefile.am
index 47c269d..0119751 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -2961,6 +2961,12 @@ test_journal_stream_SOURCES = \
 test_journal_stream_LDADD = \
 	libsystemd-journal-core.la
 
+test_journal_flush_SOURCES = \
+	src/journal/test-journal-flush.c
+
+test_journal_flush_LDADD = \
+	libsystemd-journal-core.la
+
 test_journal_init_SOURCES = \
 	src/journal/test-journal-init.c
 
@@ -3167,6 +3173,7 @@ tests += \
 	test-journal-init \
 	test-journal-verify \
 	test-journal-interleaving \
+	test-journal-flush \
 	test-mmap-cache \
 	test-catalog
 
diff --git a/TODO b/TODO
index 653258a..3383f35 100644
--- a/TODO
+++ b/TODO
@@ -85,8 +85,6 @@ Features:
 
 * be more careful what we export on the bus as (usec_t) 0 and (usec_t) -1
 
-* increase journal files by a few MB each time, instead of piecemeal
-
 * add field to transient units that indicate whether systemd or somebody else saves/restores its settings, for integration with libvirt
 
 * systemctl: rework wait filter to not require match callback
@@ -392,9 +390,6 @@ Features:
 * service: watchdog logic: for testing purposes allow ping, but do not require pong
 
 * journal:
-  - do not use magic msync() in src/journal/journal-file.c, just call fsync()
-      <alxchk> poettering: looks like msync just calls vfs_fsync
-      http://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/tree/mm/msync.c#n18
   - import and delete pstore filesystem content at startup
   - journald: also get thread ID from client, plus thread name
   - journal: when waiting for journal additions in the client always sleep at least 1s or so, in order to minimize wakeups
diff --git a/src/journal/test-journal-flush.c b/src/journal/test-journal-flush.c
new file mode 100644
index 0000000..e61e87a
--- /dev/null
+++ b/src/journal/test-journal-flush.c
@@ -0,0 +1,71 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+  This file is part of systemd.
+
+  Copyright 2013 Lennart Poettering
+
+  systemd is free software; you can redistribute it and/or modify it
+  under the terms of the GNU Lesser General Public License as published by
+  the Free Software Foundation; either version 2.1 of the License, or
+  (at your option) any later version.
+
+  systemd 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
+  Lesser General Public License for more details.
+
+  You should have received a copy of the GNU Lesser General Public License
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <fcntl.h>
+
+#include "sd-journal.h"
+#include "journal-file.h"
+#include "journal-internal.h"
+
+int main(int argc, char *argv[]) {
+
+        char fn[sizeof("/var/tmp/test-journal-flush-")-1 + DECIMAL_STR_MAX(pid_t) + sizeof(".journal")];
+        JournalFile *new_journal = NULL;
+        sd_journal *j = NULL;
+        unsigned n = 0;
+        int r;
+
+        sprintf(fn, "/var/tmp/test-journal-flush-%lu.journal", (unsigned long) getpid());
+
+        r = journal_file_open(fn, O_CREAT|O_RDWR, 0644, false, false, NULL, NULL, NULL, &new_journal);
+        assert_se(r >= 0);
+
+        unlink(fn);
+
+        r = sd_journal_open(&j, 0);
+        assert_se(r >= 0);
+
+        sd_journal_set_data_threshold(j, 0);
+
+        SD_JOURNAL_FOREACH(j) {
+                Object *o;
+                JournalFile *f;
+
+                f = j->current_file;
+                assert(f && f->current_offset > 0);
+
+                r = journal_file_move_to_object(f, OBJECT_ENTRY, f->current_offset, &o);
+                assert(r >= 0);
+
+                r = journal_file_copy_entry(f, new_journal, o, f->current_offset, NULL, NULL, NULL);
+                assert(r >= 0);
+
+                n++;
+                if (n > 10000)
+                        break;
+        }
+
+        sd_journal_close(j);
+
+        journal_file_close(new_journal);
+
+        return 0;
+}

commit 248c78c79c5cca9b981800d816a77591e504066a
Author: Lennart Poettering <lennart at poettering.net>
Date:   Wed Nov 27 00:59:07 2013 +0100

    journal: allow journal_file_copy_entry() to work on non-local files

diff --git a/src/journal/journal-file.c b/src/journal/journal-file.c
index 409be76..14eae8f 100644
--- a/src/journal/journal-file.c
+++ b/src/journal/journal-file.c
@@ -2732,10 +2732,6 @@ int journal_file_copy_entry(JournalFile *from, JournalFile *to, Object *o, uint6
         ts.monotonic = le64toh(o->entry.monotonic);
         ts.realtime = le64toh(o->entry.realtime);
 
-        if (to->tail_entry_monotonic_valid &&
-            ts.monotonic < le64toh(to->header->tail_entry_monotonic))
-                return -EINVAL;
-
         n = journal_file_entry_n_items(o);
         items = alloca(sizeof(EntryItem) * n);
 

commit e5462cd80e5328a769137c261c93931ea0c27bab
Author: Lennart Poettering <lennart at poettering.net>
Date:   Wed Nov 27 00:58:39 2013 +0100

    journal: fix iteration when we go backwards from the beginning of an array chain element

diff --git a/src/journal/journal-file.c b/src/journal/journal-file.c
index 27cd16f..409be76 100644
--- a/src/journal/journal-file.c
+++ b/src/journal/journal-file.c
@@ -1687,7 +1687,7 @@ found:
                 return 0;
 
         /* Let's cache this item for the next invocation */
-        chain_cache_put(f->chain_cache, ci, first, a, array->entry_array.items[0], t, i + (subtract_one ? -1 : 0));
+        chain_cache_put(f->chain_cache, ci, first, a, array->entry_array.items[0], t, subtract_one ? (i > 0 ? i-1 : (uint64_t) -1) : i);
 
         if (subtract_one && i == 0)
                 p = last_p;

commit f268980d2cee694fa4118a71402a47c316af0425
Author: Lennart Poettering <lennart at poettering.net>
Date:   Tue Nov 26 20:37:53 2013 +0100

    journal: optimize bisection logic a bit by caching the last position
    
    This way we can do a quick restart limiting a bit how wildly we need to
    jump around during the bisection process.

diff --git a/src/journal/journal-file.c b/src/journal/journal-file.c
index 481c242..27cd16f 100644
--- a/src/journal/journal-file.c
+++ b/src/journal/journal-file.c
@@ -1366,6 +1366,7 @@ typedef struct ChainCacheItem {
         uint64_t array; /* the cached array */
         uint64_t begin; /* the first item in the cached array */
         uint64_t total; /* the total number of items in all arrays before this one in the chain */
+        uint64_t last_index; /* the last index we looked at, to optimize locality when bisecting */
 } ChainCacheItem;
 
 static void chain_cache_put(
@@ -1374,7 +1375,8 @@ static void chain_cache_put(
                 uint64_t first,
                 uint64_t array,
                 uint64_t begin,
-                uint64_t total) {
+                uint64_t total,
+                uint64_t last_index) {
 
         if (!ci) {
                 /* If the chain item to cache for this chain is the
@@ -1402,12 +1404,14 @@ static void chain_cache_put(
         ci->array = array;
         ci->begin = begin;
         ci->total = total;
+        ci->last_index = last_index;
 }
 
-static int generic_array_get(JournalFile *f,
-                             uint64_t first,
-                             uint64_t i,
-                             Object **ret, uint64_t *offset) {
+static int generic_array_get(
+                JournalFile *f,
+                uint64_t first,
+                uint64_t i,
+                Object **ret, uint64_t *offset) {
 
         Object *o;
         uint64_t p = 0, a, t = 0;
@@ -1448,7 +1452,7 @@ static int generic_array_get(JournalFile *f,
 
 found:
         /* Let's cache this item for the next invocation */
-        chain_cache_put(f->chain_cache, ci, first, a, o->entry_array.items[0], t);
+        chain_cache_put(f->chain_cache, ci, first, a, o->entry_array.items[0], t, i);
 
         r = journal_file_move_to_object(f, OBJECT_ENTRY, p, &o);
         if (r < 0)
@@ -1463,11 +1467,12 @@ found:
         return 1;
 }
 
-static int generic_array_get_plus_one(JournalFile *f,
-                                      uint64_t extra,
-                                      uint64_t first,
-                                      uint64_t i,
-                                      Object **ret, uint64_t *offset) {
+static int generic_array_get_plus_one(
+                JournalFile *f,
+                uint64_t extra,
+                uint64_t first,
+                uint64_t i,
+                Object **ret, uint64_t *offset) {
 
         Object *o;
 
@@ -1498,17 +1503,18 @@ enum {
         TEST_RIGHT
 };
 
-static int generic_array_bisect(JournalFile *f,
-                                uint64_t first,
-                                uint64_t n,
-                                uint64_t needle,
-                                int (*test_object)(JournalFile *f, uint64_t p, uint64_t needle),
-                                direction_t direction,
-                                Object **ret,
-                                uint64_t *offset,
-                                uint64_t *idx) {
-
-        uint64_t a, p, t = 0, i = 0, last_p = 0;
+static int generic_array_bisect(
+                JournalFile *f,
+                uint64_t first,
+                uint64_t n,
+                uint64_t needle,
+                int (*test_object)(JournalFile *f, uint64_t p, uint64_t needle),
+                direction_t direction,
+                Object **ret,
+                uint64_t *offset,
+                uint64_t *idx) {
+
+        uint64_t a, p, t = 0, i = 0, last_p = 0, last_index = (uint64_t) -1;
         bool subtract_one = false;
         Object *o, *array = NULL;
         int r;
@@ -1533,7 +1539,7 @@ static int generic_array_bisect(JournalFile *f,
                         return r;
 
                 if (r == TEST_LEFT) {
-                        /* OK, what we are looking for is right of th
+                        /* OK, what we are looking for is right of the
                          * begin of this EntryArray, so let's jump
                          * straight to previously cached array in the
                          * chain */
@@ -1541,6 +1547,7 @@ static int generic_array_bisect(JournalFile *f,
                         a = ci->array;
                         n -= ci->total;
                         t = ci->total;
+                        last_index = ci->last_index;
                 }
         }
 
@@ -1571,6 +1578,60 @@ static int generic_array_bisect(JournalFile *f,
                 if (r == TEST_RIGHT) {
                         left = 0;
                         right -= 1;
+
+                        if (last_index != (uint64_t) -1) {
+                                assert(last_index <= right);
+
+                                /* If we cached the last index we
+                                 * looked at, let's try to not to jump
+                                 * too wildly around and see if we can
+                                 * limit the range to look at early to
+                                 * the immediate neighbors of the last
+                                 * index we looked at. */
+
+                                if (last_index > 0) {
+                                        uint64_t x = last_index - 1;
+
+                                        p = le64toh(array->entry_array.items[x]);
+                                        if (p <= 0)
+                                                return -EBADMSG;
+
+                                        r = test_object(f, p, needle);
+                                        if (r < 0)
+                                                return r;
+
+                                        if (r == TEST_FOUND)
+                                                r = direction == DIRECTION_DOWN ? TEST_RIGHT : TEST_LEFT;
+
+                                        if (r == TEST_RIGHT)
+                                                right = x;
+                                        else
+                                                left = x + 1;
+                                }
+
+                                if (last_index < right) {
+                                        uint64_t y = last_index + 1;
+
+                                        p = le64toh(array->entry_array.items[y]);
+                                        if (p <= 0)
+                                                return -EBADMSG;
+
+                                        r = test_object(f, p, needle);
+                                        if (r < 0)
+                                                return r;
+
+                                        if (r == TEST_FOUND)
+                                                r = direction == DIRECTION_DOWN ? TEST_RIGHT : TEST_LEFT;
+
+                                        if (r == TEST_RIGHT)
+                                                right = y;
+                                        else
+                                                left = y + 1;
+                                }
+
+                                last_index = (uint64_t) -1;
+                        }
+
                         for (;;) {
                                 if (left == right) {
                                         if (direction == DIRECTION_UP)
@@ -1581,8 +1642,8 @@ static int generic_array_bisect(JournalFile *f,
                                 }
 
                                 assert(left < right);
-
                                 i = (left + right) / 2;
+
                                 p = le64toh(array->entry_array.items[i]);
                                 if (p <= 0)
                                         return -EBADMSG;
@@ -1615,6 +1676,7 @@ static int generic_array_bisect(JournalFile *f,
 
                 n -= k;
                 t += k;
+                last_index = (uint64_t) -1;
                 a = le64toh(array->entry_array.next_entry_array_offset);
         }
 
@@ -1625,7 +1687,7 @@ found:
                 return 0;
 
         /* Let's cache this item for the next invocation */
-        chain_cache_put(f->chain_cache, ci, first, a, array->entry_array.items[0], t);
+        chain_cache_put(f->chain_cache, ci, first, a, array->entry_array.items[0], t, i + (subtract_one ? -1 : 0));
 
         if (subtract_one && i == 0)
                 p = last_p;
@@ -1650,16 +1712,18 @@ found:
         return 1;
 }
 
-static int generic_array_bisect_plus_one(JournalFile *f,
-                                         uint64_t extra,
-                                         uint64_t first,
-                                         uint64_t n,
-                                         uint64_t needle,
-                                         int (*test_object)(JournalFile *f, uint64_t p, uint64_t needle),
-                                         direction_t direction,
-                                         Object **ret,
-                                         uint64_t *offset,
-                                         uint64_t *idx) {
+
+static int generic_array_bisect_plus_one(
+                JournalFile *f,
+                uint64_t extra,
+                uint64_t first,
+                uint64_t n,
+                uint64_t needle,
+                int (*test_object)(JournalFile *f, uint64_t p, uint64_t needle),
+                direction_t direction,
+                Object **ret,
+                uint64_t *offset,
+                uint64_t *idx) {
 
         int r;
         bool step_back = false;



More information about the systemd-commits mailing list