bug-recutils
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[bug-recutils] [PATCH 06/13] utils,doc: make re cfix --build-index add i


From: Michał Masłowski
Subject: [bug-recutils] [PATCH 06/13] utils,doc: make re cfix --build-index add index trees.
Date: Mon, 20 Aug 2012 18:21:27 +0200

The index file build APIs should be probably changed to make the use
of a temporary file not so integrated with adding indexes.
---
 ChangeLog         |  10 +++
 doc/recutils.texi |   5 +-
 utils/recfix.c    | 246 ++++++++++++++++++++++++++++++++++++++++++++++++------
 3 files changed, 233 insertions(+), 28 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index 2a61ffe..9de0115 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,15 @@
 2012-08-18  Michał Masłowski  <address@hidden>
 
+       utils,doc: make recfix --build-index add index trees.
+
+       * utils/recfix.c (recfix_do_build_index): Add indexes from %key or
+       index file.
+
+       * doc/recutils.texi (recfix Invocation): Document recfix
+       --build-index regarding indexes.
+
+2012-08-18  Michał Masłowski  <address@hidden>
+
        src: fix index file builder.
        * src/rec-idx-file.c (rec_idx_build_file): Add padding after rset
        names.
diff --git a/doc/recutils.texi b/doc/recutils.texi
index 6523a61..72bd12c 100644
--- a/doc/recutils.texi
+++ b/doc/recutils.texi
@@ -2820,7 +2820,10 @@ Note that this is a destructive operation.
 
 @itemx @address@hidden
 Build the index file for this recfile.  The file argument is required to
-determine the index file name and get recfile filesystem metadata.
+determine the index file name and get recfile filesystem metadata.  If
+an index file is found, it will be regenerated with the same (supported)
+indexes.  Otherwise the new file will contain only indexes for record
+set primary keys.
 @end table
 
 Some operations make use of certain specific options, which are
diff --git a/utils/recfix.c b/utils/recfix.c
index 75c0d5e..840a52d 100644
--- a/utils/recfix.c
+++ b/utils/recfix.c
@@ -31,6 +31,7 @@
 #include <getpass.h>
 #include <gettext.h>
 #define _(str) gettext (str)
+#include <sys/stat.h>
 
 #include <rec.h>
 #include <recutl.h>
@@ -537,11 +538,21 @@ recfix_do_auto ()
 static int
 recfix_do_build_index (void)
 {
-  FILE *recfile, *idx = NULL;
+  FILE *recfile, *idx = NULL, *idx_read = NULL;
   rec_db_t db;
-  int64_t time;
-  size_t size;
+  int64_t time, index_type;
+  size_t size, num_indexes = 0, index_size, n_fields, n, rset_number;
   char *index_name;
+  rec_idx_file_t idx_file = NULL;
+  bool res = true;
+  uint8_t *index_data = NULL, *old_index = NULL;
+  rec_idx_tree_t old_tree;
+  rec_rset_t rset;
+  const char **field_names;
+  rec_idx_tree_key_t *field_types;
+  char tmp_file_name[100];
+  int stat_result, des;
+  struct stat st1;
 
   if (!recfix_file)
     {
@@ -554,48 +565,229 @@ recfix_do_build_index (void)
     {
       return EXIT_FAILURE;
     }
+
   recfile = fopen (recfix_file, "r");
-  if (!recfile)
+  if (!recfile || !recutl_parse_db_from_file (recfile, recfix_file, db))
     {
-      rec_db_destroy (db);
-      return EXIT_FAILURE;
+      res = false;
     }
-  if (!recutl_parse_db_from_file (recfile, recfix_file, db))
+
+  /* Get its metadata. */
+  if (res && !rec_idx_get_time_size (recfile, &time, &size))
     {
-      rec_db_destroy (db);
-      fclose (recfile);
-      return EXIT_FAILURE;
+      res = false;
     }
 
-  /* Get its metadata. */
-  if (!rec_idx_get_time_size (recfile, &time, &size))
+  if (recfile)
     {
-      rec_db_destroy (db);
       fclose (recfile);
-      return EXIT_FAILURE;
     }
-  fclose (recfile);
 
-  /* Open the index file for write.  When indices will be supported,
-     it will be opened for read first to know what indices to
-     regenerate.  */
-  index_name = rec_idx_get_file_name (recfix_file);
-  if (index_name)
+  /* Get the index file name. */
+  if (res)
+    {
+      index_name = rec_idx_get_file_name (recfix_file);
+      if (!index_name)
+        {
+          res = false;
+        }
+    }
+
+  /* Open the index file for read if it exists.  Intentionally no
+     verification of the file is done, since this operation is not
+     useful with valid index files (although they should be
+     parsable).  */
+  if (res)
     {
-      idx = fopen (index_name, "wb");
+      idx_read = fopen (index_name, "rb");
+      if (idx_read)
+        {
+          idx_file = rec_idx_file_new (idx_read);
+        }
     }
-  if (idx)
+
+  /* Record the original index file attributes. */
+  stat_result = stat (index_name, &st1);
+
+  /* Use a temporary file for writing the index. */
+  if (res)
+    {
+      strcpy (tmp_file_name, "recXXXXXX");
+      des = mkstemp (tmp_file_name);
+      if (des == -1)
+        {
+          recutl_fatal (_("cannot create a unique name.\n"));
+        }
+      idx = fdopen (des, "wb");
+    }
+
+  if (!idx)
+    {
+      res = false;
+    }
+
+  /* Build the index file.  Indexes will be added later.  */
+  if (res && !rec_idx_build_file (db, idx, time, size, 0))
+    {
+      res = false;
+    }
+
+  /* Add indexes from the index file if available or from rset %keys
+     (in future choosing appropriate types).  */
+  if (res && idx_file)
+    {
+      while (res && ((old_index = (uint8_t *)
+                      rec_idx_file_index (idx_file,
+                                          (char *) old_index,
+                                          &index_type,
+                                          &index_size)) != NULL))
+        {
+          /* Read the old index. */
+          old_tree = rec_idx_tree_new (old_index, index_type, index_size);
+          if (old_tree == NULL)
+            {
+              /* Unsupported index, won't be added. */
+              continue;
+            }
+
+          /* Construct key type data. */
+          rset_number = rec_idx_tree_get_rset_number (old_tree);
+          n_fields = rec_idx_tree_get_num_fields (old_tree);
+          rset = rec_db_get_rset (db, rset_number);
+          if (!rset)
+            {
+              res = false;
+            }
+
+          if (res)
+            {
+              field_names = malloc (sizeof (*field_names) * n_fields);
+              field_types = malloc (sizeof (*field_types) * n_fields);
+
+              if (!field_names || !field_types)
+                {
+                  res = false;
+                }
+            }
+
+          if (res)
+            {
+              for (n = 0; n < n_fields; n++)
+                {
+                  field_names[n] = rec_idx_tree_get_field_name (old_tree, n);
+                  field_types[n] = rec_idx_tree_get_field_type (old_tree, n);
+                }
+            }
+
+          /* Build the new index. */
+          if (res)
+            {
+              res = rec_idx_tree_build (rset, rset_number, n_fields,
+                                        field_names, field_types,
+                                        &index_data, &index_size, &index_type);
+            }
+
+          if (res)
+            {
+              res = rec_idx_build_add_index (idx, index_type, index_size,
+                                             (char *) index_data);
+              free (index_data);
+            }
+
+          if (field_names)
+            {
+              free (field_names);
+            }
+
+          if (field_types)
+            {
+              free (field_types);
+            }
+
+          rec_idx_tree_destroy (old_tree);
+
+          if (res)
+            {
+              num_indexes++;
+            }
+        }
+    }
+  else if (res)
     {
-      /* Build the index file without indices. */
-      if (rec_idx_build_file (db, idx, time, size, 0))
+      /* Add indexes for rset primary keys. */
+      for (rset_number = 0; rset_number < rec_db_size (db); rset_number++)
         {
-          fclose (idx);
-          return EXIT_SUCCESS;
+          /* A record has only one primary key (i.e. not a tuple).  In
+             future other types should be used depending on the key
+             field type.  */
+          const char *field_names[1];
+          const rec_idx_tree_key_t field_types[1] = {REC_IDX_KEY_STRING};
+
+          rset = rec_db_get_rset (db, rset_number);
+          field_names[0] = rec_rset_key (rset);
+
+          if (field_names[0] == NULL)
+            {
+              continue;  /* no key */
+            }
+
+          res = rec_idx_tree_build (rset, rset_number, 1,
+                                    field_names, field_types,
+                                    &index_data, &index_size, &index_type);
+
+          if (res)
+            {
+              res = rec_idx_build_add_index (idx, index_type, index_size,
+                                             (char *) index_data);
+              free (index_data);
+            }
+
+          if (res)
+            {
+              num_indexes++;
+            }
         }
+    }
+
+  if (res)
+    {
+      rec_idx_build_num_indices (idx, num_indexes);
+    }
+
+  if (db)
+    {
+      rec_db_destroy (db);
+    }
+
+  if (idx)
+    {
       fclose (idx);
     }
 
-  return EXIT_FAILURE;
+  if (idx_file)
+    {
+      rec_idx_file_destroy (idx_file);
+    }
+
+  /* Rename the temporary file to file_name.  */
+  if (rename (tmp_file_name, index_name) == -1)
+    {
+      remove (tmp_file_name);
+      recutl_fatal (_("renaming file %s to %s\n"), tmp_file_name, index_name);
+    }
+
+  /* Restore the attributes of the original file. */
+  if (stat_result != -1)
+    {
+      chmod (index_name, st1.st_mode);
+    }
+
+  if (idx_read)
+    {
+      fclose (idx_read);
+    }
+
+  return res ? EXIT_SUCCESS : EXIT_FAILURE;
 }
 
 int
-- 
1.7.11.4




reply via email to

[Prev in Thread] Current Thread [Next in Thread]