Improve some ancient, crufty code in bootstrap + initdb.
authorTom Lane <tgl@sss.pgh.pa.us>
Sat, 5 Sep 2020 20:20:04 +0000 (16:20 -0400)
committerTom Lane <tgl@sss.pgh.pa.us>
Sat, 5 Sep 2020 20:20:04 +0000 (16:20 -0400)
At some point back in the last century, somebody felt that reading
all of pg_type twice was cheaper, or at least easier, than using
repalloc() to resize the Typ[] array dynamically.  That seems like an
entirely wacko proposition, so rewrite the code to do it the other
way.  (To add insult to injury, there were two not-quite-identical
copies of said code.)

initdb.c's readfile() function had the same disease of preferring
to do double the I/O to avoid resizing its output array.  Here,
we can make things easier by using the just-invented pg_get_line()
function to handle reading individual lines without a predetermined
notion of how long they are.

On my machine, it's difficult to detect any net change in the
overall runtime of initdb from these changes; but they should
help on slower buildfarm machines (especially since a buildfarm
cycle involves a lot of initdb's these days).

My attention was drawn to these places by scan-build complaints,
but on inspection they needed a lot more work than just suppressing
dead stores :-(

src/backend/bootstrap/bootstrap.c
src/bin/initdb/initdb.c

index 45b7efbe4659f8cb5b824f9b414e75e614be8b50..76b2f5066f680cb448dfc2c2a472dd6e1f6d3b1a 100644 (file)
 uint32         bootstrap_data_checksum_version = 0;    /* No checksum */
 
 
-#define ALLOC(t, c) \
-       ((t *) MemoryContextAllocZero(TopMemoryContext, (unsigned)(c) * sizeof(t)))
-
 static void CheckerModeMain(void);
 static void BootstrapModeMain(void);
 static void bootstrap_signals(void);
 static void ShutdownAuxiliaryProcess(int code, Datum arg);
 static Form_pg_attribute AllocateAttribute(void);
+static void populate_typ_array(void);
 static Oid     gettype(char *type);
 static void cleanup(void);
 
@@ -583,46 +581,24 @@ ShutdownAuxiliaryProcess(int code, Datum arg)
 
 /* ----------------
  *             boot_openrel
+ *
+ * Execute BKI OPEN command.
  * ----------------
  */
 void
 boot_openrel(char *relname)
 {
        int                     i;
-       struct typmap **app;
-       Relation        rel;
-       TableScanDesc scan;
-       HeapTuple       tup;
 
        if (strlen(relname) >= NAMEDATALEN)
                relname[NAMEDATALEN - 1] = '\0';
 
+       /*
+        * pg_type must be filled before any OPEN command is executed, hence we
+        * can now populate the Typ array if we haven't yet.
+        */
        if (Typ == NULL)
-       {
-               /* We can now load the pg_type data */
-               rel = table_open(TypeRelationId, NoLock);
-               scan = table_beginscan_catalog(rel, 0, NULL);
-               i = 0;
-               while ((tup = heap_getnext(scan, ForwardScanDirection)) != NULL)
-                       ++i;
-               table_endscan(scan);
-               app = Typ = ALLOC(struct typmap *, i + 1);
-               while (i-- > 0)
-                       *app++ = ALLOC(struct typmap, 1);
-               *app = NULL;
-               scan = table_beginscan_catalog(rel, 0, NULL);
-               app = Typ;
-               while ((tup = heap_getnext(scan, ForwardScanDirection)) != NULL)
-               {
-                       (*app)->am_oid = ((Form_pg_type) GETSTRUCT(tup))->oid;
-                       memcpy((char *) &(*app)->am_typ,
-                                  (char *) GETSTRUCT(tup),
-                                  sizeof((*app)->am_typ));
-                       app++;
-               }
-               table_endscan(scan);
-               table_close(rel, NoLock);
-       }
+               populate_typ_array();
 
        if (boot_reldesc != NULL)
                closerel(NULL);
@@ -889,6 +865,52 @@ cleanup(void)
                closerel(NULL);
 }
 
+/* ----------------
+ *             populate_typ_array
+ *
+ * Load the Typ array by reading pg_type.
+ * ----------------
+ */
+static void
+populate_typ_array(void)
+{
+       Relation        rel;
+       TableScanDesc scan;
+       HeapTuple       tup;
+       int                     nalloc;
+       int                     i;
+
+       Assert(Typ == NULL);
+
+       nalloc = 512;
+       Typ = (struct typmap **)
+               MemoryContextAlloc(TopMemoryContext, nalloc * sizeof(struct typmap *));
+
+       rel = table_open(TypeRelationId, NoLock);
+       scan = table_beginscan_catalog(rel, 0, NULL);
+       i = 0;
+       while ((tup = heap_getnext(scan, ForwardScanDirection)) != NULL)
+       {
+               Form_pg_type typForm = (Form_pg_type) GETSTRUCT(tup);
+
+               /* make sure there will be room for a trailing NULL pointer */
+               if (i >= nalloc - 1)
+               {
+                       nalloc *= 2;
+                       Typ = (struct typmap **)
+                               repalloc(Typ, nalloc * sizeof(struct typmap *));
+               }
+               Typ[i] = (struct typmap *)
+                       MemoryContextAlloc(TopMemoryContext, sizeof(struct typmap));
+               Typ[i]->am_oid = typForm->oid;
+               memcpy(&(Typ[i]->am_typ), typForm, sizeof(Typ[i]->am_typ));
+               i++;
+       }
+       Typ[i] = NULL;                          /* Fill trailing NULL pointer */
+       table_endscan(scan);
+       table_close(rel, NoLock);
+}
+
 /* ----------------
  *             gettype
  *
@@ -903,14 +925,10 @@ cleanup(void)
 static Oid
 gettype(char *type)
 {
-       int                     i;
-       Relation        rel;
-       TableScanDesc scan;
-       HeapTuple       tup;
-       struct typmap **app;
-
        if (Typ != NULL)
        {
+               struct typmap **app;
+
                for (app = Typ; *app != NULL; app++)
                {
                        if (strncmp(NameStr((*app)->am_typ.typname), type, NAMEDATALEN) == 0)
@@ -922,33 +940,16 @@ gettype(char *type)
        }
        else
        {
+               int                     i;
+
                for (i = 0; i < n_types; i++)
                {
                        if (strncmp(type, TypInfo[i].name, NAMEDATALEN) == 0)
                                return i;
                }
+               /* Not in TypInfo, so we'd better be able to read pg_type now */
                elog(DEBUG4, "external type: %s", type);
-               rel = table_open(TypeRelationId, NoLock);
-               scan = table_beginscan_catalog(rel, 0, NULL);
-               i = 0;
-               while ((tup = heap_getnext(scan, ForwardScanDirection)) != NULL)
-                       ++i;
-               table_endscan(scan);
-               app = Typ = ALLOC(struct typmap *, i + 1);
-               while (i-- > 0)
-                       *app++ = ALLOC(struct typmap, 1);
-               *app = NULL;
-               scan = table_beginscan_catalog(rel, 0, NULL);
-               app = Typ;
-               while ((tup = heap_getnext(scan, ForwardScanDirection)) != NULL)
-               {
-                       (*app)->am_oid = ((Form_pg_type) GETSTRUCT(tup))->oid;
-                       memmove((char *) &(*app++)->am_typ,
-                                       (char *) GETSTRUCT(tup),
-                                       sizeof((*app)->am_typ));
-               }
-               table_endscan(scan);
-               table_close(rel, NoLock);
+               populate_typ_array();
                return gettype(type);
        }
        elog(ERROR, "unrecognized type \"%s\"", type);
index 73ddf408654a8c0b7bb392bf1bb4bb4f6ac632be..861b8817b9311e4e0962307c725c47c1f076ae9d 100644 (file)
@@ -468,14 +468,11 @@ filter_lines_with_token(char **lines, const char *token)
 static char **
 readfile(const char *path)
 {
+       char      **result;
        FILE       *infile;
-       int                     maxlength = 1,
-                               linelen = 0;
-       int                     nlines = 0;
+       int                     maxlines;
        int                     n;
-       char      **result;
-       char       *buffer;
-       int                     c;
+       char       *ln;
 
        if ((infile = fopen(path, "r")) == NULL)
        {
@@ -483,39 +480,24 @@ readfile(const char *path)
                exit(1);
        }
 
-       /* pass over the file twice - the first time to size the result */
+       maxlines = 1024;
+       result = (char **) pg_malloc(maxlines * sizeof(char *));
 
-       while ((c = fgetc(infile)) != EOF)
+       n = 0;
+       while ((ln = pg_get_line(infile)) != NULL)
        {
-               linelen++;
-               if (c == '\n')
+               /* make sure there will be room for a trailing NULL pointer */
+               if (n >= maxlines - 1)
                {
-                       nlines++;
-                       if (linelen > maxlength)
-                               maxlength = linelen;
-                       linelen = 0;
+                       maxlines *= 2;
+                       result = (char **) pg_realloc(result, maxlines * sizeof(char *));
                }
-       }
-
-       /* handle last line without a terminating newline (yuck) */
-       if (linelen)
-               nlines++;
-       if (linelen > maxlength)
-               maxlength = linelen;
 
-       /* set up the result and the line buffer */
-       result = (char **) pg_malloc((nlines + 1) * sizeof(char *));
-       buffer = (char *) pg_malloc(maxlength + 1);
-
-       /* now reprocess the file and store the lines */
-       rewind(infile);
-       n = 0;
-       while (fgets(buffer, maxlength + 1, infile) != NULL && n < nlines)
-               result[n++] = pg_strdup(buffer);
+               result[n++] = ln;
+       }
+       result[n] = NULL;
 
        fclose(infile);
-       free(buffer);
-       result[n] = NULL;
 
        return result;
 }