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 :-(
This commit is contained in:
parent
a5cc4dab6d
commit
e0f05cd5ba
@ -53,14 +53,12 @@
|
|||||||
uint32 bootstrap_data_checksum_version = 0; /* No checksum */
|
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 CheckerModeMain(void);
|
||||||
static void BootstrapModeMain(void);
|
static void BootstrapModeMain(void);
|
||||||
static void bootstrap_signals(void);
|
static void bootstrap_signals(void);
|
||||||
static void ShutdownAuxiliaryProcess(int code, Datum arg);
|
static void ShutdownAuxiliaryProcess(int code, Datum arg);
|
||||||
static Form_pg_attribute AllocateAttribute(void);
|
static Form_pg_attribute AllocateAttribute(void);
|
||||||
|
static void populate_typ_array(void);
|
||||||
static Oid gettype(char *type);
|
static Oid gettype(char *type);
|
||||||
static void cleanup(void);
|
static void cleanup(void);
|
||||||
|
|
||||||
@ -583,46 +581,24 @@ ShutdownAuxiliaryProcess(int code, Datum arg)
|
|||||||
|
|
||||||
/* ----------------
|
/* ----------------
|
||||||
* boot_openrel
|
* boot_openrel
|
||||||
|
*
|
||||||
|
* Execute BKI OPEN command.
|
||||||
* ----------------
|
* ----------------
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
boot_openrel(char *relname)
|
boot_openrel(char *relname)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
struct typmap **app;
|
|
||||||
Relation rel;
|
|
||||||
TableScanDesc scan;
|
|
||||||
HeapTuple tup;
|
|
||||||
|
|
||||||
if (strlen(relname) >= NAMEDATALEN)
|
if (strlen(relname) >= NAMEDATALEN)
|
||||||
relname[NAMEDATALEN - 1] = '\0';
|
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)
|
if (Typ == NULL)
|
||||||
{
|
populate_typ_array();
|
||||||
/* 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);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (boot_reldesc != NULL)
|
if (boot_reldesc != NULL)
|
||||||
closerel(NULL);
|
closerel(NULL);
|
||||||
@ -889,6 +865,52 @@ cleanup(void)
|
|||||||
closerel(NULL);
|
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
|
* gettype
|
||||||
*
|
*
|
||||||
@ -903,14 +925,10 @@ cleanup(void)
|
|||||||
static Oid
|
static Oid
|
||||||
gettype(char *type)
|
gettype(char *type)
|
||||||
{
|
{
|
||||||
int i;
|
|
||||||
Relation rel;
|
|
||||||
TableScanDesc scan;
|
|
||||||
HeapTuple tup;
|
|
||||||
struct typmap **app;
|
|
||||||
|
|
||||||
if (Typ != NULL)
|
if (Typ != NULL)
|
||||||
{
|
{
|
||||||
|
struct typmap **app;
|
||||||
|
|
||||||
for (app = Typ; *app != NULL; app++)
|
for (app = Typ; *app != NULL; app++)
|
||||||
{
|
{
|
||||||
if (strncmp(NameStr((*app)->am_typ.typname), type, NAMEDATALEN) == 0)
|
if (strncmp(NameStr((*app)->am_typ.typname), type, NAMEDATALEN) == 0)
|
||||||
@ -922,33 +940,16 @@ gettype(char *type)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
for (i = 0; i < n_types; i++)
|
for (i = 0; i < n_types; i++)
|
||||||
{
|
{
|
||||||
if (strncmp(type, TypInfo[i].name, NAMEDATALEN) == 0)
|
if (strncmp(type, TypInfo[i].name, NAMEDATALEN) == 0)
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
|
/* Not in TypInfo, so we'd better be able to read pg_type now */
|
||||||
elog(DEBUG4, "external type: %s", type);
|
elog(DEBUG4, "external type: %s", type);
|
||||||
rel = table_open(TypeRelationId, NoLock);
|
populate_typ_array();
|
||||||
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);
|
|
||||||
return gettype(type);
|
return gettype(type);
|
||||||
}
|
}
|
||||||
elog(ERROR, "unrecognized type \"%s\"", type);
|
elog(ERROR, "unrecognized type \"%s\"", type);
|
||||||
|
@ -468,14 +468,11 @@ filter_lines_with_token(char **lines, const char *token)
|
|||||||
static char **
|
static char **
|
||||||
readfile(const char *path)
|
readfile(const char *path)
|
||||||
{
|
{
|
||||||
FILE *infile;
|
|
||||||
int maxlength = 1,
|
|
||||||
linelen = 0;
|
|
||||||
int nlines = 0;
|
|
||||||
int n;
|
|
||||||
char **result;
|
char **result;
|
||||||
char *buffer;
|
FILE *infile;
|
||||||
int c;
|
int maxlines;
|
||||||
|
int n;
|
||||||
|
char *ln;
|
||||||
|
|
||||||
if ((infile = fopen(path, "r")) == NULL)
|
if ((infile = fopen(path, "r")) == NULL)
|
||||||
{
|
{
|
||||||
@ -483,39 +480,24 @@ readfile(const char *path)
|
|||||||
exit(1);
|
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)
|
|
||||||
{
|
|
||||||
linelen++;
|
|
||||||
if (c == '\n')
|
|
||||||
{
|
|
||||||
nlines++;
|
|
||||||
if (linelen > maxlength)
|
|
||||||
maxlength = linelen;
|
|
||||||
linelen = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 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;
|
n = 0;
|
||||||
while (fgets(buffer, maxlength + 1, infile) != NULL && n < nlines)
|
while ((ln = pg_get_line(infile)) != NULL)
|
||||||
result[n++] = pg_strdup(buffer);
|
{
|
||||||
|
/* make sure there will be room for a trailing NULL pointer */
|
||||||
|
if (n >= maxlines - 1)
|
||||||
|
{
|
||||||
|
maxlines *= 2;
|
||||||
|
result = (char **) pg_realloc(result, maxlines * sizeof(char *));
|
||||||
|
}
|
||||||
|
|
||||||
|
result[n++] = ln;
|
||||||
|
}
|
||||||
|
result[n] = NULL;
|
||||||
|
|
||||||
fclose(infile);
|
fclose(infile);
|
||||||
free(buffer);
|
|
||||||
result[n] = NULL;
|
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user