Add circular logging 12/11312/3
authorDave Barach <dave@barachs.net>
Thu, 22 Mar 2018 14:54:45 +0000 (10:54 -0400)
committerDamjan Marion <dmarion.lists@gmail.com>
Thu, 22 Mar 2018 22:36:20 +0000 (22:36 +0000)
Change-Id: Ide8bf41e24a427643a3a17b1c9089993790c12a6
Signed-off-by: Dave Barach <dave@barachs.net>
src/vppinfra/maplog.c
src/vppinfra/maplog.h
src/vppinfra/test_maplog.c

index deb07aa..1900aa8 100644 (file)
@@ -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)
        {
index 9bc8596..67a83a7 100644 (file)
@@ -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 */
     }
 
index edb61bd..7ae70c5 100644 (file)
@@ -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;