aboutsummaryrefslogtreecommitdiff
path: root/src/backend/bootstrap/bootstrap.c
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>2020-09-05 16:20:04 -0400
committerTom Lane <tgl@sss.pgh.pa.us>2020-09-05 16:20:04 -0400
commite0f05cd5ba76a75e2ce3b85ba050e48e857dca00 (patch)
tree5c0ba4e65ab145e66f8c1ccadf026a3f4cbea957 /src/backend/bootstrap/bootstrap.c
parenta5cc4dab6d1d694f113912a2aca7012a95262f0b (diff)
downloadpostgresql-e0f05cd5ba76a75e2ce3b85ba050e48e857dca00.tar.gz
postgresql-e0f05cd5ba76a75e2ce3b85ba050e48e857dca00.zip
Improve some ancient, crufty code in bootstrap + initdb.
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 :-(
Diffstat (limited to 'src/backend/bootstrap/bootstrap.c')
-rw-r--r--src/backend/bootstrap/bootstrap.c119
1 files changed, 60 insertions, 59 deletions
diff --git a/src/backend/bootstrap/bootstrap.c b/src/backend/bootstrap/bootstrap.c
index 45b7efbe465..76b2f5066f6 100644
--- a/src/backend/bootstrap/bootstrap.c
+++ b/src/backend/bootstrap/bootstrap.c
@@ -53,14 +53,12 @@
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);
@@ -890,6 +866,52 @@ cleanup(void)
}
/* ----------------
+ * 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
*
* NB: this is really ugly; it will return an integer index into TypInfo[],
@@ -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);