]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
journald: periodically drop cache for all dead PIDs
authorZbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>
Tue, 22 Jan 2019 16:30:48 +0000 (17:30 +0100)
committerLukáš Nykrýn <lnykryn@redhat.com>
Thu, 7 Feb 2019 11:57:43 +0000 (12:57 +0100)
In normal use, this allow us to drop dead entries from the cache and reduces
the cache size so that we don't evict entries unnecessarily. The time limit is
there mostly to serve as a guard against malicious logging from many different
PIDs.

(cherry-picked from commit 91714a7f427a6c9c5c3be8b3819fee45050028f3)

Related: #1664976

src/journal/journald-context.c
src/journal/journald-server.h

index 0f0dc1de4dc011ceb8e5ef8a89ae5f5ef1be7046..51f79fd803fe6a2d7b29ef5896d0a0307e01d19b 100644 (file)
@@ -541,15 +541,39 @@ refresh:
 }
 
 static void client_context_try_shrink_to(Server *s, size_t limit) {
+        ClientContext *c;
+        usec_t t;
+
         assert(s);
 
+        /* Flush any cache entries for PIDs that have already moved on. Don't do this
+         * too often, since it's a slow process. */
+        t = now(CLOCK_MONOTONIC);
+        if (s->last_cache_pid_flush + MAX_USEC < t) {
+                unsigned n = prioq_size(s->client_contexts_lru), idx = 0;
+
+                /* We do a number of iterations based on the initial size of the prioq.  When we remove an
+                 * item, a new item is moved into its places, and items to the right might be reshuffled.
+                 */
+                for (unsigned i = 0; i < n; i++) {
+                        c = prioq_peek_by_index(s->client_contexts_lru, idx);
+
+                        assert(c->n_ref == 0);
+
+                        if (!pid_is_unwaited(c->pid))
+                                client_context_free(s, c);
+                        else
+                                idx ++;
+                }
+
+                s->last_cache_pid_flush = t;
+        }
+
         /* Bring the number of cache entries below the indicated limit, so that we can create a new entry without
          * breaching the limit. Note that we only flush out entries that aren't pinned here. This means the number of
          * cache entries may very well grow beyond the limit, if all entries stored remain pinned. */
 
         while (hashmap_size(s->client_contexts) > limit) {
-                ClientContext *c;
-
                 c = prioq_pop(s->client_contexts_lru);
                 if (!c)
                         break; /* All remaining entries are pinned, give up */
index 983be8bb89fa4f13b6c26f3612f0eb701518eac1..c6c9b1fb1d9784e61d4872ca5e093d3f9444ebb1 100644 (file)
@@ -163,6 +163,8 @@ struct Server {
         Hashmap *client_contexts;
         Prioq *client_contexts_lru;
 
+        usec_t last_cache_pid_flush;
+
         ClientContext *my_context; /* the context of journald itself */
         ClientContext *pid1_context; /* the context of PID 1 */
 };