journal: implement time-based rotation/vacuuming
This also enables time-based rotation (but not vacuuming) after 1month, so that not more one month of journal is lost at a time per vacuuming.
This commit is contained in:
parent
1f2da9ec51
commit
fb0951b02e
1
README
1
README
|
@ -47,6 +47,7 @@ REQUIREMENTS:
|
||||||
libgcrypt (optional)
|
libgcrypt (optional)
|
||||||
libaudit (optional)
|
libaudit (optional)
|
||||||
libacl (optional)
|
libacl (optional)
|
||||||
|
libattr (optional)
|
||||||
libselinux (optional)
|
libselinux (optional)
|
||||||
liblzma (optional)
|
liblzma (optional)
|
||||||
tcpwrappers (optional)
|
tcpwrappers (optional)
|
||||||
|
|
41
configure.ac
41
configure.ac
|
@ -1,4 +1,4 @@
|
||||||
|
#
|
||||||
# This file is part of systemd.
|
# This file is part of systemd.
|
||||||
#
|
#
|
||||||
# Copyright 2010-2012 Lennart Poettering
|
# Copyright 2010-2012 Lennart Poettering
|
||||||
|
@ -340,6 +340,44 @@ fi
|
||||||
AC_SUBST(ACL_LIBS)
|
AC_SUBST(ACL_LIBS)
|
||||||
AM_CONDITIONAL([HAVE_ACL], [test "x$have_acl" != xno])
|
AM_CONDITIONAL([HAVE_ACL], [test "x$have_acl" != xno])
|
||||||
|
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
AC_ARG_ENABLE([xattr],
|
||||||
|
AS_HELP_STRING([--disable-xattr],[Disable optional XATTR support]),
|
||||||
|
[case "${enableval}" in
|
||||||
|
yes) have_xattr=yes ;;
|
||||||
|
no) have_xattr=no ;;
|
||||||
|
*) AC_MSG_ERROR(bad value ${enableval} for --disable-xattr) ;;
|
||||||
|
esac],
|
||||||
|
[have_xattr=auto])
|
||||||
|
|
||||||
|
if test "x${have_xattr}" != xno ; then
|
||||||
|
AC_CHECK_HEADERS(
|
||||||
|
[attr/xattr.h],
|
||||||
|
[have_xattr=yes],
|
||||||
|
[if test "x$have_xattr" = xyes ; then
|
||||||
|
AC_MSG_ERROR([*** XATTR headers not found.])
|
||||||
|
fi])
|
||||||
|
|
||||||
|
AC_CHECK_LIB(
|
||||||
|
[attr],
|
||||||
|
[fsetxattr],
|
||||||
|
[have_xattr=yes],
|
||||||
|
[if test "x$have_xattr" = xyes ; then
|
||||||
|
AC_MSG_ERROR([*** libattr not found.])
|
||||||
|
fi])
|
||||||
|
|
||||||
|
if test "x$have_xattr" = xyes ; then
|
||||||
|
XATTR_LIBS="-lattr"
|
||||||
|
AC_DEFINE(HAVE_XATTR, 1, [XATTR available])
|
||||||
|
else
|
||||||
|
have_xattr=no
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
XATTR_LIBS=
|
||||||
|
fi
|
||||||
|
AC_SUBST(XATTR_LIBS)
|
||||||
|
AM_CONDITIONAL([HAVE_XATTR], [test "x$have_xattr" != xno])
|
||||||
|
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
AC_ARG_ENABLE([gcrypt],
|
AC_ARG_ENABLE([gcrypt],
|
||||||
AS_HELP_STRING([--disable-gcrypt],[Disable optional GCRYPT support]),
|
AS_HELP_STRING([--disable-gcrypt],[Disable optional GCRYPT support]),
|
||||||
|
@ -823,6 +861,7 @@ AC_MSG_RESULT([
|
||||||
SELinux: ${have_selinux}
|
SELinux: ${have_selinux}
|
||||||
XZ: ${have_xz}
|
XZ: ${have_xz}
|
||||||
ACL: ${have_acl}
|
ACL: ${have_acl}
|
||||||
|
XATTR: ${have_xattr}
|
||||||
GCRYPT: ${have_gcrypt}
|
GCRYPT: ${have_gcrypt}
|
||||||
QRENCODE: ${have_qrencode}
|
QRENCODE: ${have_qrencode}
|
||||||
MICROHTTPD: ${have_microhttpd}
|
MICROHTTPD: ${have_microhttpd}
|
||||||
|
|
|
@ -278,6 +278,57 @@
|
||||||
time.</para></listitem>
|
time.</para></listitem>
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
|
||||||
|
<varlistentry>
|
||||||
|
<term><varname>MaxFileSec=</varname></term>
|
||||||
|
|
||||||
|
<listitem><para>The maximum time to
|
||||||
|
store entries in a single journal
|
||||||
|
file, before rotating to the next
|
||||||
|
one. Normally time-based rotation
|
||||||
|
should not be required as size-based
|
||||||
|
rotation with options such as
|
||||||
|
<varname>SystemMaxFileSize=</varname>
|
||||||
|
should be sufficient to ensure that
|
||||||
|
journal files don't grow without
|
||||||
|
bounds. However, to ensure that not
|
||||||
|
too much data is lost at once when old
|
||||||
|
journal files are deleted it might
|
||||||
|
make sense to change this value from
|
||||||
|
the default of one month. Set to 0 to
|
||||||
|
turn off this feature. This setting
|
||||||
|
takes time values which may be
|
||||||
|
suffixed with the units year, month,
|
||||||
|
week, day, h, m to override the
|
||||||
|
default time unit of
|
||||||
|
seconds.</para></listitem>
|
||||||
|
</varlistentry>
|
||||||
|
|
||||||
|
<varlistentry>
|
||||||
|
<term><varname>MaxRetentionSec=</varname></term>
|
||||||
|
|
||||||
|
<listitem><para>The maximum time to
|
||||||
|
store journal entries for. This
|
||||||
|
controls whether journal files
|
||||||
|
containing entries older then the
|
||||||
|
specified time span are
|
||||||
|
deleted. Normally time-based deletion
|
||||||
|
of old journal files should not be
|
||||||
|
required as size-based deletion with
|
||||||
|
options such as
|
||||||
|
<varname>SystemMaxUse=</varname>
|
||||||
|
should be sufficient to ensure that
|
||||||
|
journal files don't grow without
|
||||||
|
bounds. However, to enforce data
|
||||||
|
retention policies it might make sense
|
||||||
|
to set change this value from the
|
||||||
|
default of 0 (which turns off this
|
||||||
|
feature). This settings also takes
|
||||||
|
time values which may be suffixed with
|
||||||
|
the units year, month, week, day, h, m
|
||||||
|
to override the default time unit of
|
||||||
|
seconds. </para></listitem>
|
||||||
|
</varlistentry>
|
||||||
|
|
||||||
<varlistentry>
|
<varlistentry>
|
||||||
<term><varname>ForwardToSyslog=</varname></term>
|
<term><varname>ForwardToSyslog=</varname></term>
|
||||||
<term><varname>ForwardToKMsg=</varname></term>
|
<term><varname>ForwardToKMsg=</varname></term>
|
||||||
|
|
|
@ -27,6 +27,10 @@
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
|
|
||||||
|
#ifdef HAVE_XATTR
|
||||||
|
#include <attr/xattr.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#include "journal-def.h"
|
#include "journal-def.h"
|
||||||
#include "journal-file.h"
|
#include "journal-file.h"
|
||||||
#include "journal-authenticate.h"
|
#include "journal-authenticate.h"
|
||||||
|
@ -1978,7 +1982,7 @@ void journal_file_print_header(JournalFile *f) {
|
||||||
(unsigned long long) le64toh(f->header->arena_size),
|
(unsigned long long) le64toh(f->header->arena_size),
|
||||||
(unsigned long long) le64toh(f->header->data_hash_table_size) / sizeof(HashItem),
|
(unsigned long long) le64toh(f->header->data_hash_table_size) / sizeof(HashItem),
|
||||||
(unsigned long long) le64toh(f->header->field_hash_table_size) / sizeof(HashItem),
|
(unsigned long long) le64toh(f->header->field_hash_table_size) / sizeof(HashItem),
|
||||||
yes_no(journal_file_rotate_suggested(f)),
|
yes_no(journal_file_rotate_suggested(f, 0)),
|
||||||
(unsigned long long) le64toh(f->header->head_entry_seqnum),
|
(unsigned long long) le64toh(f->header->head_entry_seqnum),
|
||||||
(unsigned long long) le64toh(f->header->tail_entry_seqnum),
|
(unsigned long long) le64toh(f->header->tail_entry_seqnum),
|
||||||
format_timestamp(x, sizeof(x), le64toh(f->header->head_entry_realtime)),
|
format_timestamp(x, sizeof(x), le64toh(f->header->head_entry_realtime)),
|
||||||
|
@ -2080,7 +2084,22 @@ int journal_file_open(
|
||||||
}
|
}
|
||||||
|
|
||||||
if (f->last_stat.st_size == 0 && f->writable) {
|
if (f->last_stat.st_size == 0 && f->writable) {
|
||||||
newly_created = true;
|
#ifdef HAVE_XATTR
|
||||||
|
uint64_t crtime;
|
||||||
|
|
||||||
|
/* Let's attach the creation time to the journal file,
|
||||||
|
* so that the vacuuming code knows the age of this
|
||||||
|
* file even if the file might end up corrupted one
|
||||||
|
* day... Ideally we'd just use the creation time many
|
||||||
|
* file systems maintain for each file, but there is
|
||||||
|
* currently no usable API to query this, hence let's
|
||||||
|
* emulate this via extended attributes. If extended
|
||||||
|
* attributes are not supported we'll just skip this,
|
||||||
|
* and rely solely on mtime/atime/ctime of the file.*/
|
||||||
|
|
||||||
|
crtime = htole64((uint64_t) now(CLOCK_REALTIME));
|
||||||
|
fsetxattr(f->fd, "user.crtime_usec", &crtime, sizeof(crtime), XATTR_CREATE);
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef HAVE_GCRYPT
|
#ifdef HAVE_GCRYPT
|
||||||
/* Try to load the FSPRG state, and if we can't, then
|
/* Try to load the FSPRG state, and if we can't, then
|
||||||
|
@ -2100,6 +2119,8 @@ int journal_file_open(
|
||||||
r = -errno;
|
r = -errno;
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
newly_created = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (f->last_stat.st_size < (off_t) HEADER_SIZE_MIN) {
|
if (f->last_stat.st_size < (off_t) HEADER_SIZE_MIN) {
|
||||||
|
@ -2207,8 +2228,8 @@ int journal_file_rotate(JournalFile **f, bool compress, bool seal) {
|
||||||
sd_id128_to_string(old_file->header->seqnum_id, p + l - 8 + 1);
|
sd_id128_to_string(old_file->header->seqnum_id, p + l - 8 + 1);
|
||||||
snprintf(p + l - 8 + 1 + 32, 1 + 16 + 1 + 16 + 8 + 1,
|
snprintf(p + l - 8 + 1 + 32, 1 + 16 + 1 + 16 + 8 + 1,
|
||||||
"-%016llx-%016llx.journal",
|
"-%016llx-%016llx.journal",
|
||||||
(unsigned long long) le64toh((*f)->header->tail_entry_seqnum),
|
(unsigned long long) le64toh((*f)->header->head_entry_seqnum),
|
||||||
(unsigned long long) le64toh((*f)->header->tail_entry_realtime));
|
(unsigned long long) le64toh((*f)->header->head_entry_realtime));
|
||||||
|
|
||||||
r = rename(old_file->path, p);
|
r = rename(old_file->path, p);
|
||||||
free(p);
|
free(p);
|
||||||
|
@ -2501,7 +2522,7 @@ int journal_file_get_cutoff_monotonic_usec(JournalFile *f, sd_id128_t boot_id, u
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool journal_file_rotate_suggested(JournalFile *f) {
|
bool journal_file_rotate_suggested(JournalFile *f, usec_t max_file_usec) {
|
||||||
assert(f);
|
assert(f);
|
||||||
|
|
||||||
/* If we gained new header fields we gained new features,
|
/* If we gained new header fields we gained new features,
|
||||||
|
@ -2539,5 +2560,15 @@ bool journal_file_rotate_suggested(JournalFile *f) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (max_file_usec > 0) {
|
||||||
|
usec_t t, h;
|
||||||
|
|
||||||
|
h = le64toh(f->header->head_entry_realtime);
|
||||||
|
t = now(CLOCK_REALTIME);
|
||||||
|
|
||||||
|
if (h > 0 && t > h + max_file_usec)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -184,4 +184,4 @@ void journal_default_metrics(JournalMetrics *m, int fd);
|
||||||
int journal_file_get_cutoff_realtime_usec(JournalFile *f, usec_t *from, usec_t *to);
|
int journal_file_get_cutoff_realtime_usec(JournalFile *f, usec_t *from, usec_t *to);
|
||||||
int journal_file_get_cutoff_monotonic_usec(JournalFile *f, sd_id128_t boot, usec_t *from, usec_t *to);
|
int journal_file_get_cutoff_monotonic_usec(JournalFile *f, sd_id128_t boot, usec_t *from, usec_t *to);
|
||||||
|
|
||||||
bool journal_file_rotate_suggested(JournalFile *f);
|
bool journal_file_rotate_suggested(JournalFile *f, usec_t max_file_usec);
|
||||||
|
|
|
@ -25,6 +25,10 @@
|
||||||
#include <sys/statvfs.h>
|
#include <sys/statvfs.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#ifdef HAVE_XATTR
|
||||||
|
#include <attr/xattr.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#include "journal-def.h"
|
#include "journal-def.h"
|
||||||
#include "journal-file.h"
|
#include "journal-file.h"
|
||||||
#include "journal-vacuum.h"
|
#include "journal-vacuum.h"
|
||||||
|
@ -68,18 +72,89 @@ static int vacuum_compare(const void *_a, const void *_b) {
|
||||||
return strcmp(a->filename, b->filename);
|
return strcmp(a->filename, b->filename);
|
||||||
}
|
}
|
||||||
|
|
||||||
int journal_directory_vacuum(const char *directory, uint64_t max_use, uint64_t min_free) {
|
static void patch_realtime(
|
||||||
|
const char *dir,
|
||||||
|
const char *fn,
|
||||||
|
const struct stat *st,
|
||||||
|
unsigned long long *realtime) {
|
||||||
|
|
||||||
|
usec_t x;
|
||||||
|
|
||||||
|
#ifdef HAVE_XATTR
|
||||||
|
uint64_t crtime;
|
||||||
|
_cleanup_free_ const char *path = NULL;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* The timestamp was determined by the file name, but let's
|
||||||
|
* see if the file might actually be older than the file name
|
||||||
|
* suggested... */
|
||||||
|
|
||||||
|
assert(dir);
|
||||||
|
assert(fn);
|
||||||
|
assert(st);
|
||||||
|
assert(realtime);
|
||||||
|
|
||||||
|
x = timespec_load(&st->st_ctim);
|
||||||
|
if (x > 0 && x != (usec_t) -1 && x < *realtime)
|
||||||
|
*realtime = x;
|
||||||
|
|
||||||
|
x = timespec_load(&st->st_atim);
|
||||||
|
if (x > 0 && x != (usec_t) -1 && x < *realtime)
|
||||||
|
*realtime = x;
|
||||||
|
|
||||||
|
x = timespec_load(&st->st_mtim);
|
||||||
|
if (x > 0 && x != (usec_t) -1 && x < *realtime)
|
||||||
|
*realtime = x;
|
||||||
|
|
||||||
|
#ifdef HAVE_XATTR
|
||||||
|
/* Let's read the original creation time, if possible. Ideally
|
||||||
|
* we'd just query the creation time the FS might provide, but
|
||||||
|
* unfortunately there's currently no sane API to query
|
||||||
|
* it. Hence let's implement this manually... */
|
||||||
|
|
||||||
|
/* Unfortunately there is is not fgetxattrat(), so we need to
|
||||||
|
* go via path here. :-( */
|
||||||
|
|
||||||
|
path = strjoin(dir, "/", fn, NULL);
|
||||||
|
if (!path)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (getxattr(path, "user.crtime_usec", &crtime, sizeof(crtime)) == sizeof(crtime)) {
|
||||||
|
crtime = le64toh(crtime);
|
||||||
|
|
||||||
|
if (crtime > 0 && crtime != (uint64_t) -1 && crtime < *realtime)
|
||||||
|
*realtime = crtime;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
int journal_directory_vacuum(
|
||||||
|
const char *directory,
|
||||||
|
uint64_t max_use,
|
||||||
|
uint64_t min_free,
|
||||||
|
usec_t max_retention_usec,
|
||||||
|
usec_t *oldest_usec) {
|
||||||
|
|
||||||
DIR *d;
|
DIR *d;
|
||||||
int r = 0;
|
int r = 0;
|
||||||
struct vacuum_info *list = NULL;
|
struct vacuum_info *list = NULL;
|
||||||
unsigned n_list = 0, n_allocated = 0, i;
|
unsigned n_list = 0, n_allocated = 0, i;
|
||||||
uint64_t sum = 0;
|
uint64_t sum = 0;
|
||||||
|
usec_t retention_limit = 0;
|
||||||
|
|
||||||
assert(directory);
|
assert(directory);
|
||||||
|
|
||||||
if (max_use <= 0)
|
if (max_use <= 0 && min_free <= 0 && max_retention_usec <= 0)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
if (max_retention_usec > 0) {
|
||||||
|
retention_limit = now(CLOCK_REALTIME);
|
||||||
|
if (retention_limit > max_retention_usec)
|
||||||
|
retention_limit -= max_retention_usec;
|
||||||
|
else
|
||||||
|
max_retention_usec = retention_limit = 0;
|
||||||
|
}
|
||||||
|
|
||||||
d = opendir(directory);
|
d = opendir(directory);
|
||||||
if (!d)
|
if (!d)
|
||||||
return -errno;
|
return -errno;
|
||||||
|
@ -170,6 +245,8 @@ int journal_directory_vacuum(const char *directory, uint64_t max_use, uint64_t m
|
||||||
} else
|
} else
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
patch_realtime(directory, de->d_name, &st, &realtime);
|
||||||
|
|
||||||
if (n_list >= n_allocated) {
|
if (n_list >= n_allocated) {
|
||||||
struct vacuum_info *j;
|
struct vacuum_info *j;
|
||||||
|
|
||||||
|
@ -199,7 +276,7 @@ int journal_directory_vacuum(const char *directory, uint64_t max_use, uint64_t m
|
||||||
if (n_list > 0)
|
if (n_list > 0)
|
||||||
qsort(list, n_list, sizeof(struct vacuum_info), vacuum_compare);
|
qsort(list, n_list, sizeof(struct vacuum_info), vacuum_compare);
|
||||||
|
|
||||||
for(i = 0; i < n_list; i++) {
|
for (i = 0; i < n_list; i++) {
|
||||||
struct statvfs ss;
|
struct statvfs ss;
|
||||||
|
|
||||||
if (fstatvfs(dirfd(d), &ss) < 0) {
|
if (fstatvfs(dirfd(d), &ss) < 0) {
|
||||||
|
@ -207,8 +284,9 @@ int journal_directory_vacuum(const char *directory, uint64_t max_use, uint64_t m
|
||||||
goto finish;
|
goto finish;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sum <= max_use &&
|
if ((max_retention_usec <= 0 || list[i].realtime >= retention_limit) &&
|
||||||
(uint64_t) ss.f_bavail * (uint64_t) ss.f_bsize >= min_free)
|
(max_use <= 0 || sum <= max_use) &&
|
||||||
|
(min_free <= 0 || (uint64_t) ss.f_bavail * (uint64_t) ss.f_bsize >= min_free))
|
||||||
break;
|
break;
|
||||||
|
|
||||||
if (unlinkat(dirfd(d), list[i].filename, 0) >= 0) {
|
if (unlinkat(dirfd(d), list[i].filename, 0) >= 0) {
|
||||||
|
@ -218,6 +296,9 @@ int journal_directory_vacuum(const char *directory, uint64_t max_use, uint64_t m
|
||||||
log_warning("Failed to delete %s/%s: %m", directory, list[i].filename);
|
log_warning("Failed to delete %s/%s: %m", directory, list[i].filename);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (oldest_usec && i < n_list && (*oldest_usec == 0 || list[i].realtime < *oldest_usec))
|
||||||
|
*oldest_usec = list[i].realtime;
|
||||||
|
|
||||||
finish:
|
finish:
|
||||||
for (i = 0; i < n_list; i++)
|
for (i = 0; i < n_list; i++)
|
||||||
free(list[i].filename);
|
free(list[i].filename);
|
||||||
|
|
|
@ -23,4 +23,4 @@
|
||||||
|
|
||||||
#include <inttypes.h>
|
#include <inttypes.h>
|
||||||
|
|
||||||
int journal_directory_vacuum(const char *directory, uint64_t max_use, uint64_t min_free);
|
int journal_directory_vacuum(const char *directory, uint64_t max_use, uint64_t min_free, usec_t max_retention_usec, usec_t *oldest_usec);
|
||||||
|
|
|
@ -28,6 +28,8 @@ Journal.RuntimeMaxUse, config_parse_bytes_off, 0, offsetof(Server, runtime_
|
||||||
Journal.RuntimeMaxFileSize, config_parse_bytes_off, 0, offsetof(Server, runtime_metrics.max_size)
|
Journal.RuntimeMaxFileSize, config_parse_bytes_off, 0, offsetof(Server, runtime_metrics.max_size)
|
||||||
Journal.RuntimeMinFileSize, config_parse_bytes_off, 0, offsetof(Server, runtime_metrics.min_size)
|
Journal.RuntimeMinFileSize, config_parse_bytes_off, 0, offsetof(Server, runtime_metrics.min_size)
|
||||||
Journal.RuntimeKeepFree, config_parse_bytes_off, 0, offsetof(Server, runtime_metrics.keep_free)
|
Journal.RuntimeKeepFree, config_parse_bytes_off, 0, offsetof(Server, runtime_metrics.keep_free)
|
||||||
|
Journal.MaxRetentionSec, config_parse_usec, 0, offsetof(Server, max_retention_usec)
|
||||||
|
Journal.MaxFileSec, config_parse_usec, 0, offsetof(Server, max_file_usec)
|
||||||
Journal.ForwardToSyslog, config_parse_bool, 0, offsetof(Server, forward_to_syslog)
|
Journal.ForwardToSyslog, config_parse_bool, 0, offsetof(Server, forward_to_syslog)
|
||||||
Journal.ForwardToKMsg, config_parse_bool, 0, offsetof(Server, forward_to_kmsg)
|
Journal.ForwardToKMsg, config_parse_bool, 0, offsetof(Server, forward_to_kmsg)
|
||||||
Journal.ForwardToConsole, config_parse_bool, 0, offsetof(Server, forward_to_console)
|
Journal.ForwardToConsole, config_parse_bool, 0, offsetof(Server, forward_to_console)
|
||||||
|
|
|
@ -361,6 +361,8 @@ static void server_vacuum(Server *s) {
|
||||||
|
|
||||||
log_debug("Vacuuming...");
|
log_debug("Vacuuming...");
|
||||||
|
|
||||||
|
s->oldest_file_usec = 0;
|
||||||
|
|
||||||
r = sd_id128_get_machine(&machine);
|
r = sd_id128_get_machine(&machine);
|
||||||
if (r < 0) {
|
if (r < 0) {
|
||||||
log_error("Failed to get machine ID: %s", strerror(-r));
|
log_error("Failed to get machine ID: %s", strerror(-r));
|
||||||
|
@ -376,7 +378,7 @@ static void server_vacuum(Server *s) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
r = journal_directory_vacuum(p, s->system_metrics.max_use, s->system_metrics.keep_free);
|
r = journal_directory_vacuum(p, s->system_metrics.max_use, s->system_metrics.keep_free, s->max_retention_usec, &s->oldest_file_usec);
|
||||||
if (r < 0 && r != -ENOENT)
|
if (r < 0 && r != -ENOENT)
|
||||||
log_error("Failed to vacuum %s: %s", p, strerror(-r));
|
log_error("Failed to vacuum %s: %s", p, strerror(-r));
|
||||||
free(p);
|
free(p);
|
||||||
|
@ -389,7 +391,7 @@ static void server_vacuum(Server *s) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
r = journal_directory_vacuum(p, s->runtime_metrics.max_use, s->runtime_metrics.keep_free);
|
r = journal_directory_vacuum(p, s->runtime_metrics.max_use, s->runtime_metrics.keep_free, s->max_retention_usec, &s->oldest_file_usec);
|
||||||
if (r < 0 && r != -ENOENT)
|
if (r < 0 && r != -ENOENT)
|
||||||
log_error("Failed to vacuum %s: %s", p, strerror(-r));
|
log_error("Failed to vacuum %s: %s", p, strerror(-r));
|
||||||
free(p);
|
free(p);
|
||||||
|
@ -482,7 +484,7 @@ static void write_to_journal(Server *s, uid_t uid, struct iovec *iovec, unsigned
|
||||||
if (!f)
|
if (!f)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (journal_file_rotate_suggested(f)) {
|
if (journal_file_rotate_suggested(f, s->max_file_usec)) {
|
||||||
log_debug("%s: Journal header limits reached or header out-of-date, rotating.", f->path);
|
log_debug("%s: Journal header limits reached or header out-of-date, rotating.", f->path);
|
||||||
server_rotate(s);
|
server_rotate(s);
|
||||||
server_vacuum(s);
|
server_vacuum(s);
|
||||||
|
@ -1543,24 +1545,38 @@ int main(int argc, char *argv[]) {
|
||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
struct epoll_event event;
|
struct epoll_event event;
|
||||||
int t;
|
int t = -1;
|
||||||
|
usec_t n;
|
||||||
|
|
||||||
|
n = now(CLOCK_REALTIME);
|
||||||
|
|
||||||
|
if (server.max_retention_usec > 0 && server.oldest_file_usec > 0) {
|
||||||
|
|
||||||
|
/* The retention time is reached, so let's vacuum! */
|
||||||
|
if (server.oldest_file_usec + server.max_retention_usec < n) {
|
||||||
|
log_info("Retention time reached.");
|
||||||
|
server_rotate(&server);
|
||||||
|
server_vacuum(&server);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Calculate when to rotate the next time */
|
||||||
|
t = (int) ((server.oldest_file_usec + server.max_retention_usec - n + USEC_PER_MSEC - 1) / USEC_PER_MSEC);
|
||||||
|
log_info("Sleeping for %i ms", t);
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef HAVE_GCRYPT
|
#ifdef HAVE_GCRYPT
|
||||||
usec_t u;
|
if (server.system_journal) {
|
||||||
|
usec_t u;
|
||||||
|
|
||||||
if (server.system_journal &&
|
if (journal_file_next_evolve_usec(server.system_journal, &u)) {
|
||||||
journal_file_next_evolve_usec(server.system_journal, &u)) {
|
if (n >= u)
|
||||||
usec_t n;
|
t = 0;
|
||||||
|
else
|
||||||
n = now(CLOCK_REALTIME);
|
t = MIN(t, (int) ((u - n + USEC_PER_MSEC - 1) / USEC_PER_MSEC));
|
||||||
|
}
|
||||||
if (n >= u)
|
}
|
||||||
t = 0;
|
|
||||||
else
|
|
||||||
t = (int) ((u - n + USEC_PER_MSEC - 1) / USEC_PER_MSEC);
|
|
||||||
} else
|
|
||||||
#endif
|
#endif
|
||||||
t = -1;
|
|
||||||
|
|
||||||
r = epoll_wait(server.epoll_fd, &event, 1, t);
|
r = epoll_wait(server.epoll_fd, &event, 1, t);
|
||||||
if (r < 0) {
|
if (r < 0) {
|
||||||
|
|
|
@ -22,6 +22,8 @@
|
||||||
#RuntimeKeepFree=
|
#RuntimeKeepFree=
|
||||||
#RuntimeMaxFileSize=
|
#RuntimeMaxFileSize=
|
||||||
#RuntimeMinFileSize=
|
#RuntimeMinFileSize=
|
||||||
|
#MaxRetentionSec=
|
||||||
|
#MaxFileSec=1month
|
||||||
#ForwardToSyslog=yes
|
#ForwardToSyslog=yes
|
||||||
#ForwardToKMsg=no
|
#ForwardToKMsg=no
|
||||||
#ForwardToConsole=no
|
#ForwardToConsole=no
|
||||||
|
|
|
@ -91,6 +91,10 @@ typedef struct Server {
|
||||||
|
|
||||||
uint64_t var_available_timestamp;
|
uint64_t var_available_timestamp;
|
||||||
|
|
||||||
|
usec_t max_retention_usec;
|
||||||
|
usec_t max_file_usec;
|
||||||
|
usec_t oldest_file_usec;
|
||||||
|
|
||||||
gid_t file_gid;
|
gid_t file_gid;
|
||||||
bool file_gid_valid;
|
bool file_gid_valid;
|
||||||
|
|
||||||
|
|
|
@ -119,7 +119,7 @@ int main(int argc, char *argv[]) {
|
||||||
|
|
||||||
journal_file_close(f);
|
journal_file_close(f);
|
||||||
|
|
||||||
journal_directory_vacuum(".", 3000000, 0);
|
journal_directory_vacuum(".", 3000000, 0, 0, NULL);
|
||||||
|
|
||||||
log_error("Exiting...");
|
log_error("Exiting...");
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue