Add circular logging
Change-Id: Ide8bf41e24a427643a3a17b1c9089993790c12a6
Signed-off-by: Dave Barach <dave@barachs.net>
diff --git a/src/vppinfra/maplog.c b/src/vppinfra/maplog.c
index deb07aa..1900aa8 100644
--- a/src/vppinfra/maplog.c
+++ b/src/vppinfra/maplog.c
@@ -27,7 +27,7 @@
int
clib_maplog_init (clib_maplog_init_args_t * a)
{
- int i, fd;
+ int i, fd, limit;
int rv = 0;
u8 zero = 0;
u32 record_size_in_cache_lines;
@@ -54,7 +54,6 @@
/* Round up file size in records to a power of 2, for speed... */
mm->log2_file_size_in_records = max_log2 (file_size_in_records);
file_size_in_records = 1ULL << (mm->log2_file_size_in_records);
-
a->file_size_in_bytes = file_size_in_records * record_size_in_cache_lines
* CLIB_CACHE_LINE_BYTES;
@@ -68,9 +67,19 @@
mm->file_size_in_records = file_size_in_records;
mm->flags |= CLIB_MAPLOG_FLAG_INIT;
mm->record_size_in_cachelines = record_size_in_cache_lines;
+ limit = 2;
+ if (a->maplog_is_circular)
+ {
+ mm->log2_file_size_in_records = 63;
+ mm->flags |= CLIB_MAPLOG_FLAG_CIRCULAR;
+ limit = 1;
+ }
- /* Map two files */
- for (i = 0; i < 2; i++)
+ /*
+ * Map the one and only file for a circular log,
+ * two files for a normal log.
+ */
+ for (i = 0; i < limit; i++)
{
mm->filenames[i] = format (0, "%v_%d", mm->file_basename,
mm->current_file_index++);
@@ -117,6 +126,7 @@
h->file_size_in_records = file_size_in_records;
h->number_of_records = ~0ULL;
h->number_of_files = ~0ULL;
+ h->maplog_flag_circular = a->maplog_is_circular;
memcpy (h->file_basename, mm->file_basename, vec_len (mm->file_basename));
mm->header_filename = format (0, "%v_header", mm->file_basename);
@@ -143,7 +153,7 @@
if (fd >= 0)
(void) close (fd);
- for (i = 0; i < 2; i++)
+ for (i = 0; i < limit; i++)
{
if (mm->file_baseva[i])
(void) munmap ((u8 *) mm->file_baseva[i], a->file_size_in_bytes);
@@ -171,6 +181,9 @@
u64 file_size_in_bytes = mm->file_size_in_records
* mm->record_size_in_cachelines * CLIB_CACHE_LINE_BYTES;
+ /* This should never happen */
+ ASSERT ((mm->flags & CLIB_MAPLOG_FLAG_CIRCULAR) == 0);
+
/*
* Kill some time by calling format before we make the previous log
* segment disappear. Obviously it won't do to call clib_maplog_get_entry(),
@@ -256,6 +269,7 @@
/* Fix the header... */
h->number_of_records = mm->next_record_index;
h->number_of_files = mm->current_file_index;
+ h->maplog_flag_wrapped = (mm->flags & CLIB_MAPLOG_FLAG_WRAPPED) ? 1 : 0;
/* Back to the beginning of the log header... */
if (lseek (fd, 0, SEEK_SET) < 0)
@@ -284,7 +298,7 @@
void
clib_maplog_close (clib_maplog_main_t * mm)
{
- int i;
+ int i, limit;
u64 file_size_in_bytes;
if (!(mm->flags & CLIB_MAPLOG_FLAG_INIT))
@@ -296,8 +310,10 @@
mm->file_size_in_records * mm->record_size_in_cachelines *
CLIB_CACHE_LINE_BYTES;
+ limit = (mm->flags & CLIB_MAPLOG_FLAG_CIRCULAR) ? 1 : 2;
+
/* unmap current + next segments */
- for (i = 0; i < 2; i++)
+ for (i = 0; i < limit; i++)
{
(void) munmap ((u8 *) mm->file_baseva[i], file_size_in_bytes);
vec_free (mm->filenames[i]);
@@ -324,13 +340,15 @@
if (!verbose)
goto brief;
s = format (s, "basename %s ", h->file_basename);
- s = format (s, "log ver %d.%d.%d app id %u ver %d.%d.%d\n",
+ s = format (s, "log ver %d.%d.%d app id %u ver %d.%d.%d %s %s\n",
h->maplog_major_version,
h->maplog_minor_version,
h->maplog_patch_version,
h->application_id,
h->application_major_version,
- h->application_minor_version, h->application_patch_version);
+ h->application_minor_version, h->application_patch_version,
+ h->maplog_flag_circular ? "circular" : "linear",
+ h->maplog_flag_wrapped ? "wrapped" : "not wrapped");
s = format (s, " records are %d %d-byte cachelines\n",
h->record_size_in_cachelines, h->cacheline_size);
s = format (s, " files are %lld records long, %lld files\n",
@@ -427,7 +445,27 @@
records_this_file = (records_left > h->file_size_in_records) ?
h->file_size_in_records : records_left;
- (*fp) (h, file_baseva, records_this_file);
+ /*
+ * Normal log, or a circular non-wrapped log, or a circular
+ * wrapped log which happens to be exactly linear
+ */
+ if (h->maplog_flag_circular == 0 || h->maplog_flag_wrapped == 0 ||
+ ((h->number_of_records % h->file_size_in_records) == 0))
+ (*fp) (h, file_baseva, records_this_file);
+ else
+ {
+ /* "Normal" wrapped circular log */
+ u64 first_chunk_record_index = h->number_of_records &
+ (h->file_size_in_records - 1);
+ u64 first_chunk_number_of_records = records_this_file -
+ first_chunk_record_index;
+ u8 *chunk_baseva = file_baseva +
+ first_chunk_record_index * h->record_size_in_cachelines *
+ h->cacheline_size;
+ (*fp) (h, chunk_baseva, first_chunk_number_of_records);
+ (*fp) (h, file_baseva,
+ records_this_file - first_chunk_number_of_records);
+ }
if (munmap (file_baseva, file_size_in_bytes) < 0)
{
diff --git a/src/vppinfra/maplog.h b/src/vppinfra/maplog.h
index 9bc8596..67a83a7 100644
--- a/src/vppinfra/maplog.h
+++ b/src/vppinfra/maplog.h
@@ -45,12 +45,12 @@
u8 maplog_major_version; /**< library major version number */
u8 maplog_minor_version; /**< library minor version number */
u8 maplog_patch_version; /**< library patch version number */
- u8 pad;
+ u8 maplog_flag_wrapped; /**< log has wrapped */
u32 application_id; /**< application identifier */
u8 application_major_version; /**< application major version number */
u8 application_minor_version; /**< application minor version number */
u8 application_patch_version; /**< application patch version number */
- u8 pad2;
+ u8 maplog_flag_circular; /**< log is circular */
u32 record_size_in_cachelines; /**< record size in cache lines */
u32 cacheline_size; /**< cache line size */
u64 file_size_in_records; /**< file size in records */
@@ -60,7 +60,7 @@
} clib_maplog_header_t;
#define MAPLOG_MAJOR_VERSION 1
-#define MAPLOG_MINOR_VERSION 0
+#define MAPLOG_MINOR_VERSION 1
#define MAPLOG_PATCH_VERSION 0
/** Process-private main data structure */
@@ -90,6 +90,8 @@
/* flag bits */
#define CLIB_MAPLOG_FLAG_INIT (1<<0)
+#define CLIB_MAPLOG_FLAG_CIRCULAR (1<<1)
+#define CLIB_MAPLOG_FLAG_WRAPPED (1<<2)
/** log initialization structure */
typedef struct
@@ -102,6 +104,7 @@
u8 application_major_version; /**< applcation major version number */
u8 application_minor_version; /**< applcation minor version number */
u8 application_patch_version; /**< applcation patch version number */
+ u8 maplog_is_circular; /**< single, circular log */
} clib_maplog_init_args_t;
/* function prototypes */
@@ -139,9 +142,15 @@
/* Time to unmap and create a new logfile? */
if (PREDICT_FALSE ((my_record_index & (mm->file_size_in_records - 1)) == 0))
{
- /* Yes, but not the very first time... (;-)... */
- if (my_record_index)
- return _clib_maplog_get_entry_slowpath (mm, my_record_index);
+ /* Regular log? Switch file... */
+ if (!(mm->flags & CLIB_MAPLOG_FLAG_CIRCULAR))
+ {
+ /* Yes, but not the very first time... (;-)... */
+ if (my_record_index)
+ return _clib_maplog_get_entry_slowpath (mm, my_record_index);
+ }
+ else /* Circular log: set the wrap bit and move along */
+ mm->flags |= CLIB_MAPLOG_FLAG_WRAPPED;
/* FALLTHROUGH */
}
diff --git a/src/vppinfra/test_maplog.c b/src/vppinfra/test_maplog.c
index edb61bd..7ae70c5 100644
--- a/src/vppinfra/test_maplog.c
+++ b/src/vppinfra/test_maplog.c
@@ -23,6 +23,12 @@
u64 junk[7];
} test_entry_t;
+typedef enum
+{
+ TEST_NORMAL,
+ TEST_CIRCULAR,
+} test_type_t;
+
static void
process_maplog_records (clib_maplog_header_t * h,
test_entry_t * e, u64 records_this_file)
@@ -49,7 +55,7 @@
}
e++;
}
- fformat (stdout, "--------------\n");
+ fformat (stdout, "\n--------------\n");
}
int
@@ -58,12 +64,20 @@
clib_maplog_main_t *mm = &maplog_main;
clib_maplog_init_args_t _a, *a = &_a;
int rv;
- int i;
+ int i, limit;
test_entry_t *t;
int noclose = 0;
+ test_type_t which = TEST_NORMAL;
- if (unformat (input, "noclose"))
- noclose = 1;
+ while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
+ {
+ if (unformat (input, "noclose"))
+ noclose = 1;
+ else if (unformat (input, "circular"))
+ which = TEST_CIRCULAR;
+ else
+ clib_warning ("unknown input '%U'", format_unformat_error, input);
+ }
memset (a, 0, sizeof (*a));
a->mm = mm;
@@ -74,6 +88,7 @@
a->application_major_version = 1;
a->application_minor_version = 0;
a->application_patch_version = 0;
+ a->maplog_is_circular = (which == TEST_CIRCULAR) ? 1 : 0;
rv = clib_maplog_init (a);
@@ -83,7 +98,9 @@
exit (1);
}
- for (i = 0; i < 64 * 5; i++)
+ limit = (which == TEST_CIRCULAR) ? (64 + 2) : 64 * 5;
+
+ for (i = 0; i < limit; i++)
{
t = clib_maplog_get_entry (mm);
t->serial_number = i + 1;