From babfc09177c1e71cec6c1ef9602e265ed40cfe4f Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 31 Dec 2011 02:31:54 +0100 Subject: journal: automatically deduce journal metrics from file system sizes --- src/journal/journal-file.c | 100 ++++++++++++++++++++++++++++++++++++++++++--- src/journal/journal-file.h | 9 ++-- src/journal/journald.c | 81 ++++++++++++++++++++++-------------- src/util.c | 34 +++++++++++++++ src/util.h | 2 + 5 files changed, 184 insertions(+), 42 deletions(-) diff --git a/src/journal/journal-file.c b/src/journal/journal-file.c index 190bfb996b..fd2e9ebbbc 100644 --- a/src/journal/journal-file.c +++ b/src/journal/journal-file.c @@ -39,6 +39,25 @@ #define COMPRESSION_SIZE_THRESHOLD (64ULL) +/* This is the minimum journal file size */ +#define JOURNAL_FILE_SIZE_MIN (64ULL*1024ULL) + +/* These are the lower and upper bounds if we deduce the max_use value + * from the file system size */ +#define DEFAULT_MAX_USE_LOWER (1ULL*1024ULL*1024ULL) /* 1 MiB */ +#define DEFAULT_MAX_USE_UPPER (4ULL*1024ULL*1024ULL*1024ULL) /* 4 GiB */ + +/* This is the upper bound if we deduce max_size from max_use */ +#define DEFAULT_MAX_SIZE_UPPER (16ULL*1024ULL*1024ULL) /* 16 MiB */ + +/* This is the upper bound if we deduce the keep_free value from the + * file system size */ +#define DEFAULT_KEEP_FREE_UPPER (4ULL*1024ULL*1024ULL*1024ULL) /* 4 GiB */ + +/* This is the keep_free value when we can't determine the system + * size */ +#define DEFAULT_KEEP_FREE (1024ULL*1024ULL) /* 1 MB */ + static const char signature[] = { 'L', 'P', 'K', 'S', 'H', 'H', 'R', 'H' }; #define ALIGN64(x) (((x) + 7ULL) & ~7ULL) @@ -1701,10 +1720,6 @@ int journal_file_open( f->writable = (flags & O_ACCMODE) != O_RDONLY; f->prot = prot_from_flags(flags); - f->metrics.max_size = DEFAULT_MAX_SIZE; - f->metrics.min_size = DEFAULT_MIN_SIZE; - f->metrics.keep_free = DEFAULT_KEEP_FREE; - f->path = strdup(fname); if (!f->path) { r = -ENOMEM; @@ -1877,7 +1892,7 @@ int journal_directory_vacuum(const char *directory, uint64_t max_use, uint64_t m assert(directory); if (max_use <= 0) - max_use = DEFAULT_MAX_USE; + return 0; d = opendir(directory); if (!d) @@ -2076,3 +2091,78 @@ int journal_file_copy_entry(JournalFile *from, JournalFile *to, Object *o, uint6 return journal_file_append_entry_internal(to, &ts, xor_hash, items, n, seqnum, ret, offset); } + +void journal_default_metrics(JournalMetrics *m, int fd) { + uint64_t fs_size = 0; + struct statvfs ss; + char a[64], b[64], c[64], d[64]; + + assert(m); + assert(fd >= 0); + + if (fstatvfs(fd, &ss) >= 0) + fs_size = ss.f_frsize * ss.f_blocks; + + if (m->max_use == (uint64_t) -1) { + + if (fs_size > 0) { + m->max_use = PAGE_ALIGN(fs_size / 10); /* 10% of file system size */ + + if (m->max_use > DEFAULT_MAX_USE_UPPER) + m->max_use = DEFAULT_MAX_USE_UPPER; + + if (m->max_use < DEFAULT_MAX_USE_LOWER) + m->max_use = DEFAULT_MAX_USE_LOWER; + } else + m->max_use = DEFAULT_MAX_USE_LOWER; + } else { + m->max_use = PAGE_ALIGN(m->max_use); + + if (m->max_use < JOURNAL_FILE_SIZE_MIN*2) + m->max_use = JOURNAL_FILE_SIZE_MIN*2; + } + + if (m->max_size == (uint64_t) -1) { + m->max_size = PAGE_ALIGN(m->max_use / 8); /* 8 chunks */ + + if (m->max_size > DEFAULT_MAX_SIZE_UPPER) + m->max_size = DEFAULT_MAX_SIZE_UPPER; + } else + m->max_size = PAGE_ALIGN(m->max_size); + + if (m->max_size < JOURNAL_FILE_SIZE_MIN) + m->max_size = JOURNAL_FILE_SIZE_MIN; + + if (m->max_size*2 > m->max_use) + m->max_use = m->max_size*2; + + if (m->min_size == (uint64_t) -1) + m->min_size = JOURNAL_FILE_SIZE_MIN; + else { + m->min_size = PAGE_ALIGN(m->min_size); + + if (m->min_size < JOURNAL_FILE_SIZE_MIN) + m->min_size = JOURNAL_FILE_SIZE_MIN; + + if (m->min_size > m->max_size) + m->max_size = m->min_size; + } + + if (m->keep_free == (uint64_t) -1) { + + if (fs_size > 0) { + m->keep_free = PAGE_ALIGN(fs_size / 20); /* 5% of file system size */ + + if (m->keep_free > DEFAULT_KEEP_FREE_UPPER) + m->keep_free = DEFAULT_KEEP_FREE_UPPER; + + } else + m->keep_free = DEFAULT_KEEP_FREE; + } + + log_debug("Fixed max_use=%s max_size=%s min_size=%s keep_free=%s", + format_bytes(a, sizeof(a), m->max_use), + format_bytes(b, sizeof(b), m->max_size), + format_bytes(c, sizeof(c), m->min_size), + format_bytes(d, sizeof(d), m->keep_free)); +} diff --git a/src/journal/journal-file.h b/src/journal/journal-file.h index acc55272a0..51d7119d09 100644 --- a/src/journal/journal-file.h +++ b/src/journal/journal-file.h @@ -28,11 +28,6 @@ #include "util.h" #include "sd-id128.h" -#define DEFAULT_MAX_SIZE (128ULL*1024ULL*1024ULL) -#define DEFAULT_MIN_SIZE (256ULL*1024ULL) -#define DEFAULT_KEEP_FREE (1ULL*1024ULL*1024ULL) -#define DEFAULT_MAX_USE (16ULL*1024ULL*1024ULL*16ULL) - typedef struct Window { void *ptr; uint64_t offset; @@ -51,10 +46,10 @@ enum { }; typedef struct JournalMetrics { + uint64_t max_use; uint64_t max_size; uint64_t min_size; uint64_t keep_free; - uint64_t max_use; } JournalMetrics; typedef struct JournalFile { @@ -124,4 +119,6 @@ int journal_directory_vacuum(const char *directory, uint64_t max_use, uint64_t m void journal_file_post_change(JournalFile *f); +void journal_default_metrics(JournalMetrics *m, int fd); + #endif diff --git a/src/journal/journald.c b/src/journal/journald.c index 78ccb4e05a..f637d9471d 100644 --- a/src/journal/journald.c +++ b/src/journal/journald.c @@ -75,7 +75,9 @@ typedef struct Server { JournalRateLimit *rate_limit; - JournalMetrics metrics; + JournalMetrics runtime_metrics; + JournalMetrics system_metrics; + bool compress; uint64_t cached_available_space; @@ -117,15 +119,17 @@ struct StdoutStream { static int server_flush_to_var(Server *s); static uint64_t available_space(Server *s) { - char ids[33]; - sd_id128_t machine; - char *p; + char ids[33], *p; const char *f; + sd_id128_t machine; struct statvfs ss; uint64_t sum = 0, avail = 0, ss_avail = 0; int r; DIR *d; - usec_t ts = now(CLOCK_MONOTONIC); + usec_t ts; + JournalMetrics *m; + + ts = now(CLOCK_MONOTONIC); if (s->cached_available_space_timestamp + RECHECK_AVAILABLE_SPACE_USEC > ts) return s->cached_available_space; @@ -134,10 +138,15 @@ static uint64_t available_space(Server *s) { if (r < 0) return 0; - if (s->system_journal) + if (s->system_journal) { f = "/var/log/journal/"; - else + m = &s->system_metrics; + } else { f = "/run/log/journal/"; + m = &s->runtime_metrics; + } + + assert(m); p = strappend(f, sd_id128_to_string(machine, ids)); if (!p) @@ -175,11 +184,11 @@ static uint64_t available_space(Server *s) { sum += (uint64_t) st.st_blocks * (uint64_t) st.st_blksize; } - avail = sum >= s->metrics.max_use ? 0 : s->metrics.max_use - sum; + avail = sum >= m->max_use ? 0 : m->max_use - sum; ss_avail = ss.f_bsize * ss.f_bavail; - ss_avail = ss_avail < s->metrics.keep_free ? 0 : ss_avail - s->metrics.keep_free; + ss_avail = ss_avail < m->keep_free ? 0 : ss_avail - m->keep_free; if (ss_avail < avail) avail = ss_avail; @@ -284,7 +293,7 @@ static JournalFile* find_journal(Server *s, uid_t uid) { return s->system_journal; fix_perms(f, uid); - f->metrics = s->metrics; + f->metrics = s->system_metrics; f->compress = s->compress; r = hashmap_put(s->user_journals, UINT32_TO_PTR(uid), f); @@ -335,25 +344,32 @@ static void server_vacuum(Server *s) { return; } - if (asprintf(&p, "/var/log/journal/%s", sd_id128_to_string(machine, ids)) < 0) { - log_error("Out of memory."); - return; - } + sd_id128_to_string(machine, ids); - r = journal_directory_vacuum(p, s->metrics.max_use, s->metrics.keep_free); - if (r < 0 && r != -ENOENT) - log_error("Failed to vacuum %s: %s", p, strerror(-r)); - free(p); + if (s->system_journal) { + if (asprintf(&p, "/var/log/journal/%s", ids) < 0) { + log_error("Out of memory."); + return; + } - if (asprintf(&p, "/run/log/journal/%s", ids) < 0) { - log_error("Out of memory."); - return; + r = journal_directory_vacuum(p, s->system_metrics.max_use, s->system_metrics.keep_free); + if (r < 0 && r != -ENOENT) + log_error("Failed to vacuum %s: %s", p, strerror(-r)); + free(p); } - r = journal_directory_vacuum(p, s->metrics.max_use, s->metrics.keep_free); - if (r < 0 && r != -ENOENT) - log_error("Failed to vacuum %s: %s", p, strerror(-r)); - free(p); + + if (s->runtime_journal) { + if (asprintf(&p, "/run/log/journal/%s", ids) < 0) { + log_error("Out of memory."); + return; + } + + r = journal_directory_vacuum(p, s->runtime_metrics.max_use, s->runtime_metrics.keep_free); + if (r < 0 && r != -ENOENT) + log_error("Failed to vacuum %s: %s", p, strerror(-r)); + free(p); + } s->cached_available_space_timestamp = 0; } @@ -1144,7 +1160,9 @@ static int system_journal_open(Server *s) { free(fn); if (r >= 0) { - s->system_journal->metrics = s->metrics; + journal_default_metrics(&s->system_metrics, s->system_journal->fd); + + s->system_journal->metrics = s->system_metrics; s->system_journal->compress = s->compress; fix_perms(s->system_journal, 0); @@ -1200,7 +1218,9 @@ static int system_journal_open(Server *s) { } if (s->runtime_journal) { - s->runtime_journal->metrics = s->metrics; + journal_default_metrics(&s->runtime_metrics, s->runtime_journal->fd); + + s->runtime_journal->metrics = s->runtime_metrics; s->runtime_journal->compress = s->compress; fix_perms(s->runtime_journal, 0); @@ -1717,12 +1737,11 @@ static int server_init(Server *s) { zero(*s); s->syslog_fd = s->native_fd = s->stdout_fd = s->signal_fd = s->epoll_fd = -1; - s->metrics.max_size = DEFAULT_MAX_SIZE; - s->metrics.min_size = DEFAULT_MIN_SIZE; - s->metrics.keep_free = DEFAULT_KEEP_FREE; - s->metrics.max_use = DEFAULT_MAX_USE; s->compress = true; + memset(&s->system_metrics, 0xFF, sizeof(s->system_metrics)); + memset(&s->runtime_metrics, 0xFF, sizeof(s->runtime_metrics)); + s->user_journals = hashmap_new(trivial_hash_func, trivial_compare_func); if (!s->user_journals) { log_error("Out of memory."); diff --git a/src/util.c b/src/util.c index 7191750c52..0d1d16d9ac 100644 --- a/src/util.c +++ b/src/util.c @@ -5940,3 +5940,37 @@ unsigned long cap_last_cap(void) { return p; } + +char *format_bytes(char *buf, size_t l, off_t t) { + int i; + + static const struct { + const char *suffix; + off_t factor; + } table[] = { + { "T", 1024ULL*1024ULL*1024ULL*1024ULL }, + { "G", 1024ULL*1024ULL*1024ULL }, + { "M", 1024ULL*1024ULL }, + { "K", 1024ULL }, + }; + + for (i = 0; i < ELEMENTSOF(table); i++) { + + if (t >= table[i].factor) { + snprintf(buf, l, + "%llu.%llu%s", + (unsigned long long) (t / table[i].factor), + (unsigned long long) (((t*10ULL) / table[i].factor) % 10ULL), + table[i].suffix); + + goto finish; + } + } + + snprintf(buf, l, "%lluB", (unsigned long long) t); + +finish: + buf[l-1] = 0; + return buf; + +} diff --git a/src/util.h b/src/util.h index ac2ec8c351..7f25788b3f 100644 --- a/src/util.h +++ b/src/util.h @@ -518,4 +518,6 @@ int prot_from_flags(int flags); unsigned long cap_last_cap(void); +char *format_bytes(char *buf, size_t l, off_t t); + #endif -- cgit v1.2.3-54-g00ecf