#include "lookup3.h"
#include "compress.h"
-#define DEFAULT_DATA_HASH_TABLE_SIZE (2047ULL*16ULL)
-#define DEFAULT_FIELD_HASH_TABLE_SIZE (2047ULL*16ULL)
+#define DEFAULT_DATA_HASH_TABLE_SIZE (2047ULL*sizeof(HashItem))
+#define DEFAULT_FIELD_HASH_TABLE_SIZE (333ULL*sizeof(HashItem))
#define DEFAULT_WINDOW_SIZE (8ULL*1024ULL*1024ULL)
assert(f);
if (f->header) {
- if (f->writable)
+ /* Mark the file offline. Don't override the archived state if it already is set */
+ if (f->writable && f->header->state == STATE_ONLINE)
f->header->state = STATE_OFFLINE;
munmap(f->header, PAGE_ALIGN(sizeof(Header)));
assert(f);
- s = DEFAULT_DATA_HASH_TABLE_SIZE;
+ /* We estimate that we need 1 hash table entry per 768 of
+ journal file and we want to make sure we never get beyond
+ 75% fill level. Calculate the hash table size for the
+ maximum file size based on these metrics. */
+
+ s = (f->metrics.max_size * 4 / 768 / 3) * sizeof(HashItem);
+ if (s < DEFAULT_DATA_HASH_TABLE_SIZE)
+ s = DEFAULT_DATA_HASH_TABLE_SIZE;
+
+ log_info("Reserving %llu entries in hash table.", (unsigned long long) (s / sizeof(HashItem)));
+
r = journal_file_append_object(f,
OBJECT_DATA_HASH_TABLE,
offsetof(Object, hash_table.items) + s,
"Machine ID: %s\n"
"Boot ID: %s\n"
"Sequential Number ID: %s\n"
+ "State: %s\n"
+ "Compatible Flags:%s%s\n"
+ "Incompatible Flags:%s%s\n"
"Header size: %llu\n"
"Arena size: %llu\n"
"Data Hash Table Size: %llu\n"
sd_id128_to_string(f->header->machine_id, b),
sd_id128_to_string(f->header->boot_id, c),
sd_id128_to_string(f->header->seqnum_id, c),
+ f->header->state == STATE_OFFLINE ? "offline" :
+ f->header->state == STATE_ONLINE ? "online" :
+ f->header->state == STATE_ARCHIVED ? "archived" : "unknown",
+ (f->header->compatible_flags & HEADER_COMPATIBLE_SIGNED) ? " SIGNED" : "",
+ (f->header->compatible_flags & ~HEADER_COMPATIBLE_SIGNED) ? " ???" : "",
+ (f->header->incompatible_flags & HEADER_INCOMPATIBLE_COMPRESSED) ? " COMPRESSED" : "",
+ (f->header->incompatible_flags & ~HEADER_INCOMPATIBLE_COMPRESSED) ? " ???" : "",
(unsigned long long) le64toh(f->header->header_size),
(unsigned long long) le64toh(f->header->arena_size),
(unsigned long long) le64toh(f->header->data_hash_table_size) / sizeof(HashItem),
const char *fname,
int flags,
mode_t mode,
+ JournalMetrics *metrics,
JournalFile *template,
JournalFile **ret) {
f->writable = (flags & O_ACCMODE) != O_RDONLY;
f->prot = prot_from_flags(flags);
- if (template) {
- f->metrics = template->metrics;
+ if (template)
f->compress = template->compress;
- }
f->path = strdup(fname);
if (!f->path) {
}
if (f->writable) {
+ if (metrics) {
+ journal_default_metrics(metrics, f->fd);
+ f->metrics = *metrics;
+ } else if (template)
+ f->metrics = template->metrics;
+
r = journal_file_refresh_header(f);
if (r < 0)
goto fail;
old_file->header->state = STATE_ARCHIVED;
- r = journal_file_open(old_file->path, old_file->flags, old_file->mode, old_file, &new_file);
+ r = journal_file_open(old_file->path, old_file->flags, old_file->mode, NULL, old_file, &new_file);
journal_file_close(old_file);
*f = new_file;
const char *fname,
int flags,
mode_t mode,
+ JournalMetrics *metrics,
JournalFile *template,
JournalFile **ret) {
size_t l;
char *p;
- r = journal_file_open(fname, flags, mode, template, ret);
+ r = journal_file_open(fname, flags, mode, metrics, template, ret);
if (r != -EBADMSG && /* corrupted */
r != -ENODATA && /* truncated */
r != -EHOSTDOWN && /* other machine */
- r != -EPROTONOSUPPORT) /* incompatible feature */
+ r != -EPROTONOSUPPORT && /* incompatible feature */
+ r != -EBUSY && /* unclean shutdown */
+ r != -ESHUTDOWN /* already archived */)
return r;
if ((flags & O_ACCMODE) == O_RDONLY)
if (r < 0)
return -errno;
- log_warning("File %s corrupted, renaming and replacing.", fname);
+ log_warning("File %s corrupted or uncleanly shut down, renaming and replacing.", fname);
- return journal_file_open(fname, flags, mode, template, ret);
+ return journal_file_open(fname, flags, mode, metrics, template, ret);
}
struct vacuum_info {
/* If we gained new header fields we gained new features,
* hence suggest a rotation */
- if (le64toh(f->header->header_size) < sizeof(Header))
+ if (le64toh(f->header->header_size) < sizeof(Header)) {
+ log_debug("%s uses an outdated header, suggesting rotation.", f->path);
return true;
+ }
/* Let's check if the hash tables grew over a certain fill
* level (75%, borrowing this value from Java's hash table
* in newer versions. */
if (JOURNAL_HEADER_CONTAINS(f->header, n_data))
- if (le64toh(f->header->n_data) * 4ULL > (le64toh(f->header->data_hash_table_size) / sizeof(HashItem)) * 3ULL)
+ if (le64toh(f->header->n_data) * 4ULL > (le64toh(f->header->data_hash_table_size) / sizeof(HashItem)) * 3ULL) {
+ log_debug("Data hash table of %s has a fill level at %.1f (%llu of %llu items, %llu file size, %llu bytes per hash table item), suggesting rotation.",
+ f->path,
+ 100.0 * (double) le64toh(f->header->n_data) / ((double) (le64toh(f->header->data_hash_table_size) / sizeof(HashItem))),
+ (unsigned long long) le64toh(f->header->n_data),
+ (unsigned long long) (le64toh(f->header->data_hash_table_size) / sizeof(HashItem)),
+ (unsigned long long) (f->last_stat.st_size),
+ (unsigned long long) (f->last_stat.st_size / le64toh(f->header->n_data)));
return true;
+ }
if (JOURNAL_HEADER_CONTAINS(f->header, n_fields))
- if (le64toh(f->header->n_fields) * 4ULL > (le64toh(f->header->field_hash_table_size) / sizeof(HashItem)) * 3ULL)
+ if (le64toh(f->header->n_fields) * 4ULL > (le64toh(f->header->field_hash_table_size) / sizeof(HashItem)) * 3ULL) {
+ log_debug("Field hash table of %s has a fill level at %.1f (%llu of %llu items), suggesting rotation.",
+ f->path,
+ 100.0 * (double) le64toh(f->header->n_fields) / ((double) (le64toh(f->header->field_hash_table_size) / sizeof(HashItem))),
+ (unsigned long long) le64toh(f->header->n_fields),
+ (unsigned long long) (le64toh(f->header->field_hash_table_size) / sizeof(HashItem)));
return true;
+ }
return false;
}