From 4cc6b8a8ca4a982b8b6a521b40abffbcd9853807 Mon Sep 17 00:00:00 2001
From: Konstantin Osipov <kostja@tarantool.org>
Date: Tue, 20 Aug 2013 21:20:17 +0400
Subject: [PATCH] Rewrite --init-storage: dump a compiled-in blob in it

Rewrite --init-storage to dump a compiled-in blob
instead of firing off the entire save snapshot machinery.

This should simplify bootstrap in presence of system
spaces:
there's going to be no need to implement the
code which creates system, they will be created
simply by recovery from a snapshot.
---
 cmake/utils.cmake    |  16 ++++++++++
 extra/CMakeLists.txt |   1 +
 extra/bin2c.c        |  73 +++++++++++++++++++++++++++++++++++++++++++
 include/box/box.h    |   8 +----
 include/recovery.h   |   5 +--
 src/CMakeLists.txt   |   3 ++
 src/bootstrap.snap   | Bin 0 -> 15 bytes
 src/box/box.cc       |  11 ++-----
 src/box/key_def.h    |   8 +++++
 src/recovery.cc      |   6 ++--
 src/replication.cc   |   2 +-
 src/tarantool.cc     |  40 +++++++++++++-----------
 test/box/args.result |   2 --
 13 files changed, 131 insertions(+), 44 deletions(-)
 create mode 100644 extra/bin2c.c
 create mode 100644 src/bootstrap.snap

diff --git a/cmake/utils.cmake b/cmake/utils.cmake
index e78e4bf7d9..c6a24f1a05 100644
--- a/cmake/utils.cmake
+++ b/cmake/utils.cmake
@@ -55,3 +55,19 @@ function(lua_source varname filename)
     set(var ${${varname}})
     set(${varname} ${var} ${dstfile} PARENT_SCOPE)
 endfunction()
+
+function(bin_source varname srcfile dstfile)
+    set (tmpfile "${CMAKE_CURRENT_BINARY_DIR}/${dstfile}.tmp")
+    get_filename_component(module ${dstfile} NAME_WE)
+
+    ADD_CUSTOM_COMMAND(OUTPUT ${dstfile}
+        COMMAND ${ECHO} 'const unsigned char ${module}_bin[] = {' > ${tmpfile}
+        COMMAND ${CMAKE_BINARY_DIR}/extra/bin2c ${srcfile} >> ${tmpfile}
+        COMMAND ${ECHO} '}\;' >> ${tmpfile}
+        COMMAND ${CMAKE_COMMAND} -E copy_if_different ${tmpfile} ${dstfile}
+        COMMAND ${CMAKE_COMMAND} -E remove ${tmpfile}
+        DEPENDS ${srcfile} bin2c)
+
+    set(var ${${varname}})
+    set(${varname} ${var} ${dstfile} PARENT_SCOPE)
+endfunction()
diff --git a/extra/CMakeLists.txt b/extra/CMakeLists.txt
index 05cd374540..58b3eb54c0 100644
--- a/extra/CMakeLists.txt
+++ b/extra/CMakeLists.txt
@@ -26,3 +26,4 @@ endif()
 configure_file(rpm.spec.in rpm.spec @ONLY)
 
 add_executable(txt2c txt2c.c)
+add_executable(bin2c bin2c.c)
diff --git a/extra/bin2c.c b/extra/bin2c.c
new file mode 100644
index 0000000000..9776d55224
--- /dev/null
+++ b/extra/bin2c.c
@@ -0,0 +1,73 @@
+/*
+ * txt2c: Converts text files to C strings
+ *
+ * Compile with:
+ *	gcc txt2cs.c -o txt2cs
+ *
+ * Public domain.
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+int main(int argc, char** argv) {
+	const char *prefix = "";
+	const char *suffix = "\n";
+	int no_quote = 0; /* if 1, do not prepend and append quotation marks (") */
+	FILE *in = stdin;
+	FILE *out = stdout;
+
+	int c;
+	while ((c = getopt(argc, argv, "np:s:h")) != -1) {
+		switch (c) {
+		case 'p':
+			prefix = optarg;
+			break;
+		case 's':
+			suffix = optarg;
+			break;
+		case 'h':
+			printf("Usage: %s [-n] [-p prefix] [-s suffix] [infile] [outfile]\n", argv[0]);
+			exit(0);
+			break;
+		}
+	}
+
+	if (optind < argc) {
+		if (strcmp(argv[optind], "-") != 0) {
+			if (!(in = fopen(argv[optind], "r"))) {
+				fprintf(stderr, "Can't open %s\n",
+					argv[optind]);
+				perror(argv[0]);
+				exit(1);
+			}
+		}
+		if (optind + 1 < argc) {
+			if (strcmp(argv[optind + 1], "-") != 0) {
+				if (!(out = fopen(argv[optind + 1], "w"))) {
+					fprintf(stderr, "Can't open %s\n",
+						argv[optind + 1]);
+					perror(argv[0]);
+					exit(1);
+				}
+			}
+		}
+	}
+
+	fputs(prefix, out);
+	int col = 1;
+
+	while ((c = fgetc(in)) != -1) {
+		if (col >= 78 - 6)
+		{
+			fputs("\n", out);
+			col = 0;
+		}
+		fprintf(out, " 0x%.2x,", c);
+		col += 6;
+	}
+	fputs(suffix, out);
+	return 0;
+}
+
diff --git a/include/box/box.h b/include/box/box.h
index e366696013..a019d61154 100644
--- a/include/box/box.h
+++ b/include/box/box.h
@@ -49,7 +49,7 @@ struct tarantool_cfg;
 struct lua_State;
 
 /** To be called at program start. */
-void box_init(bool init_storage);
+void box_init();
 /** To be called at program end. */
 void box_free(void);
 
@@ -96,12 +96,6 @@ const char *box_status(void);
 void
 box_leave_local_standby_mode(void *data __attribute__((unused)));
 
-enum {
-	BOX_SPACE_MAX = UINT32_MAX,
-	BOX_INDEX_MAX = 10,
-	BOX_FIELD_MAX = UINT32_MAX
-};
-
 #if defined(__cplusplus)
 }
 #endif /* defined(__cplusplus) */
diff --git a/include/recovery.h b/include/recovery.h
index 1757593728..816f4f2d56 100644
--- a/include/recovery.h
+++ b/include/recovery.h
@@ -41,8 +41,6 @@ extern "C" {
 struct fiber;
 struct tbuf;
 
-#define RECOVER_READONLY 1
-
 typedef int (row_handler)(void *, const char *, uint32_t);
 
 /** A "condition variable" that allows fibers to wait when a given
@@ -100,7 +98,6 @@ struct recovery_state {
 	void *row_handler_param;
 	int snap_io_rate_limit;
 	int rows_per_wal;
-	int flags;
 	double wal_fsync_delay;
 	struct wait_lsn wait_lsn;
 	enum wal_mode wal_mode;
@@ -112,7 +109,7 @@ extern struct recovery_state *recovery_state;
 
 void recovery_init(const char *snap_dirname, const char *xlog_dirname,
 		   row_handler row_handler, void *row_handler_param,
-		   int rows_per_wal, int flags);
+		   int rows_per_wal);
 void recovery_update_mode(struct recovery_state *r,
 			  const char *wal_mode, double fsync_delay);
 void recovery_update_io_rate_limit(struct recovery_state *r,
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 7f650d5179..76ddcbd2cd 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -62,6 +62,8 @@ set_property(DIRECTORY PROPERTY CLEAN_NO_CUSTOM true)
 file(MAKE_DIRECTORY ${CMAKE_BINARY_DIR}/src/lua)
 set(lua_sources)
 lua_source(lua_sources lua/uuid.lua)
+set(bin_sources)
+bin_source(bin_sources bootstrap.snap bootstrap.h)
 
 add_custom_target(generate_lua_sources
     WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/src/box
@@ -120,6 +122,7 @@ set (common_sources
      lua/session.cc
      lua/cjson.cc
      ${lua_sources}
+     ${bin_sources}
 )
 
 if (ENABLE_TRACE)
diff --git a/src/bootstrap.snap b/src/bootstrap.snap
new file mode 100644
index 0000000000000000000000000000000000000000..8f8d8ac5b4c8634e2099b9d6671560db48518960
GIT binary patch
literal 15
WcmWIca}3}z&@(jT;*wjvRsaASSp$~<

literal 0
HcmV?d00001

diff --git a/src/box/box.cc b/src/box/box.cc
index c3569e67bf..901fa3cafe 100644
--- a/src/box/box.cc
+++ b/src/box/box.cc
@@ -316,7 +316,7 @@ box_free(void)
 }
 
 void
-box_init(bool init_storage)
+box_init()
 {
 	title("loading");
 	atexit(box_free);
@@ -328,17 +328,12 @@ box_init(bool init_storage)
 
 	/* recovery initialization */
 	recovery_init(cfg.snap_dir, cfg.wal_dir,
-		      recover_row, NULL,
-		      cfg.rows_per_wal,
-		      init_storage ? RECOVER_READONLY : 0);
+		      recover_row, NULL, cfg.rows_per_wal);
 	recovery_update_io_rate_limit(recovery_state, cfg.snap_io_rate_limit);
 	recovery_setup_panic(recovery_state, cfg.panic_on_snap_error, cfg.panic_on_wal_error);
 
 	stat_base = stat_register(requests_strs, requests_MAX);
 
-	if (init_storage)
-		return;
-
 	begin_build_primary_indexes();
 	recover_snap(recovery_state);
 	end_build_primary_indexes();
@@ -383,7 +378,7 @@ snapshot_space(struct space *sp, void *udata)
 	struct tuple *tuple;
 	struct snapshot_space_param *ud = (struct snapshot_space_param *) udata;
 	Index *pk = space_index(sp, 0);
-	struct iterator *it = pk->position();;
+	struct iterator *it = pk->position();
 	pk->initIterator(it, ITER_ALL, NULL, 0);
 
 	while ((tuple = it->next(it)))
diff --git a/src/box/key_def.h b/src/box/key_def.h
index 9bb22513f1..03939f7e8e 100644
--- a/src/box/key_def.h
+++ b/src/box/key_def.h
@@ -29,6 +29,14 @@
  * SUCH DAMAGE.
  */
 #include "tarantool/util.h"
+#include "rlist.h"
+
+enum {
+	BOX_SPACE_MAX = INT32_MAX,
+	BOX_INDEX_MAX = 10,
+	BOX_FIELD_MAX = UINT32_MAX
+};
+
 /*
  * Possible field data types. Can't use STRS/ENUM macros for them,
  * since there is a mismatch between enum name (STRING) and type
diff --git a/src/recovery.cc b/src/recovery.cc
index 4e85b95ddc..f1d5eaf271 100644
--- a/src/recovery.cc
+++ b/src/recovery.cc
@@ -202,7 +202,7 @@ recovery_stop_local(struct recovery_state *r);
 void
 recovery_init(const char *snap_dirname, const char *wal_dirname,
 	      row_handler row_handler, void *row_handler_param,
-	      int rows_per_wal, int flags)
+	      int rows_per_wal)
 {
 	assert(recovery_state == NULL);
 	recovery_state = (struct recovery_state *) p0alloc(eter_pool, sizeof(struct recovery_state));
@@ -222,7 +222,6 @@ recovery_init(const char *snap_dirname, const char *wal_dirname,
 	r->wal_dir->open_wflags = r->wal_mode == WAL_FSYNC ? WAL_SYNC_FLAG : 0;
 	r->rows_per_wal = rows_per_wal;
 	wait_lsn_clear(&r->wait_lsn);
-	r->flags = flags;
 }
 
 void
@@ -564,8 +563,7 @@ recovery_finalize(struct recovery_state *r)
 		log_io_close(&r->current_wal);
 	}
 
-	if ((r->flags & RECOVER_READONLY) == 0)
-		wal_writer_start(r);
+	wal_writer_start(r);
 }
 
 
diff --git a/src/replication.cc b/src/replication.cc
index 747a7d4ddc..fbd4bb3568 100644
--- a/src/replication.cc
+++ b/src/replication.cc
@@ -683,7 +683,7 @@ replication_relay_loop(int client_sock)
 	/* Initialize the recovery process */
 	recovery_init(cfg.snap_dir, cfg.wal_dir,
 		      replication_relay_send_row, (void *)(intptr_t) client_sock,
-		      INT32_MAX, RECOVER_READONLY);
+		      INT32_MAX);
 	/*
 	 * Note that recovery starts with lsn _NEXT_ to
 	 * the confirmed one.
diff --git a/src/tarantool.cc b/src/tarantool.cc
index c188064b0c..8e36e525c5 100644
--- a/src/tarantool.cc
+++ b/src/tarantool.cc
@@ -52,6 +52,7 @@
 #include <iproto.h>
 #include "mutex.h"
 #include <recovery.h>
+#include "log_io.h"
 #include <crc32.h>
 #include <palloc.h>
 #include <salloc.h>
@@ -69,6 +70,7 @@ extern "C" {
 #include "memcached.h"
 #include "session.h"
 #include "box/box.h"
+#include "bootstrap.h"
 #include "scoped_guard.h"
 
 
@@ -619,20 +621,26 @@ tarantool_free(void)
 #endif
 }
 
-static void
-initialize_minimal()
-{
-	if (!salloc_init(64 * 1000 * 1000, 4, 2))
-		panic_syserror("can't initialize slab allocator");
-	fiber_init();
-	coeio_init();
-}
-
-/** Callback of snapshot_save() when doing --init-storage */
+/** Create the initial snapshot file in the storage. */
 void
-init_storage(struct log_io * /* l */, struct fio_batch * /* batch */)
+init_storage()
 {
-	/* Nothing. */
+	struct log_dir dir = snap_dir;
+	dir.dirname = cfg.snap_dir;
+	const char *filename = format_filename(&dir, 1 /* lsn */, NONE);
+	int fd = open(filename, O_EXCL|O_CREAT|O_WRONLY, dir.mode);
+	say_info("saving snapshot `%s'", filename);
+	if (fd == -1) {
+		panic_syserror("failed to open snapshot file `%s' for "
+			       "writing", filename);
+	}
+	if (write(fd, bootstrap_bin, sizeof(bootstrap_bin)) !=
+						sizeof(bootstrap_bin)) {
+		panic_syserror("failed to write to snapshot file `%s'",
+			       filename);
+	}
+	close(fd);
+	say_info("done");
 }
 
 int
@@ -803,11 +811,7 @@ main(int argc, char **argv)
 	}
 
 	if (gopt(opt, 'I')) {
-		initialize_minimal();
-		tarantool_L = tarantool_lua_init(); /* box.space[] */
-		box_init(true);
-		set_lsn(recovery_state, 1);
-		snapshot_save(recovery_state, init_storage);
+		init_storage();
 		exit(EXIT_SUCCESS);
 	}
 
@@ -851,7 +855,7 @@ main(int argc, char **argv)
 
 	try {
 		tarantool_L = tarantool_lua_init();
-		box_init(false);
+		box_init();
 		atexit(tarantool_lua_free);
 		memcached_init(cfg.bind_ipaddr, cfg.memcached_port);
 		tarantool_lua_load_cfg(tarantool_L, &cfg);
diff --git a/test/box/args.result b/test/box/args.result
index 5d0b6846ea..5f7b4bedf6 100644
--- a/test/box/args.result
+++ b/test/box/args.result
@@ -95,8 +95,6 @@ CXX_FLAGS: flags
 # can be relative to work_dir.
 
 tarantool_box --config=bug726778.cfg --init-storage
-tarantool_box: space 0 successfully configured
-tarantool_box: creating `snapshots/00000000000000000001.snap.inprogress'
 tarantool_box: saving snapshot `snapshots/00000000000000000001.snap'
 tarantool_box: done
 
-- 
GitLab