Hi,

On 2022-02-19 20:46:26 -0500, Tom Lane wrote:
> I tried it like that (full patch attached) and the results are intensely
> disappointing.  On my Mac laptop, the time needed for 50 iterations of
> initdb drops from 16.8 sec to 16.75 sec.

Hm. I'd hoped for at least a little bit bigger win. But I think it enables
more, see below:


> Not sure that this is worth pursuing any further.

I experimented with moving all the bootstrapping into --boot mode and got it
working. Albeit definitely with a few hacks (more below).

While I had hoped for a bit more of a win, it's IMO a nice improvement.
Executing 10 initdb -N --wal-segsize 1 in a loop:

HEAD:

  assert:
  8.06user 1.17system 0:09.25elapsed 99%CPU (0avgtext+0avgdata 
91724maxresident)k
  0inputs+549280outputs (40major+99824minor)pagefaults 0swaps

  opt:
  2.89user 0.99system 0:04.81elapsed 80%CPU (0avgtext+0avgdata 
88864maxresident)k
  0inputs+549280outputs (40major+99792minor)pagefaults 0swaps


default to lz4:

  assert:
  7.61user 1.03system 0:08.69elapsed 99%CPU (0avgtext+0avgdata 
91508maxresident)k
  0inputs+546400outputs (42major+99551minor)pagefaults 0swaps

  opt:
  2.55user 0.94system 0:03.49elapsed 99%CPU (0avgtext+0avgdata 
88816maxresident)k
  0inputs+546400outputs (40major+99551minor)pagefaults 0swaps


bootstrap replace:

  assert:
  7.42user 1.00system 0:08.52elapsed 98%CPU (0avgtext+0avgdata 
91656maxresident)k
  0inputs+546400outputs (40major+97737minor)pagefaults 0swaps

  opt:
  2.49user 0.98system 0:03.49elapsed 99%CPU (0avgtext+0avgdata 
88700maxresident)k
  0inputs+546400outputs (40major+97728minor)pagefaults 0swaps


everything in bootstrap:

  assert:
  6.31user 0.94system 0:07.35elapsed 98%CPU (0avgtext+0avgdata 
97812maxresident)k
  0inputs+547360outputs (30major+88617minor)pagefaults 0swaps

  opt:
  2.42user 0.85system 0:03.28elapsed 99%CPU (0avgtext+0avgdata 
94572maxresident)k
  0inputs+547360outputs (30major+83712minor)pagefaults 0swaps


optimize WAL in bootstrap:
  assert:
  6.26user 0.96system 0:07.29elapsed 99%CPU (0avgtext+0avgdata 
97844maxresident)k
  0inputs+547360outputs (30major+88586minor)pagefaults 0swaps

  opt:
  2.43user 0.80system 0:03.24elapsed 99%CPU (0avgtext+0avgdata 
94436maxresident)k
  0inputs+547360outputs (30major+83664minor)pagefaults 0swaps


remote isatty in bootstrap:

  assert:
  6.15user 0.83system 0:06.99elapsed 99%CPU (0avgtext+0avgdata 
97832maxresident)k
  0inputs+465120outputs (30major+88559minor)pagefaults 0swaps

  opt:
  2.28user 0.85system 0:03.14elapsed 99%CPU (0avgtext+0avgdata 
94604maxresident)k
  0inputs+465120outputs (30major+83728minor)pagefaults 0swaps


That's IMO not bad.

On windows I see a higher gains, which makes sense, because filesystem IO is
slower. Freebsd as well, but the variance is oddly high, so I might be doing
something wrong.


The main reason I like this however isn't the speedup itself, but that after
this initdb doesn't depend on single user mode at all anymore.


About the prototype:

- Most of the bootstrap SQL is executed from bootstrap.c itself. But some
  still comes from the client. E.g. password, a few information_schema
  details and the database / authid changes.

- To execute the sql I mostly used extension.c's
  read_whole_file()/execute_sql_string(). But VACUUM, CREATE DATABASE require
  all the transactional hacks in portal.c etc. So I wrapped
  exec_simple_query() for that phase.

  Might be better to just call vacuum.c / database.c directly.

- for indexed relcache access to work the phase of
  RelationCacheInitializePhase3() that's initially skipped needs to be
  executed. I hacked that up by adding a RelationCacheInitializePhase3b() that
  bootstrap.c can call, but that's obviously too ugly to live.

- InvalidateSystemCaches() is needed after bki processing. Otherwise I see an
  "row is too big:" error. Didn't investigate yet.

- I definitely removed some validation that we'd probably want. But that seems
  something to care about later...

- 0004 prevents a fair bit of WAL from being written. While XLogInsert did
  some of that, it didn't block FPIs, which obviously are bulky. This reduces
  WAL from ~5MB to ~100kB.


There's quite a bit of further speedup potential:

- One bottleneck, particularly in optimized mode, is the handling of huge node
  trees for views. strToNode() and nodeRead() are > 10% alone

- Enabling index access sometime during the postgres.bki processing would make
  invalidation handling for subsequent indexes faster. Or maybe we can disable
  a few more invalidations. Inval processing is >10%

- more than 10% (assert) / 7% (optimized) is spent in
  compute_scalar_stats()->qsort_arg(). Something seems off with that to me.


Completely crazy?


Greetings,

Andres Freund
>From 45d63168ddeb8bdf3ed29ca150f453ffcd051697 Mon Sep 17 00:00:00 2001
From: Andres Freund <and...@anarazel.de>
Date: Sun, 20 Feb 2022 12:20:42 -0800
Subject: [PATCH v1 1/5] Set default_toast_compression=lz4 if available.

Makes initdb faster, generally a good idea, users shouldn't have to bother
with this.

Author: Justin Pryzby <pryz...@telsasoft.com>
Discussion: https://postgr.es/m/20220216212952.gh31...@telsasoft.com
---
 src/backend/utils/misc/guc.c | 4 ++++
 src/bin/initdb/initdb.c      | 6 ++++++
 doc/src/sgml/config.sgml     | 4 +++-
 3 files changed, 13 insertions(+), 1 deletion(-)

diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c
index 01f373815e0..f502f9840f5 100644
--- a/src/backend/utils/misc/guc.c
+++ b/src/backend/utils/misc/guc.c
@@ -4727,7 +4727,11 @@ static struct config_enum ConfigureNamesEnum[] =
 			NULL
 		},
 		&default_toast_compression,
+#ifdef USE_LZ4
+		TOAST_LZ4_COMPRESSION,
+#else
 		TOAST_PGLZ_COMPRESSION,
+#endif
 		default_toast_compression_options,
 		NULL, NULL, NULL
 	},
diff --git a/src/bin/initdb/initdb.c b/src/bin/initdb/initdb.c
index 97f15971e2b..73ccbf63207 100644
--- a/src/bin/initdb/initdb.c
+++ b/src/bin/initdb/initdb.c
@@ -1185,6 +1185,12 @@ setup_config(void)
 							  "#update_process_title = off");
 #endif
 
+#ifdef USE_LZ4
+	conflines = replace_token(conflines,
+							  "#default_toast_compression = 'pglz'",
+							  "#default_toast_compression = 'lz4'");
+#endif
+
 	/*
 	 * Change password_encryption setting to md5 if md5 was chosen as an
 	 * authentication method, unless scram-sha-256 was also chosen.
diff --git a/doc/src/sgml/config.sgml b/doc/src/sgml/config.sgml
index d99bf38e677..97e78506b13 100644
--- a/doc/src/sgml/config.sgml
+++ b/doc/src/sgml/config.sgml
@@ -8536,7 +8536,9 @@ COPY postgres_log FROM '/full/path/to/logfile.csv' WITH csv;
         The supported compression methods are <literal>pglz</literal> and
         (if <productname>PostgreSQL</productname> was compiled with
         <option>--with-lz4</option>) <literal>lz4</literal>.
-        The default is <literal>pglz</literal>.
+        The default is <literal>lz4</literal> if available at the time 
+        <productname>PostgreSQL</productname> was compiled, otherwise
+        <literal>pglz</literal>.
        </para>
       </listitem>
      </varlistentry>
-- 
2.34.0

>From f3ea20b09c3e66c3c3e86e729e1920ac26ffd706 Mon Sep 17 00:00:00 2001
From: Andres Freund <and...@anarazel.de>
Date: Sat, 19 Feb 2022 17:33:34 -0800
Subject: [PATCH v1 2/5] initdb: move token replacing in postgres.bki to
 backend.

Author: Tom Lane
---
 src/include/catalog/pg_database.dat |   9 ++-
 src/backend/bootstrap/bootstrap.c   |  17 +++++
 src/bin/initdb/initdb.c             | 110 +++++++++++++---------------
 3 files changed, 72 insertions(+), 64 deletions(-)

diff --git a/src/include/catalog/pg_database.dat b/src/include/catalog/pg_database.dat
index e7e42d60234..c92cdde2600 100644
--- a/src/include/catalog/pg_database.dat
+++ b/src/include/catalog/pg_database.dat
@@ -12,11 +12,14 @@
 
 [
 
+# We initialize template1's encoding as PG_SQL_ASCII and its locales as C.
+# initdb will change that during database initialization.
+
 { oid => '1', oid_symbol => 'TemplateDbOid',
   descr => 'default template for new databases',
-  datname => 'template1', encoding => 'ENCODING', datistemplate => 't',
+  datname => 'template1', encoding => '0', datistemplate => 't',
   datallowconn => 't', datconnlimit => '-1', datfrozenxid => '0',
-  datminmxid => '1', dattablespace => 'pg_default', datcollate => 'LC_COLLATE',
-  datctype => 'LC_CTYPE', datacl => '_null_' },
+  datminmxid => '1', dattablespace => 'pg_default', datcollate => 'C',
+  datctype => 'C', datacl => '_null_' },
 
 ]
diff --git a/src/backend/bootstrap/bootstrap.c b/src/backend/bootstrap/bootstrap.c
index 9fa8fdd4cf3..667c829064d 100644
--- a/src/backend/bootstrap/bootstrap.c
+++ b/src/backend/bootstrap/bootstrap.c
@@ -635,6 +635,8 @@ InsertOneTuple(void)
 
 /* ----------------
  *		InsertOneValue
+ *
+ * Fill the i'th column of the current tuple with the given value.
  * ----------------
  */
 void
@@ -653,6 +655,21 @@ InsertOneValue(char *value, int i)
 
 	elog(DEBUG4, "inserting column %d value \"%s\"", i, value);
 
+	/*
+	 * In order to make the contents of postgres.bki architecture-independent,
+	 * certain values in it are represented symbolically, and we perform the
+	 * necessary replacements here.
+	 */
+	if (strcmp(value, "NAMEDATALEN") == 0)
+		value = CppAsString2(NAMEDATALEN);
+	else if (strcmp(value, "SIZEOF_POINTER") == 0)
+		value = CppAsString2(SIZEOF_VOID_P);
+	else if (strcmp(value, "ALIGNOF_POINTER") == 0)
+		value = (SIZEOF_VOID_P == 4) ? "i" : "d";
+	else if (strcmp(value, "FLOAT8PASSBYVAL") == 0)
+		value = FLOAT8PASSBYVAL ? "true" : "false";
+
+	/* Now convert the value to internal form */
 	typoid = TupleDescAttr(boot_reldesc->rd_att, i)->atttypid;
 
 	boot_get_type_io_data(typoid,
diff --git a/src/bin/initdb/initdb.c b/src/bin/initdb/initdb.c
index 73ccbf63207..37ac928b2ef 100644
--- a/src/bin/initdb/initdb.c
+++ b/src/bin/initdb/initdb.c
@@ -265,13 +265,13 @@ static void setup_privileges(FILE *cmdfd);
 static void set_info_version(void);
 static void setup_schema(FILE *cmdfd);
 static void load_plpgsql(FILE *cmdfd);
+static void set_remaining_details(FILE *cmdfd);
 static void vacuum_db(FILE *cmdfd);
 static void make_template0(FILE *cmdfd);
 static void make_postgres(FILE *cmdfd);
 static void trapsig(int signum);
 static void check_ok(void);
 static char *escape_quotes(const char *src);
-static char *escape_quotes_bki(const char *src);
 static int	locale_date_order(const char *locale);
 static void check_locale_name(int category, const char *locale,
 							  char **canonname);
@@ -336,32 +336,6 @@ escape_quotes(const char *src)
 	return result;
 }
 
-/*
- * Escape a field value to be inserted into the BKI data.
- * Run the value through escape_quotes (which will be inverted
- * by the backend's DeescapeQuotedString() function), then wrap
- * the value in single quotes, even if that isn't strictly necessary.
- */
-static char *
-escape_quotes_bki(const char *src)
-{
-	char	   *result;
-	char	   *data = escape_quotes(src);
-	char	   *resultp;
-	char	   *datap;
-
-	result = (char *) pg_malloc(strlen(data) + 3);
-	resultp = result;
-	*resultp++ = '\'';
-	for (datap = data; *datap; datap++)
-		*resultp++ = *datap;
-	*resultp++ = '\'';
-	*resultp = '\0';
-
-	free(data);
-	return result;
-}
-
 /*
  * make a copy of the array of lines, with token replaced by replacement
  * the first time it occurs on each line.
@@ -1363,7 +1337,6 @@ bootstrap_template1(void)
 	char	  **line;
 	char	  **bki_lines;
 	char		headerline[MAXPGPATH];
-	char		buf[64];
 
 	printf(_("running bootstrap script ... "));
 	fflush(stdout);
@@ -1385,32 +1358,6 @@ bootstrap_template1(void)
 		exit(1);
 	}
 
-	/* Substitute for various symbols used in the BKI file */
-
-	sprintf(buf, "%d", NAMEDATALEN);
-	bki_lines = replace_token(bki_lines, "NAMEDATALEN", buf);
-
-	sprintf(buf, "%d", (int) sizeof(Pointer));
-	bki_lines = replace_token(bki_lines, "SIZEOF_POINTER", buf);
-
-	bki_lines = replace_token(bki_lines, "ALIGNOF_POINTER",
-							  (sizeof(Pointer) == 4) ? "i" : "d");
-
-	bki_lines = replace_token(bki_lines, "FLOAT8PASSBYVAL",
-							  FLOAT8PASSBYVAL ? "true" : "false");
-
-	bki_lines = replace_token(bki_lines, "POSTGRES",
-							  escape_quotes_bki(username));
-
-	bki_lines = replace_token(bki_lines, "ENCODING",
-							  encodingid_to_string(encodingid));
-
-	bki_lines = replace_token(bki_lines, "LC_COLLATE",
-							  escape_quotes_bki(lc_collate));
-
-	bki_lines = replace_token(bki_lines, "LC_CTYPE",
-							  escape_quotes_bki(lc_ctype));
-
 	/* Also ensure backend isn't confused by this environment var: */
 	unsetenv("PGCLIENTENCODING");
 
@@ -1628,12 +1575,11 @@ setup_collation(FILE *cmdfd)
 static void
 setup_privileges(FILE *cmdfd)
 {
-	char	  **line;
-	char	  **priv_lines;
-	static char *privileges_setup[] = {
+	const char *const *line;
+	static const char *const privileges_setup[] = {
 		"UPDATE pg_class "
 		"  SET relacl = (SELECT array_agg(a.acl) FROM "
-		" (SELECT E'=r/\"$POSTGRES_SUPERUSERNAME\"' as acl "
+		" (SELECT '=r/\"POSTGRES\"' as acl "
 		"  UNION SELECT unnest(pg_catalog.acldefault("
 		"    CASE WHEN relkind = " CppAsString2(RELKIND_SEQUENCE) " THEN 's' "
 		"         ELSE 'r' END::\"char\"," CppAsString2(BOOTSTRAP_SUPERUSERID) "::oid))"
@@ -1765,9 +1711,7 @@ setup_privileges(FILE *cmdfd)
 		NULL
 	};
 
-	priv_lines = replace_token(privileges_setup, "$POSTGRES_SUPERUSERNAME",
-							   escape_quotes(username));
-	for (line = priv_lines; *line != NULL; line++)
+	for (line = privileges_setup; *line != NULL; line++)
 		PG_CMD_PUTS(*line);
 }
 
@@ -1828,6 +1772,48 @@ load_plpgsql(FILE *cmdfd)
 	PG_CMD_PUTS("CREATE EXTENSION plpgsql;\n\n");
 }
 
+/*
+ * Set some remaining details that aren't known when postgres.bki is made.
+ *
+ * Up to now, the bootstrap superuser has been named "POSTGRES".
+ * Replace that with the user-specified name (often "postgres").
+ * Also, insert the desired locale and encoding details in pg_database.
+ *
+ * Note: this must run after setup_privileges(), which expects the superuser
+ * name to still be "POSTGRES".
+ */
+static void
+set_remaining_details(FILE *cmdfd)
+{
+	char	  **line;
+	char	  **detail_lines;
+
+	/*
+	 * Ideally we'd change the superuser name with ALTER USER, but the backend
+	 * will reject that with "session user cannot be renamed", so we must
+	 * cheat.  (In any case, we'd need a function to escape an identifier, not
+	 * a string literal.)  Likewise, we can't change template1's
+	 * locale/encoding without cheating.
+	 */
+	static char *final_details[] = {
+		"UPDATE pg_authid SET rolname = E'SUPERUSER_NAME' WHERE rolname = 'POSTGRES';\n\n",
+		"UPDATE pg_database SET encoding = E'ENCODING', datcollate = E'LC_COLLATE', datctype = E'LC_CTYPE';\n\n",
+		NULL
+	};
+
+	detail_lines = replace_token(final_details, "SUPERUSER_NAME",
+								 escape_quotes(username));
+	detail_lines = replace_token(detail_lines, "ENCODING",
+								 encodingid_to_string(encodingid));
+	detail_lines = replace_token(detail_lines, "LC_COLLATE",
+								 escape_quotes(lc_collate));
+	detail_lines = replace_token(detail_lines, "LC_CTYPE",
+								 escape_quotes(lc_ctype));
+
+	for (line = detail_lines; *line != NULL; line++)
+		PG_CMD_PUTS(*line);
+}
+
 /*
  * clean everything up in template1
  */
@@ -2857,6 +2843,8 @@ initialize_data_directory(void)
 
 	load_plpgsql(cmdfd);
 
+	set_remaining_details(cmdfd);
+
 	vacuum_db(cmdfd);
 
 	make_template0(cmdfd);
-- 
2.34.0

>From ed39cf53788242d6b6990497ae86250dd658d26c Mon Sep 17 00:00:00 2001
From: Andres Freund <and...@anarazel.de>
Date: Sun, 20 Feb 2022 11:03:20 -0800
Subject: [PATCH v1 3/5] initdb: perform everything during --boot, mostly in
 backend.

Author:
Reviewed-By:
Discussion: https://postgr.es/m/
Backpatch:
---
 src/include/bootstrap/bootstrap.h   |   1 +
 src/include/commands/extension.h    |   2 +
 src/include/tcop/tcopprot.h         |   1 +
 src/include/utils/relcache.h        |   1 +
 src/backend/bootstrap/bootscanner.l |   6 +
 src/backend/bootstrap/bootstrap.c   | 306 +++++++++++++++-
 src/backend/catalog/Makefile        |   2 +
 src/backend/catalog/description.sql |  16 +
 src/backend/catalog/privileges.sql  | 154 ++++++++
 src/backend/commands/extension.c    |   5 +-
 src/backend/main/main.c             |   1 +
 src/backend/tcop/postgres.c         |  12 +
 src/backend/utils/cache/relcache.c  |  11 +-
 src/bin/initdb/initdb.c             | 532 ++--------------------------
 14 files changed, 535 insertions(+), 515 deletions(-)
 create mode 100644 src/backend/catalog/description.sql
 create mode 100644 src/backend/catalog/privileges.sql

diff --git a/src/include/bootstrap/bootstrap.h b/src/include/bootstrap/bootstrap.h
index 471414909f3..f94e9339373 100644
--- a/src/include/bootstrap/bootstrap.h
+++ b/src/include/bootstrap/bootstrap.h
@@ -54,6 +54,7 @@ extern void boot_get_type_io_data(Oid typid,
 								  Oid *typinput,
 								  Oid *typoutput);
 
+extern void boot_input(FILE *file);
 extern int	boot_yyparse(void);
 
 extern int	boot_yylex(void);
diff --git a/src/include/commands/extension.h b/src/include/commands/extension.h
index e24e3759f0c..cd1668e5865 100644
--- a/src/include/commands/extension.h
+++ b/src/include/commands/extension.h
@@ -48,6 +48,8 @@ extern ObjectAddress ExecAlterExtensionContentsStmt(AlterExtensionContentsStmt *
 extern Oid	get_extension_oid(const char *extname, bool missing_ok);
 extern char *get_extension_name(Oid ext_oid);
 extern bool extension_file_exists(const char *extensionName);
+extern void execute_sql_string(const char *sql);
+extern char *read_whole_file(const char *filename, int *length);
 
 extern ObjectAddress AlterExtensionNamespace(const char *extensionName, const char *newschema,
 											 Oid *oldschema);
diff --git a/src/include/tcop/tcopprot.h b/src/include/tcop/tcopprot.h
index 15a11bc3ff1..47c8ff283e4 100644
--- a/src/include/tcop/tcopprot.h
+++ b/src/include/tcop/tcopprot.h
@@ -60,6 +60,7 @@ extern PlannedStmt *pg_plan_query(Query *querytree, const char *query_string,
 extern List *pg_plan_queries(List *querytrees, const char *query_string,
 							 int cursorOptions,
 							 ParamListInfo boundParams);
+extern void exec_simple_query_bootstrap(const char *query_string);
 
 extern bool check_max_stack_depth(int *newval, void **extra, GucSource source);
 extern void assign_max_stack_depth(int newval, void *extra);
diff --git a/src/include/utils/relcache.h b/src/include/utils/relcache.h
index 84d6afef19b..e400146f648 100644
--- a/src/include/utils/relcache.h
+++ b/src/include/utils/relcache.h
@@ -93,6 +93,7 @@ extern int	errtableconstraint(Relation rel, const char *conname);
 extern void RelationCacheInitialize(void);
 extern void RelationCacheInitializePhase2(void);
 extern void RelationCacheInitializePhase3(void);
+extern void RelationCacheInitializePhase3b(bool needNewCacheFile);
 
 /*
  * Routine to create a relcache entry for an about-to-be-created relation
diff --git a/src/backend/bootstrap/bootscanner.l b/src/backend/bootstrap/bootscanner.l
index 3094ccb93f4..72c3f40a88f 100644
--- a/src/backend/bootstrap/bootscanner.l
+++ b/src/backend/bootstrap/bootscanner.l
@@ -125,3 +125,9 @@ yyerror(const char *message)
 {
 	elog(ERROR, "%s at line %d", message, yyline);
 }
+
+void
+boot_input(FILE *file)
+{
+	yyin = file;
+}
diff --git a/src/backend/bootstrap/bootstrap.c b/src/backend/bootstrap/bootstrap.c
index 667c829064d..3fd8ed60715 100644
--- a/src/backend/bootstrap/bootstrap.c
+++ b/src/backend/bootstrap/bootstrap.c
@@ -2,7 +2,10 @@
  *
  * bootstrap.c
  *	  routines to support running postgres in 'bootstrap' mode
- *	bootstrap mode is used to create the initial template database
+ *
+ * bootstrap mode is used to create the initial template1 database, perform
+ * additional initialization it via SQL scripts, and then create template0,
+ * postgres from template1.
  *
  * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
@@ -26,10 +29,14 @@
 #include "access/xlog_internal.h"
 #include "bootstrap/bootstrap.h"
 #include "catalog/index.h"
+#include "catalog/pg_authid_d.h"
 #include "catalog/pg_collation.h"
 #include "catalog/pg_type.h"
+#include "commands/extension.h"
 #include "common/link-canary.h"
+#include "common/string.h"
 #include "libpq/pqsignal.h"
+#include "mb/pg_wchar.h"
 #include "miscadmin.h"
 #include "nodes/makefuncs.h"
 #include "pg_getopt.h"
@@ -41,6 +48,7 @@
 #include "tcop/tcopprot.h"
 #include "utils/builtins.h"
 #include "utils/fmgroids.h"
+#include "utils/inval.h"
 #include "utils/memutils.h"
 #include "utils/rel.h"
 #include "utils/relmapper.h"
@@ -55,6 +63,12 @@ static void populate_typ_list(void);
 static Oid	gettype(char *type);
 static void cleanup(void);
 
+static void bootstrap_load_nonbki(const char *share_path);
+static void bootstrap_create_databases(void);
+
+static void exec_sql(const char *share_path, const char *str);
+static void exec_sql_file(const char *share_path, const char *str);
+
 /* ----------------
  *		global variables
  * ----------------
@@ -206,6 +220,7 @@ BootstrapModeMain(int argc, char *argv[], bool check_only)
 	char	   *progname = argv[0];
 	int			flag;
 	char	   *userDoption = NULL;
+	char	   *share_path = NULL;
 
 	Assert(!IsUnderPostmaster);
 
@@ -221,7 +236,12 @@ BootstrapModeMain(int argc, char *argv[], bool check_only)
 	argv++;
 	argc--;
 
-	while ((flag = getopt(argc, argv, "B:c:d:D:Fkr:X:-:")) != -1)
+	/*
+	 * XXX: -s for share_path is probably a bad choice, it conflicts with a
+	 * normal postgres option. Also, should probably just determine share path
+	 * ourselves.
+	 */
+	while ((flag = getopt(argc, argv, "B:c:d:D:s:Fkr:X:-:")) != -1)
 	{
 		switch (flag)
 		{
@@ -247,6 +267,9 @@ BootstrapModeMain(int argc, char *argv[], bool check_only)
 			case 'F':
 				SetConfigOption("fsync", "false", PGC_POSTMASTER, PGC_S_ARGV);
 				break;
+			case 's':
+			    share_path = optarg;
+				break;
 			case 'k':
 				bootstrap_data_checksum_version = PG_DATA_CHECKSUM_VERSION;
 				break;
@@ -338,6 +361,12 @@ BootstrapModeMain(int argc, char *argv[], bool check_only)
 		abort();
 	}
 
+	if (share_path == NULL)
+	{
+		write_stderr("%s: -s is required in --boot mode\n", progname);
+		proc_exit(1);
+	}
+
 	/*
 	 * Do backend-like initialization for bootstrap mode
 	 */
@@ -365,11 +394,34 @@ BootstrapModeMain(int argc, char *argv[], bool check_only)
 	}
 
 	/*
-	 * Process bootstrap input.
+	 * Process bootstrap file to create initial template1 contents.
 	 */
-	StartTransactionCommand();
-	boot_yyparse();
-	CommitTransactionCommand();
+	{
+		char bootstrap_file[MAXPGPATH];
+		FILE *boot;
+		instr_time start_ts, boot_ts;
+
+		INSTR_TIME_SET_CURRENT(start_ts);
+
+		sprintf(bootstrap_file, "%s/%s", share_path, "postgres.bki");
+
+		boot = fopen(bootstrap_file, "r");
+		if (boot == NULL)
+			elog(ERROR, "could not open bootstrap file \"%s\": %m",
+				 bootstrap_file);
+		boot_input(boot);
+
+		StartTransactionCommand();
+		boot_yyparse();
+		CommitTransactionCommand();
+
+		fclose(boot);
+
+		INSTR_TIME_SET_CURRENT(boot_ts);
+
+		elog(LOG, "boot in %.3f ms",
+			 (INSTR_TIME_GET_DOUBLE(boot_ts) - INSTR_TIME_GET_DOUBLE(start_ts)) * 1000);
+	}
 
 	/*
 	 * We should now know about all mapped relations, so it's okay to write
@@ -377,11 +429,251 @@ BootstrapModeMain(int argc, char *argv[], bool check_only)
 	 */
 	RelationMapFinishBootstrap();
 
-	/* Clean up and exit */
+	/* Clean up and exit FIXME */
 	cleanup();
+
+	/*
+	 * Now that the catalog is populated with crucial contents, bring up
+	 * system caches into a fully valid state.
+	 */
+
+	SetProcessingMode(InitProcessing);
+
+	IgnoreSystemIndexes = false;
+
+	StartTransactionCommand();
+	/* Seeing odd "row is too big:" failures without */
+	InvalidateSystemCaches();
+	/* FIXME: speechless-making API */
+	RelationCacheInitializePhase3b(true);
+	CommitTransactionCommand();
+
+	/*
+	 * Load further catalog contents by running a bunch of SQL commands.
+	 */
+	SetProcessingMode(NormalProcessing);
+
+	bootstrap_load_nonbki(share_path);
+
+	bootstrap_create_databases();
+
 	proc_exit(0);
 }
 
+/*
+ * Create template0 and postgres from template1.
+ *
+ * XXX: Several of the statements contain commands that cannot be executed in
+ * a transaction (VACUUM, CREATE DATABASE) and thus require a fairly
+ * complicated dance to maintain correct state. The easiest is to just rely on
+ * exec_simple_query() (via a wrapper) for that. Don't want to do that for
+ * everything else, because it's considerably faster to use exec_sql().
+ */
+static void
+bootstrap_create_databases(void)
+{
+	/*
+	 * pg_upgrade tries to preserve database OIDs across upgrades. It's smart
+	 * enough to drop and recreate a conflicting database with the same name,
+	 * but if the same OID were used for one system-created database in the
+	 * old cluster and a different system-created database in the new cluster,
+	 * it would fail. To avoid that, assign a fixed OID to template0 rather
+	 * than letting the server choose one.
+	 *
+	 * (Note that, while the user could have dropped and recreated these
+	 * objects in the old cluster, the problem scenario only exists if the OID
+	 * that is in use in the old cluster is also used in the new cluster - and
+	 * the new cluster should be the result of a fresh initdb.)
+	 */
+	static const char *const template0_setup[] = {
+		"CREATE DATABASE template0 IS_TEMPLATE = true ALLOW_CONNECTIONS = false OID = "
+		CppAsString2(Template0ObjectId) ";\n",
+
+		/*
+		 * template0 shouldn't have any collation-dependent objects, so unset
+		 * the collation version.  This disables collation version checks when
+		 * making a new database from it.
+		 */
+		"UPDATE pg_database SET datcollversion = NULL WHERE datname = 'template0';\n",
+
+		/*
+		 * While we are here, do set the collation version on template1.
+		 */
+		"UPDATE pg_database SET datcollversion = pg_database_collation_actual_version(oid) WHERE datname = 'template1';\n",
+
+		/*
+		 * Explicitly revoke public create-schema and create-temp-table
+		 * privileges in template1 and template0; else the latter would be on
+		 * by default
+		 */
+		"REVOKE CREATE,TEMPORARY ON DATABASE template1 FROM public;\n",
+		"REVOKE CREATE,TEMPORARY ON DATABASE template0 FROM public;\n",
+
+		"COMMENT ON DATABASE template0 IS 'unmodifiable empty database';\n",
+		NULL
+	};
+
+	/* Assign a fixed OID to postgres, for the same reasons as template0 */
+	static const char *const postgres_setup[] = {
+		"CREATE DATABASE postgres OID = " CppAsString2(PostgresObjectId) ";\n",
+		"COMMENT ON DATABASE postgres IS 'default administrative connection database';\n",
+		NULL
+	};
+	instr_time start_ts, created_ts;
+
+	INSTR_TIME_SET_CURRENT(start_ts);
+
+
+	MessageContext = AllocSetContextCreate(TopMemoryContext,
+										   "MessageContext",
+										   ALLOCSET_DEFAULT_SIZES);
+
+	/*
+	 * clean everything up in template1
+	 */
+	exec_simple_query_bootstrap("VACUUM FREEZE");
+
+	/*
+	 * copy template1 to template0
+	 */
+	for (const char *const *line = template0_setup; *line; line++)
+		exec_simple_query_bootstrap(*line);
+
+	/*
+	 * copy template1 to postgres
+	 */
+	for (const char *const *line = postgres_setup; *line; line++)
+		exec_simple_query_bootstrap(*line);
+
+	/*
+	 * Finally vacuum to clean up dead rows in pg_database
+	 */
+	exec_simple_query_bootstrap("VACUUM pg_database");
+
+	MemoryContextDelete(MessageContext);
+	MessageContext = NULL;
+
+	INSTR_TIME_SET_CURRENT(created_ts);
+
+	elog(LOG, "created template0 and postgres in %.3f ms",
+		 (INSTR_TIME_GET_DOUBLE(created_ts) - INSTR_TIME_GET_DOUBLE(start_ts)) * 1000);
+}
+
+static void
+bootstrap_load_nonbki(const char *share_path)
+{
+	StringInfoData sql;
+
+	initStringInfo(&sql);
+
+	StartTransactionCommand();
+	PushActiveSnapshot(GetTransactionSnapshot());
+
+	exec_sql_file(share_path, "system_constraints.sql");
+	exec_sql_file(share_path, "system_functions.sql");
+
+	/*
+	 * set up the shadow password table
+	 */
+	exec_sql("pg_authid", "REVOKE ALL ON pg_authid FROM public;");
+
+	/*
+	 * Advance the OID counter so that subsequently-created objects aren't
+	 * pinned. Subsequent objects are all droppable at the whim of the DBA.
+	 */
+	StopGeneratingPinnedObjectIds();
+
+	exec_sql_file(share_path, "system_views.sql");
+
+	exec_sql_file(share_path, "description.sql");
+
+	/* populate pg_collation */
+	{
+		/*
+		 * Add an SQL-standard name.  We don't want to pin this, so it doesn't go
+		 * in pg_collation.h.  But add it before reading system collations, so
+		 * that it wins if libc defines a locale named ucs_basic.
+		 */
+		appendStringInfo(&sql,
+						 "INSERT INTO pg_collation (oid, collname, "
+						 "    collnamespace, collowner, "
+						 "    collprovider, collisdeterministic, collencoding, "
+						 "    collcollate, collctype) "
+						 "VALUES ("
+						 "    pg_nextoid('pg_catalog.pg_collation', 'oid', "
+						 "        'pg_catalog.pg_collation_oid_index'), "
+						 "    'ucs_basic', 'pg_catalog'::regnamespace, %u, "
+						 "    '%c', true, %d, 'C', 'C');",
+						 BOOTSTRAP_SUPERUSERID, COLLPROVIDER_LIBC, PG_UTF8);
+		exec_sql("pg_collation", sql.data);
+		resetStringInfo(&sql);
+
+		/* Now import all collations we can find in the operating system */
+		exec_sql("import collations",
+				 "SELECT pg_import_system_collations('pg_catalog');");
+	}
+
+	exec_sql_file(share_path, "snowball_create.sql");
+
+	exec_sql_file(share_path, "privileges.sql");
+
+	exec_sql_file(share_path, "information_schema.sql");
+
+	exec_sql("plpgsql", "CREATE EXTENSION plpgsql;");
+
+	/*
+	 * Process SQL coming from initdb. This includes things like setting
+	 * up passwords, which would be a bit of pain to move to the backend.
+	 */
+	while (true)
+	{
+		if (!pg_get_line_buf(stdin, &sql))
+			break;
+
+		/* XXX: better descriptor than more */
+		exec_sql("more", sql.data);
+		resetStringInfo(&sql);
+	}
+
+	/* Run analyze before VACUUM so the statistics are frozen. */
+	exec_sql("analyze", "ANALYZE");
+
+	PopActiveSnapshot();
+	CommitTransactionCommand();
+}
+
+static void
+exec_sql(const char *name, const char *sql)
+{
+	instr_time start_ts, exec_ts;
+
+	INSTR_TIME_SET_CURRENT(start_ts);
+
+	execute_sql_string(sql);
+
+	INSTR_TIME_SET_CURRENT(exec_ts);
+
+	elog(LOG, "exec %s in %.3f ms",
+		 name,
+		 (INSTR_TIME_GET_DOUBLE(exec_ts) - INSTR_TIME_GET_DOUBLE(start_ts)) * 1000);
+}
+
+static void
+exec_sql_file(const char *share_path, const char *filename)
+{
+	int length;
+	char *str;
+	char filepath[MAXPGPATH];
+
+	sprintf(filepath, "%s/%s", share_path, filename);
+
+	str = read_whole_file(filepath, &length);
+
+	exec_sql(filename, str);
+
+	pfree(str);
+}
+
 
 /* ----------------------------------------------------------------
  *						misc functions
diff --git a/src/backend/catalog/Makefile b/src/backend/catalog/Makefile
index eefebb7bb83..d014e52968a 100644
--- a/src/backend/catalog/Makefile
+++ b/src/backend/catalog/Makefile
@@ -125,6 +125,8 @@ install-data: bki-stamp installdirs
 	$(INSTALL_DATA) $(call vpathsearch,system_constraints.sql) '$(DESTDIR)$(datadir)/system_constraints.sql'
 	$(INSTALL_DATA) $(srcdir)/system_functions.sql '$(DESTDIR)$(datadir)/system_functions.sql'
 	$(INSTALL_DATA) $(srcdir)/system_views.sql '$(DESTDIR)$(datadir)/system_views.sql'
+	$(INSTALL_DATA) $(srcdir)/description.sql '$(DESTDIR)$(datadir)/description.sql'
+	$(INSTALL_DATA) $(srcdir)/privileges.sql '$(DESTDIR)$(datadir)/privileges.sql'
 	$(INSTALL_DATA) $(srcdir)/information_schema.sql '$(DESTDIR)$(datadir)/information_schema.sql'
 	$(INSTALL_DATA) $(srcdir)/sql_features.txt '$(DESTDIR)$(datadir)/sql_features.txt'
 
diff --git a/src/backend/catalog/description.sql b/src/backend/catalog/description.sql
new file mode 100644
index 00000000000..b46a3094452
--- /dev/null
+++ b/src/backend/catalog/description.sql
@@ -0,0 +1,16 @@
+/* Create default descriptions for operator implementation functions */
+WITH funcdescs AS (
+    SELECT p.oid as p_oid, o.oid as o_oid, oprname
+    FROM pg_proc p  JOIN pg_operator o ON oprcode = p.oid
+)
+INSERT INTO pg_description
+    SELECT p_oid, 'pg_proc'::regclass, 0,
+        'implementation of ' || oprname || ' operator'
+    FROM funcdescs
+    WHERE NOT EXISTS (
+           SELECT 1 FROM pg_description
+           WHERE objoid = p_oid AND classoid = 'pg_proc'::regclass)
+        AND NOT EXISTS (
+	    SELECT 1 FROM pg_description
+            WHERE objoid = o_oid AND classoid = 'pg_operator'::regclass
+                AND description LIKE 'deprecated%');
diff --git a/src/backend/catalog/privileges.sql b/src/backend/catalog/privileges.sql
new file mode 100644
index 00000000000..3843c970df5
--- /dev/null
+++ b/src/backend/catalog/privileges.sql
@@ -0,0 +1,154 @@
+/*
+ * Set up privileges
+ *
+ * We mark most system catalogs as world-readable.  We don't currently have
+ * to touch functions, languages, or databases, because their default
+ * permissions are OK.
+ *
+ * Some objects may require different permissions by default, so we
+ * make sure we don't overwrite privilege sets that have already been
+ * set (NOT NULL).
+ *
+ * Also populate pg_init_privs to save what the privileges are at init
+ * time.  This is used by pg_dump to allow users to change privileges
+ * on catalog objects and to have those privilege changes preserved
+ * across dump/reload and pg_upgrade.
+ *
+ * Note that pg_init_privs is only for per-database objects and therefore
+ * we don't include databases or tablespaces.
+ */
+
+UPDATE pg_class
+  SET relacl = (SELECT array_agg(a.acl) FROM
+ (SELECT '=r/"POSTGRES"' as acl
+  UNION SELECT unnest(pg_catalog.acldefault(
+    CASE WHEN relkind = 'S' THEN 's'
+         ELSE 'r' END::"char", 10::oid)) -- FIXME, inlined BOOTSTRAP_SUPERUSERID
+ ) as a)
+  WHERE relkind IN ('r', 'v', 'm','S')
+  AND relacl IS NULL;
+
+GRANT USAGE ON SCHEMA pg_catalog, public TO PUBLIC;
+REVOKE ALL ON pg_largeobject FROM PUBLIC;
+INSERT INTO pg_init_privs
+  (objoid, classoid, objsubid, initprivs, privtype)
+    SELECT
+        oid,
+        (SELECT oid FROM pg_class WHERE relname = 'pg_class'),
+        0,
+        relacl,
+        'i'
+    FROM
+        pg_class
+    WHERE
+        relacl IS NOT NULL
+        AND relkind IN ('r', 'v', 'm','S');
+
+INSERT INTO pg_init_privs
+  (objoid, classoid, objsubid, initprivs, privtype)
+    SELECT
+        pg_class.oid,
+        (SELECT oid FROM pg_class WHERE relname = 'pg_class'),
+        pg_attribute.attnum,
+        pg_attribute.attacl,
+        'i'
+    FROM
+        pg_class
+        JOIN pg_attribute ON (pg_class.oid = pg_attribute.attrelid)
+    WHERE
+        pg_attribute.attacl IS NOT NULL
+        AND pg_class.relkind IN ('r', 'v', 'm', 'S');
+
+INSERT INTO pg_init_privs
+  (objoid, classoid, objsubid, initprivs, privtype)
+    SELECT
+        oid,
+        (SELECT oid FROM pg_class WHERE relname = 'pg_proc'),
+        0,
+        proacl,
+        'i'
+    FROM
+        pg_proc
+    WHERE
+        proacl IS NOT NULL;
+
+INSERT INTO pg_init_privs
+  (objoid, classoid, objsubid, initprivs, privtype)
+    SELECT
+        oid,
+        (SELECT oid FROM pg_class WHERE relname = 'pg_type'),
+        0,
+        typacl,
+        'i'
+    FROM
+        pg_type
+    WHERE
+        typacl IS NOT NULL;
+
+INSERT INTO pg_init_privs
+  (objoid, classoid, objsubid, initprivs, privtype)
+    SELECT
+        oid,
+        (SELECT oid FROM pg_class WHERE relname = 'pg_language'),
+        0,
+        lanacl,
+        'i'
+    FROM
+        pg_language
+    WHERE
+        lanacl IS NOT NULL;
+
+INSERT INTO pg_init_privs
+  (objoid, classoid, objsubid, initprivs, privtype)
+    SELECT
+        oid,
+        (SELECT oid FROM pg_class WHERE
+         relname = 'pg_largeobject_metadata'),
+        0,
+        lomacl,
+        'i'
+    FROM
+        pg_largeobject_metadata
+    WHERE
+        lomacl IS NOT NULL;
+
+INSERT INTO pg_init_privs
+  (objoid, classoid, objsubid, initprivs, privtype)
+    SELECT
+        oid,
+        (SELECT oid FROM pg_class WHERE relname = 'pg_namespace'),
+        0,
+        nspacl,
+        'i'
+    FROM
+        pg_namespace
+    WHERE
+        nspacl IS NOT NULL;
+
+INSERT INTO pg_init_privs
+  (objoid, classoid, objsubid, initprivs, privtype)
+    SELECT
+        oid,
+        (SELECT oid FROM pg_class WHERE
+         relname = 'pg_foreign_data_wrapper'),
+        0,
+        fdwacl,
+        'i'
+    FROM
+        pg_foreign_data_wrapper
+    WHERE
+        fdwacl IS NOT NULL;
+
+INSERT INTO pg_init_privs
+  (objoid, classoid, objsubid, initprivs, privtype)
+    SELECT
+        oid,
+        (SELECT oid FROM pg_class
+         WHERE relname = 'pg_foreign_server'),
+        0,
+        srvacl,
+        'i'
+    FROM
+        pg_foreign_server
+    WHERE
+        srvacl IS NOT NULL;
diff --git a/src/backend/commands/extension.c b/src/backend/commands/extension.c
index 0e04304cb09..c46e607bccb 100644
--- a/src/backend/commands/extension.c
+++ b/src/backend/commands/extension.c
@@ -127,7 +127,6 @@ static void ApplyExtensionUpdates(Oid extensionOid,
 								  char *origSchemaName,
 								  bool cascade,
 								  bool is_create);
-static char *read_whole_file(const char *filename, int *length);
 
 
 /*
@@ -716,7 +715,7 @@ read_extension_script_file(const ExtensionControlFile *control,
  * on printing the whole string as errcontext in case of any error, and that
  * could be very long.
  */
-static void
+void
 execute_sql_string(const char *sql)
 {
 	List	   *raw_parsetree_list;
@@ -3429,7 +3428,7 @@ ExecAlterExtensionContentsStmt(AlterExtensionContentsStmt *stmt,
  * The file contents are returned as a single palloc'd chunk. For convenience
  * of the callers, an extra \0 byte is added to the end.
  */
-static char *
+char *
 read_whole_file(const char *filename, int *length)
 {
 	char	   *buf;
diff --git a/src/backend/main/main.c b/src/backend/main/main.c
index 3d67ce9dcea..3b28f9c57d0 100644
--- a/src/backend/main/main.c
+++ b/src/backend/main/main.c
@@ -394,6 +394,7 @@ help(const char *progname)
 	printf(_("  --check            selects check mode (must be first argument)\n"));
 	printf(_("  DBNAME             database name (mandatory argument in bootstrapping mode)\n"));
 	printf(_("  -r FILENAME        send stdout and stderr to given file\n"));
+	printf(_("  -s SHAREPATH       path to share directory\n"));
 
 	printf(_("\nPlease read the documentation for the complete list of run-time\n"
 			 "configuration settings and how to set them on the command line or in\n"
diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c
index 3c7d08209f3..1e48645a748 100644
--- a/src/backend/tcop/postgres.c
+++ b/src/backend/tcop/postgres.c
@@ -1314,6 +1314,18 @@ exec_simple_query(const char *query_string)
 	debug_query_string = NULL;
 }
 
+/* just for bootstrap */
+void
+exec_simple_query_bootstrap(const char *query_string)
+{
+	MemoryContextSwitchTo(MessageContext);
+	SetCurrentStatementStartTimestamp();
+
+	exec_simple_query(query_string);
+
+	MemoryContextReset(MessageContext);
+}
+
 /*
  * exec_parse_message
  *
diff --git a/src/backend/utils/cache/relcache.c b/src/backend/utils/cache/relcache.c
index 2707fed12f4..6b4b14819c1 100644
--- a/src/backend/utils/cache/relcache.c
+++ b/src/backend/utils/cache/relcache.c
@@ -3949,8 +3949,6 @@ RelationCacheInitializePhase2(void)
 void
 RelationCacheInitializePhase3(void)
 {
-	HASH_SEQ_STATUS status;
-	RelIdCacheEnt *idhentry;
 	MemoryContext oldcxt;
 	bool		needNewCacheFile = !criticalSharedRelcachesBuilt;
 
@@ -3992,6 +3990,15 @@ RelationCacheInitializePhase3(void)
 	if (IsBootstrapProcessingMode())
 		return;
 
+	RelationCacheInitializePhase3b(needNewCacheFile);
+}
+
+void
+RelationCacheInitializePhase3b(bool needNewCacheFile)
+{
+	HASH_SEQ_STATUS status;
+	RelIdCacheEnt *idhentry;
+
 	/*
 	 * If we didn't get the critical system indexes loaded into relcache, do
 	 * so now.  These are critical because the catcache and/or opclass cache
diff --git a/src/bin/initdb/initdb.c b/src/bin/initdb/initdb.c
index 37ac928b2ef..bff2e5cb407 100644
--- a/src/bin/initdb/initdb.c
+++ b/src/bin/initdb/initdb.c
@@ -76,6 +76,7 @@
 #include "getopt_long.h"
 #include "mb/pg_wchar.h"
 #include "miscadmin.h"
+#include "portability/instr_time.h"
 
 
 /* Ideally this would be in a .h file, but it hardly seems worth the trouble */
@@ -158,12 +159,7 @@ static char *bki_file;
 static char *hba_file;
 static char *ident_file;
 static char *conf_file;
-static char *dictionary_file;
-static char *info_schema_file;
 static char *features_file;
-static char *system_constraints_file;
-static char *system_functions_file;
-static char *system_views_file;
 static bool success = false;
 static bool made_new_pgdata = false;
 static bool found_existing_pgdata = false;
@@ -201,8 +197,7 @@ static bool authwarning = false;
  * but here it is more convenient to pass it as an environment variable
  * (no quoting to worry about).
  */
-static const char *boot_options = "-F -c log_checkpoints=false";
-static const char *backend_options = "--single -F -O -j -c search_path=pg_catalog -c exit_on_error=true -c log_checkpoints=false";
+static const char *boot_options = " -F -c allow_system_table_mods=true -c search_path=pg_catalog -c exit_on_error=true";
 
 /* Additional switches to pass to backend (either boot or standalone) */
 static char *extra_options = "";
@@ -254,21 +249,10 @@ static void write_version_file(const char *extrapath);
 static void set_null_conf(void);
 static void test_config_settings(void);
 static void setup_config(void);
-static void bootstrap_template1(void);
-static void setup_auth(FILE *cmdfd);
 static void get_su_pwd(void);
-static void setup_depend(FILE *cmdfd);
-static void setup_run_file(FILE *cmdfd, const char *filename);
-static void setup_description(FILE *cmdfd);
-static void setup_collation(FILE *cmdfd);
-static void setup_privileges(FILE *cmdfd);
 static void set_info_version(void);
 static void setup_schema(FILE *cmdfd);
-static void load_plpgsql(FILE *cmdfd);
 static void set_remaining_details(FILE *cmdfd);
-static void vacuum_db(FILE *cmdfd);
-static void make_template0(FILE *cmdfd);
-static void make_postgres(FILE *cmdfd);
 static void trapsig(int signum);
 static void check_ok(void);
 static char *escape_quotes(const char *src);
@@ -1326,89 +1310,6 @@ setup_config(void)
 	check_ok();
 }
 
-
-/*
- * run the BKI script in bootstrap mode to create template1
- */
-static void
-bootstrap_template1(void)
-{
-	PG_CMD_DECL;
-	char	  **line;
-	char	  **bki_lines;
-	char		headerline[MAXPGPATH];
-
-	printf(_("running bootstrap script ... "));
-	fflush(stdout);
-
-	bki_lines = readfile(bki_file);
-
-	/* Check that bki file appears to be of the right version */
-
-	snprintf(headerline, sizeof(headerline), "# PostgreSQL %s\n",
-			 PG_MAJORVERSION);
-
-	if (strcmp(headerline, *bki_lines) != 0)
-	{
-		pg_log_error("input file \"%s\" does not belong to PostgreSQL %s",
-					 bki_file, PG_VERSION);
-		fprintf(stderr,
-				_("Check your installation or specify the correct path "
-				  "using the option -L.\n"));
-		exit(1);
-	}
-
-	/* Also ensure backend isn't confused by this environment var: */
-	unsetenv("PGCLIENTENCODING");
-
-	snprintf(cmd, sizeof(cmd),
-			 "\"%s\" --boot -X %d %s %s %s %s",
-			 backend_exec,
-			 wal_segment_size_mb * (1024 * 1024),
-			 data_checksums ? "-k" : "",
-			 boot_options, extra_options,
-			 debug ? "-d 5" : "");
-
-
-	PG_CMD_OPEN;
-
-	for (line = bki_lines; *line != NULL; line++)
-	{
-		PG_CMD_PUTS(*line);
-		free(*line);
-	}
-
-	PG_CMD_CLOSE;
-
-	free(bki_lines);
-
-	check_ok();
-}
-
-/*
- * set up the shadow password table
- */
-static void
-setup_auth(FILE *cmdfd)
-{
-	const char *const *line;
-	static const char *const pg_authid_setup[] = {
-		/*
-		 * The authid table shouldn't be readable except through views, to
-		 * ensure passwords are not publicly visible.
-		 */
-		"REVOKE ALL ON pg_authid FROM public;\n\n",
-		NULL
-	};
-
-	for (line = pg_authid_setup; *line != NULL; line++)
-		PG_CMD_PUTS(*line);
-
-	if (superuser_password)
-		PG_CMD_PRINTF("ALTER USER \"%s\" WITH PASSWORD E'%s';\n\n",
-					  username, escape_quotes(superuser_password));
-}
-
 /*
  * get the superuser password if required
  */
@@ -1472,249 +1373,6 @@ get_su_pwd(void)
 	superuser_password = pwd1;
 }
 
-/*
- * set up pg_depend
- */
-static void
-setup_depend(FILE *cmdfd)
-{
-	const char *const *line;
-	static const char *const pg_depend_setup[] = {
-		/*
-		 * Advance the OID counter so that subsequently-created objects aren't
-		 * pinned.
-		 */
-		"SELECT pg_stop_making_pinned_objects();\n\n",
-		NULL
-	};
-
-	for (line = pg_depend_setup; *line != NULL; line++)
-		PG_CMD_PUTS(*line);
-}
-
-/*
- * Run external file
- */
-static void
-setup_run_file(FILE *cmdfd, const char *filename)
-{
-	char	  **lines;
-
-	lines = readfile(filename);
-
-	for (char **line = lines; *line != NULL; line++)
-	{
-		PG_CMD_PUTS(*line);
-		free(*line);
-	}
-
-	PG_CMD_PUTS("\n\n");
-
-	free(lines);
-}
-
-/*
- * fill in extra description data
- */
-static void
-setup_description(FILE *cmdfd)
-{
-	/* Create default descriptions for operator implementation functions */
-	PG_CMD_PUTS("WITH funcdescs AS ( "
-				"SELECT p.oid as p_oid, o.oid as o_oid, oprname "
-				"FROM pg_proc p JOIN pg_operator o ON oprcode = p.oid ) "
-				"INSERT INTO pg_description "
-				"  SELECT p_oid, 'pg_proc'::regclass, 0, "
-				"    'implementation of ' || oprname || ' operator' "
-				"  FROM funcdescs "
-				"  WHERE NOT EXISTS (SELECT 1 FROM pg_description "
-				"   WHERE objoid = p_oid AND classoid = 'pg_proc'::regclass) "
-				"  AND NOT EXISTS (SELECT 1 FROM pg_description "
-				"   WHERE objoid = o_oid AND classoid = 'pg_operator'::regclass"
-				"         AND description LIKE 'deprecated%');\n\n");
-}
-
-/*
- * populate pg_collation
- */
-static void
-setup_collation(FILE *cmdfd)
-{
-	/*
-	 * Add an SQL-standard name.  We don't want to pin this, so it doesn't go
-	 * in pg_collation.h.  But add it before reading system collations, so
-	 * that it wins if libc defines a locale named ucs_basic.
-	 */
-	PG_CMD_PRINTF("INSERT INTO pg_collation (oid, collname, collnamespace, collowner, collprovider, collisdeterministic, collencoding, collcollate, collctype)"
-				  "VALUES (pg_nextoid('pg_catalog.pg_collation', 'oid', 'pg_catalog.pg_collation_oid_index'), 'ucs_basic', 'pg_catalog'::regnamespace, %u, '%c', true, %d, 'C', 'C');\n\n",
-				  BOOTSTRAP_SUPERUSERID, COLLPROVIDER_LIBC, PG_UTF8);
-
-	/* Now import all collations we can find in the operating system */
-	PG_CMD_PUTS("SELECT pg_import_system_collations('pg_catalog');\n\n");
-}
-
-/*
- * Set up privileges
- *
- * We mark most system catalogs as world-readable.  We don't currently have
- * to touch functions, languages, or databases, because their default
- * permissions are OK.
- *
- * Some objects may require different permissions by default, so we
- * make sure we don't overwrite privilege sets that have already been
- * set (NOT NULL).
- *
- * Also populate pg_init_privs to save what the privileges are at init
- * time.  This is used by pg_dump to allow users to change privileges
- * on catalog objects and to have those privilege changes preserved
- * across dump/reload and pg_upgrade.
- *
- * Note that pg_init_privs is only for per-database objects and therefore
- * we don't include databases or tablespaces.
- */
-static void
-setup_privileges(FILE *cmdfd)
-{
-	const char *const *line;
-	static const char *const privileges_setup[] = {
-		"UPDATE pg_class "
-		"  SET relacl = (SELECT array_agg(a.acl) FROM "
-		" (SELECT '=r/\"POSTGRES\"' as acl "
-		"  UNION SELECT unnest(pg_catalog.acldefault("
-		"    CASE WHEN relkind = " CppAsString2(RELKIND_SEQUENCE) " THEN 's' "
-		"         ELSE 'r' END::\"char\"," CppAsString2(BOOTSTRAP_SUPERUSERID) "::oid))"
-		" ) as a) "
-		"  WHERE relkind IN (" CppAsString2(RELKIND_RELATION) ", "
-		CppAsString2(RELKIND_VIEW) ", " CppAsString2(RELKIND_MATVIEW) ", "
-		CppAsString2(RELKIND_SEQUENCE) ")"
-		"  AND relacl IS NULL;\n\n",
-		"GRANT USAGE ON SCHEMA pg_catalog, public TO PUBLIC;\n\n",
-		"REVOKE ALL ON pg_largeobject FROM PUBLIC;\n\n",
-		"INSERT INTO pg_init_privs "
-		"  (objoid, classoid, objsubid, initprivs, privtype)"
-		"    SELECT"
-		"        oid,"
-		"        (SELECT oid FROM pg_class WHERE relname = 'pg_class'),"
-		"        0,"
-		"        relacl,"
-		"        'i'"
-		"    FROM"
-		"        pg_class"
-		"    WHERE"
-		"        relacl IS NOT NULL"
-		"        AND relkind IN (" CppAsString2(RELKIND_RELATION) ", "
-		CppAsString2(RELKIND_VIEW) ", " CppAsString2(RELKIND_MATVIEW) ", "
-		CppAsString2(RELKIND_SEQUENCE) ");\n\n",
-		"INSERT INTO pg_init_privs "
-		"  (objoid, classoid, objsubid, initprivs, privtype)"
-		"    SELECT"
-		"        pg_class.oid,"
-		"        (SELECT oid FROM pg_class WHERE relname = 'pg_class'),"
-		"        pg_attribute.attnum,"
-		"        pg_attribute.attacl,"
-		"        'i'"
-		"    FROM"
-		"        pg_class"
-		"        JOIN pg_attribute ON (pg_class.oid = pg_attribute.attrelid)"
-		"    WHERE"
-		"        pg_attribute.attacl IS NOT NULL"
-		"        AND pg_class.relkind IN (" CppAsString2(RELKIND_RELATION) ", "
-		CppAsString2(RELKIND_VIEW) ", " CppAsString2(RELKIND_MATVIEW) ", "
-		CppAsString2(RELKIND_SEQUENCE) ");\n\n",
-		"INSERT INTO pg_init_privs "
-		"  (objoid, classoid, objsubid, initprivs, privtype)"
-		"    SELECT"
-		"        oid,"
-		"        (SELECT oid FROM pg_class WHERE relname = 'pg_proc'),"
-		"        0,"
-		"        proacl,"
-		"        'i'"
-		"    FROM"
-		"        pg_proc"
-		"    WHERE"
-		"        proacl IS NOT NULL;\n\n",
-		"INSERT INTO pg_init_privs "
-		"  (objoid, classoid, objsubid, initprivs, privtype)"
-		"    SELECT"
-		"        oid,"
-		"        (SELECT oid FROM pg_class WHERE relname = 'pg_type'),"
-		"        0,"
-		"        typacl,"
-		"        'i'"
-		"    FROM"
-		"        pg_type"
-		"    WHERE"
-		"        typacl IS NOT NULL;\n\n",
-		"INSERT INTO pg_init_privs "
-		"  (objoid, classoid, objsubid, initprivs, privtype)"
-		"    SELECT"
-		"        oid,"
-		"        (SELECT oid FROM pg_class WHERE relname = 'pg_language'),"
-		"        0,"
-		"        lanacl,"
-		"        'i'"
-		"    FROM"
-		"        pg_language"
-		"    WHERE"
-		"        lanacl IS NOT NULL;\n\n",
-		"INSERT INTO pg_init_privs "
-		"  (objoid, classoid, objsubid, initprivs, privtype)"
-		"    SELECT"
-		"        oid,"
-		"        (SELECT oid FROM pg_class WHERE "
-		"         relname = 'pg_largeobject_metadata'),"
-		"        0,"
-		"        lomacl,"
-		"        'i'"
-		"    FROM"
-		"        pg_largeobject_metadata"
-		"    WHERE"
-		"        lomacl IS NOT NULL;\n\n",
-		"INSERT INTO pg_init_privs "
-		"  (objoid, classoid, objsubid, initprivs, privtype)"
-		"    SELECT"
-		"        oid,"
-		"        (SELECT oid FROM pg_class WHERE relname = 'pg_namespace'),"
-		"        0,"
-		"        nspacl,"
-		"        'i'"
-		"    FROM"
-		"        pg_namespace"
-		"    WHERE"
-		"        nspacl IS NOT NULL;\n\n",
-		"INSERT INTO pg_init_privs "
-		"  (objoid, classoid, objsubid, initprivs, privtype)"
-		"    SELECT"
-		"        oid,"
-		"        (SELECT oid FROM pg_class WHERE "
-		"         relname = 'pg_foreign_data_wrapper'),"
-		"        0,"
-		"        fdwacl,"
-		"        'i'"
-		"    FROM"
-		"        pg_foreign_data_wrapper"
-		"    WHERE"
-		"        fdwacl IS NOT NULL;\n\n",
-		"INSERT INTO pg_init_privs "
-		"  (objoid, classoid, objsubid, initprivs, privtype)"
-		"    SELECT"
-		"        oid,"
-		"        (SELECT oid FROM pg_class "
-		"         WHERE relname = 'pg_foreign_server'),"
-		"        0,"
-		"        srvacl,"
-		"        'i'"
-		"    FROM"
-		"        pg_foreign_server"
-		"    WHERE"
-		"        srvacl IS NOT NULL;\n\n",
-		NULL
-	};
-
-	for (line = privileges_setup; *line != NULL; line++)
-		PG_CMD_PUTS(*line);
-}
-
 /*
  * extract the strange version of version required for information schema
  * (09.08.0007abc)
@@ -1749,29 +1407,18 @@ set_info_version(void)
 static void
 setup_schema(FILE *cmdfd)
 {
-	setup_run_file(cmdfd, info_schema_file);
-
 	PG_CMD_PRINTF("UPDATE information_schema.sql_implementation_info "
 				  "  SET character_value = '%s' "
-				  "  WHERE implementation_info_name = 'DBMS VERSION';\n\n",
+				  "  WHERE implementation_info_name = 'DBMS VERSION';\n",
 				  infoversion);
 
 	PG_CMD_PRINTF("COPY information_schema.sql_features "
 				  "  (feature_id, feature_name, sub_feature_id, "
 				  "  sub_feature_name, is_supported, comments) "
-				  " FROM E'%s';\n\n",
+				  " FROM E'%s';\n",
 				  escape_quotes(features_file));
 }
 
-/*
- * load PL/pgSQL server-side language
- */
-static void
-load_plpgsql(FILE *cmdfd)
-{
-	PG_CMD_PUTS("CREATE EXTENSION plpgsql;\n\n");
-}
-
 /*
  * Set some remaining details that aren't known when postgres.bki is made.
  *
@@ -1796,8 +1443,8 @@ set_remaining_details(FILE *cmdfd)
 	 * locale/encoding without cheating.
 	 */
 	static char *final_details[] = {
-		"UPDATE pg_authid SET rolname = E'SUPERUSER_NAME' WHERE rolname = 'POSTGRES';\n\n",
-		"UPDATE pg_database SET encoding = E'ENCODING', datcollate = E'LC_COLLATE', datctype = E'LC_CTYPE';\n\n",
+		"UPDATE pg_authid SET rolname = E'SUPERUSER_NAME' WHERE rolname = 'POSTGRES';\n",
+		"UPDATE pg_database SET encoding = E'ENCODING', datcollate = E'LC_COLLATE', datctype = E'LC_CTYPE';\n",
 		NULL
 	};
 
@@ -1814,93 +1461,6 @@ set_remaining_details(FILE *cmdfd)
 		PG_CMD_PUTS(*line);
 }
 
-/*
- * clean everything up in template1
- */
-static void
-vacuum_db(FILE *cmdfd)
-{
-	/* Run analyze before VACUUM so the statistics are frozen. */
-	PG_CMD_PUTS("ANALYZE;\n\nVACUUM FREEZE;\n\n");
-}
-
-/*
- * copy template1 to template0
- */
-static void
-make_template0(FILE *cmdfd)
-{
-	const char *const *line;
-
-	/*
-	 * pg_upgrade tries to preserve database OIDs across upgrades. It's smart
-	 * enough to drop and recreate a conflicting database with the same name,
-	 * but if the same OID were used for one system-created database in the
-	 * old cluster and a different system-created database in the new cluster,
-	 * it would fail. To avoid that, assign a fixed OID to template0 rather
-	 * than letting the server choose one.
-	 *
-	 * (Note that, while the user could have dropped and recreated these
-	 * objects in the old cluster, the problem scenario only exists if the OID
-	 * that is in use in the old cluster is also used in the new cluster - and
-	 * the new cluster should be the result of a fresh initdb.)
-	 */
-	static const char *const template0_setup[] = {
-		"CREATE DATABASE template0 IS_TEMPLATE = true ALLOW_CONNECTIONS = false OID = "
-		CppAsString2(Template0ObjectId) ";\n\n",
-
-		/*
-		 * template0 shouldn't have any collation-dependent objects, so unset
-		 * the collation version.  This disables collation version checks when
-		 * making a new database from it.
-		 */
-		"UPDATE pg_database SET datcollversion = NULL WHERE datname = 'template0';\n\n",
-
-		/*
-		 * While we are here, do set the collation version on template1.
-		 */
-		"UPDATE pg_database SET datcollversion = pg_database_collation_actual_version(oid) WHERE datname = 'template1';\n\n",
-
-		/*
-		 * Explicitly revoke public create-schema and create-temp-table
-		 * privileges in template1 and template0; else the latter would be on
-		 * by default
-		 */
-		"REVOKE CREATE,TEMPORARY ON DATABASE template1 FROM public;\n\n",
-		"REVOKE CREATE,TEMPORARY ON DATABASE template0 FROM public;\n\n",
-
-		"COMMENT ON DATABASE template0 IS 'unmodifiable empty database';\n\n",
-
-		/*
-		 * Finally vacuum to clean up dead rows in pg_database
-		 */
-		"VACUUM pg_database;\n\n",
-		NULL
-	};
-
-	for (line = template0_setup; *line; line++)
-		PG_CMD_PUTS(*line);
-}
-
-/*
- * copy template1 to postgres
- */
-static void
-make_postgres(FILE *cmdfd)
-{
-	const char *const *line;
-
-	/* Assign a fixed OID to postgres, for the same reasons as template0 */
-	static const char *const postgres_setup[] = {
-		"CREATE DATABASE postgres OID = " CppAsString2(PostgresObjectId) ";\n\n",
-		"COMMENT ON DATABASE postgres IS 'default administrative connection database';\n\n",
-		NULL
-	};
-
-	for (line = postgres_setup; *line; line++)
-		PG_CMD_PUTS(*line);
-}
-
 /*
  * signal handler in case we are interrupted.
  *
@@ -2446,16 +2006,10 @@ setup_locale_encoding(void)
 void
 setup_data_file_paths(void)
 {
-	set_input(&bki_file, "postgres.bki");
 	set_input(&hba_file, "pg_hba.conf.sample");
 	set_input(&ident_file, "pg_ident.conf.sample");
 	set_input(&conf_file, "postgresql.conf.sample");
-	set_input(&dictionary_file, "snowball_create.sql");
-	set_input(&info_schema_file, "information_schema.sql");
 	set_input(&features_file, "sql_features.txt");
-	set_input(&system_constraints_file, "system_constraints.sql");
-	set_input(&system_functions_file, "system_functions.sql");
-	set_input(&system_views_file, "system_views.sql");
 
 	if (show_setting || debug)
 	{
@@ -2474,16 +2028,9 @@ setup_data_file_paths(void)
 			exit(0);
 	}
 
-	check_input(bki_file);
 	check_input(hba_file);
 	check_input(ident_file);
 	check_input(conf_file);
-	check_input(dictionary_file);
-	check_input(info_schema_file);
-	check_input(features_file);
-	check_input(system_constraints_file);
-	check_input(system_functions_file);
-	check_input(system_views_file);
 }
 
 
@@ -2744,6 +2291,7 @@ initialize_data_directory(void)
 {
 	PG_CMD_DECL;
 	int			i;
+	instr_time	last_ts, cur_ts;
 
 	setup_signals();
 
@@ -2788,68 +2336,46 @@ initialize_data_directory(void)
 	write_version_file(NULL);
 
 	/* Select suitable configuration settings */
+	INSTR_TIME_SET_CURRENT(last_ts);
 	set_null_conf();
 	test_config_settings();
+	INSTR_TIME_SET_CURRENT(cur_ts);
+	fprintf(stderr, "config determination in %.3f ms\n",
+			(INSTR_TIME_GET_DOUBLE(cur_ts) - INSTR_TIME_GET_DOUBLE(last_ts)) * 1000);
 
 	/* Now create all the text config files */
 	setup_config();
 
-	/* Bootstrap template1 */
-	bootstrap_template1();
-
 	/*
 	 * Make the per-database PG_VERSION for template1 only after init'ing it
+	 *
+	 * FIXME: move to server
 	 */
 	write_version_file("base/1");
 
-	/*
-	 * Create the stuff we don't need to use bootstrap mode for, using a
-	 * backend running in simple standalone mode.
-	 */
-	fputs(_("performing post-bootstrap initialization ... "), stdout);
-	fflush(stdout);
-
 	snprintf(cmd, sizeof(cmd),
-			 "\"%s\" %s %s template1 >%s",
-			 backend_exec, backend_options, extra_options,
+			 "\"%s\" --boot -s \"%s\" -X %d %s %s %s %s >%s 2>&1",
+			 backend_exec,
+			 share_path,
+			 wal_segment_size_mb * (1024 * 1024),
+			 data_checksums ? "-k" : "",
+			 boot_options, extra_options,
+			 debug ? "-d 5" : "",
 			 DEVNULL);
 
+	/* Also ensure backend isn't confused by this environment var: */
+	unsetenv("PGCLIENTENCODING");
+
+	printf(_("running database bootstrap ... "));
+
 	PG_CMD_OPEN;
 
-	setup_auth(cmdfd);
-
-	setup_run_file(cmdfd, system_constraints_file);
-
-	setup_run_file(cmdfd, system_functions_file);
-
-	setup_depend(cmdfd);
-
-	/*
-	 * Note that no objects created after setup_depend() will be "pinned".
-	 * They are all droppable at the whim of the DBA.
-	 */
-
-	setup_run_file(cmdfd, system_views_file);
-
-	setup_description(cmdfd);
-
-	setup_collation(cmdfd);
-
-	setup_run_file(cmdfd, dictionary_file);
-
-	setup_privileges(cmdfd);
-
 	setup_schema(cmdfd);
-
-	load_plpgsql(cmdfd);
-
 	set_remaining_details(cmdfd);
 
-	vacuum_db(cmdfd);
-
-	make_template0(cmdfd);
-
-	make_postgres(cmdfd);
+	if (superuser_password)
+		PG_CMD_PRINTF("ALTER USER \"%s\" WITH PASSWORD E'%s';\n",
+					  username, escape_quotes(superuser_password));
 
 	PG_CMD_CLOSE;
 
@@ -3178,7 +2704,7 @@ main(int argc, char *argv[])
 	else
 		printf(_("\nSync to disk skipped.\nThe data directory might become corrupt if the operating system crashes.\n"));
 
-	if (authwarning)
+	if (authwarning && false)
 	{
 		printf("\n");
 		pg_log_warning("enabling \"trust\" authentication for local connections");
-- 
2.34.0

>From 3d97d3aaafb4a6e7ea8d283e858c0200b6a2a1cc Mon Sep 17 00:00:00 2001
From: Andres Freund <and...@anarazel.de>
Date: Sun, 20 Feb 2022 12:17:03 -0800
Subject: [PATCH v1 4/5] initdb: Optimize WAL writing during initdb.

Author:
Reviewed-By:
Discussion: https://postgr.es/m/
Backpatch:
---
 src/include/miscadmin.h                 |  3 +++
 src/backend/access/transam/xloginsert.c | 18 ++++++++++++------
 src/backend/bootstrap/bootstrap.c       |  2 +-
 src/backend/catalog/heap.c              |  4 +++-
 src/backend/commands/dbcommands.c       | 16 +++++++++++++---
 5 files changed, 32 insertions(+), 11 deletions(-)

diff --git a/src/include/miscadmin.h b/src/include/miscadmin.h
index 0abc3ad5405..9af1f46b3b2 100644
--- a/src/include/miscadmin.h
+++ b/src/include/miscadmin.h
@@ -396,6 +396,7 @@ extern bool superuser_arg(Oid roleid);	/* given user is superuser */
 typedef enum ProcessingMode
 {
 	BootstrapProcessing,		/* bootstrap creation of template database */
+	LateBootstrapProcessing,	/* XXX bootstrap initializing more stuff */
 	InitProcessing,				/* initializing system */
 	NormalProcessing			/* normal processing */
 } ProcessingMode;
@@ -403,6 +404,7 @@ typedef enum ProcessingMode
 extern ProcessingMode Mode;
 
 #define IsBootstrapProcessingMode() (Mode == BootstrapProcessing)
+#define IsLateBootstrapProcessingMode() (Mode == LateBootstrapProcessing)
 #define IsInitProcessingMode()		(Mode == InitProcessing)
 #define IsNormalProcessingMode()	(Mode == NormalProcessing)
 
@@ -411,6 +413,7 @@ extern ProcessingMode Mode;
 #define SetProcessingMode(mode) \
 	do { \
 		AssertArg((mode) == BootstrapProcessing || \
+				  (mode) == LateBootstrapProcessing || \
 				  (mode) == InitProcessing || \
 				  (mode) == NormalProcessing); \
 		Mode = (mode); \
diff --git a/src/backend/access/transam/xloginsert.c b/src/backend/access/transam/xloginsert.c
index c260310c4c8..cd4316b108e 100644
--- a/src/backend/access/transam/xloginsert.c
+++ b/src/backend/access/transam/xloginsert.c
@@ -446,14 +446,20 @@ XLogInsert(RmgrId rmid, uint8 info)
 	TRACE_POSTGRESQL_WAL_INSERT(rmid, info);
 
 	/*
-	 * In bootstrap mode, we don't actually log anything but XLOG resources;
-	 * return a phony record pointer.
+	 * In bootstrap mode, we don't actually log anything but shutdown
+	 * checkpoint records; return a phony record pointer.
 	 */
-	if (IsBootstrapProcessingMode() && rmid != RM_XLOG_ID)
+	if (IsBootstrapProcessingMode() || IsLateBootstrapProcessingMode())
 	{
-		XLogResetInsertion();
-		EndPos = SizeOfXLogLongPHD; /* start of 1st chkpt record */
-		return EndPos;
+		uint8		rectype = info & ~XLR_INFO_MASK;
+
+		if (rmid != RM_XLOG_ID ||
+			rectype != XLOG_CHECKPOINT_SHUTDOWN)
+		{
+			XLogResetInsertion();
+			EndPos = SizeOfXLogLongPHD; /* start of 1st chkpt record */
+			return EndPos;
+		}
 	}
 
 	do
diff --git a/src/backend/bootstrap/bootstrap.c b/src/backend/bootstrap/bootstrap.c
index 3fd8ed60715..6230ba17685 100644
--- a/src/backend/bootstrap/bootstrap.c
+++ b/src/backend/bootstrap/bootstrap.c
@@ -451,7 +451,7 @@ BootstrapModeMain(int argc, char *argv[], bool check_only)
 	/*
 	 * Load further catalog contents by running a bunch of SQL commands.
 	 */
-	SetProcessingMode(NormalProcessing);
+	SetProcessingMode(LateBootstrapProcessing);
 
 	bootstrap_load_nonbki(share_path);
 
diff --git a/src/backend/catalog/heap.c b/src/backend/catalog/heap.c
index 7e99de88b34..486f0e5ea1f 100644
--- a/src/backend/catalog/heap.c
+++ b/src/backend/catalog/heap.c
@@ -1138,7 +1138,9 @@ heap_create_with_catalog(const char *relname,
 	/*
 	 * sanity checks
 	 */
-	Assert(IsNormalProcessingMode() || IsBootstrapProcessingMode());
+	Assert(IsNormalProcessingMode() ||
+		   IsBootstrapProcessingMode() ||
+		   IsLateBootstrapProcessingMode());
 
 	/*
 	 * Validate proposed tupdesc for the desired relkind.  If
diff --git a/src/backend/commands/dbcommands.c b/src/backend/commands/dbcommands.c
index c37e3c9a9a4..1720bad1d07 100644
--- a/src/backend/commands/dbcommands.c
+++ b/src/backend/commands/dbcommands.c
@@ -676,9 +676,15 @@ createdb(ParseState *pstate, const CreatedbStmt *stmt)
 	 * happened while we're copying files, a file might be deleted just when
 	 * we're about to copy it, causing the lstat() call in copydir() to fail
 	 * with ENOENT.
+	 *
+	 * In bootstrap mode FlushDatabaseBuffers() suffices because there are
+	 * unlink requests.
 	 */
-	RequestCheckpoint(CHECKPOINT_IMMEDIATE | CHECKPOINT_FORCE | CHECKPOINT_WAIT
-					  | CHECKPOINT_FLUSH_ALL);
+	if (IsBootstrapProcessingMode() || IsLateBootstrapProcessingMode())
+		FlushDatabaseBuffers(src_dboid);
+	else
+		RequestCheckpoint(CHECKPOINT_IMMEDIATE | CHECKPOINT_FORCE | CHECKPOINT_WAIT
+						  | CHECKPOINT_FLUSH_ALL);
 
 	/*
 	 * Once we start copying subdirectories, we need to be able to clean 'em
@@ -782,8 +788,12 @@ createdb(ParseState *pstate, const CreatedbStmt *stmt)
 		 *
 		 * Perhaps if we ever implement CREATE DATABASE in a less cheesy way,
 		 * we can avoid this.
+		 *
+		 * We do not need this checkpoint in bootstrap mode - if we fail, the
+		 * cluster won't be valid anyway.
 		 */
-		RequestCheckpoint(CHECKPOINT_IMMEDIATE | CHECKPOINT_FORCE | CHECKPOINT_WAIT);
+		if (!IsBootstrapProcessingMode() && !IsLateBootstrapProcessingMode())
+			RequestCheckpoint(CHECKPOINT_IMMEDIATE | CHECKPOINT_FORCE | CHECKPOINT_WAIT);
 
 		/*
 		 * Close pg_database, but keep lock till commit.
-- 
2.34.0

>From defeeee9b04fca7f376a7a62fcdfa0fbd46cccef Mon Sep 17 00:00:00 2001
From: Andres Freund <and...@anarazel.de>
Date: Sun, 20 Feb 2022 13:39:40 -0800
Subject: [PATCH v1 5/5] initdb: call isatty() only once in bootparse.y.

Causes a not insignificant amount of syscalls...
---
 src/backend/bootstrap/bootparse.y | 8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)

diff --git a/src/backend/bootstrap/bootparse.y b/src/backend/bootstrap/bootparse.y
index 142433f63f3..dff86f71583 100644
--- a/src/backend/bootstrap/bootparse.y
+++ b/src/backend/bootstrap/bootparse.y
@@ -62,11 +62,17 @@ do_start(void)
 static void
 do_end(void)
 {
+	static int isatty_cached = -1;
+
 	/* Reclaim memory allocated while processing this line */
 	MemoryContextSwitchTo(CurTransactionContext);
 	MemoryContextReset(per_line_ctx);
 	CHECK_FOR_INTERRUPTS();		/* allow SIGINT to kill bootstrap run */
-	if (isatty(0))
+
+	if (isatty_cached == -1)
+		isatty_cached = isatty(0);
+
+	if (isatty_cached)
 	{
 		printf("bootstrap> ");
 		fflush(stdout);
-- 
2.34.0

Reply via email to