From 6ddede72126a8e5854908b6fcf4c80f55bf450cc Mon Sep 17 00:00:00 2001 From: Dave Barach Date: Thu, 22 Mar 2018 10:54:45 -0400 Subject: [PATCH] Add circular logging Change-Id: Ide8bf41e24a427643a3a17b1c9089993790c12a6 Signed-off-by: Dave Barach --- src/vppinfra/maplog.c | 58 ++++++++++++++++++++++++++++++++++++++-------- src/vppinfra/maplog.h | 21 ++++++++++++----- src/vppinfra/test_maplog.c | 27 +++++++++++++++++---- 3 files changed, 85 insertions(+), 21 deletions(-) diff --git a/src/vppinfra/maplog.c b/src/vppinfra/maplog.c index deb07aa9b76..1900aa8f03b 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 @@ clib_maplog_init (clib_maplog_init_args_t * a) /* 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 @@ clib_maplog_init (clib_maplog_init_args_t * a) 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 @@ clib_maplog_init (clib_maplog_init_args_t * a) 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 @@ fail: 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 @@ _clib_maplog_get_entry_slowpath (clib_maplog_main_t * mm, u64 my_record_index) 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 @@ clib_maplog_update_header (clib_maplog_main_t * mm) /* 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 @@ out: 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 @@ clib_maplog_close (clib_maplog_main_t * mm) 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 @@ format_maplog_header (u8 * s, va_list * args) 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 @@ clib_maplog_process (char *file_basename, void *fp_arg) 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 9bc8596de1b..67a83a72cf3 100644 --- a/src/vppinfra/maplog.h +++ b/src/vppinfra/maplog.h @@ -45,12 +45,12 @@ typedef struct 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 @@ typedef struct } 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 @@ typedef struct /* 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 @@ typedef struct 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 @@ clib_maplog_get_entry (clib_maplog_main_t * mm) /* 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 edb61bd84d0..7ae70c52f51 100644 --- a/src/vppinfra/test_maplog.c +++ b/src/vppinfra/test_maplog.c @@ -23,6 +23,12 @@ typedef struct 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 @@ process_maplog_records (clib_maplog_header_t * h, } e++; } - fformat (stdout, "--------------\n"); + fformat (stdout, "\n--------------\n"); } int @@ -58,12 +64,20 @@ test_maplog_main (unformat_input_t * input) 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 @@ test_maplog_main (unformat_input_t * input) 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 @@ test_maplog_main (unformat_input_t * input) 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; -- 2.16.6