From 1e0860d5eceb95d0b378cfa0ae5a9e17a5fcb162 Mon Sep 17 00:00:00 2001
From: Dmitry Simonenko <pmwkaa@gmail.com>
Date: Thu, 28 Feb 2013 14:55:53 +0400
Subject: [PATCH] client-cat-add-hdr: new client options added. -H add headers
 to the raw format output (xlog and snapshot) -I read xlog content from the
 stdin

---
 client/tarantool/tc_opt.c               | 15 ++++++++++++
 client/tarantool/tc_opt.h               |  1 +
 client/tarantool/tc_print.c             |  4 ++++
 client/tarantool/tc_store.c             | 31 +++++++++++++++++++++----
 connector/c/include/tarantool/tnt_log.h |  3 +++
 connector/c/tntrpl/tnt_log.c            | 21 ++++++++++-------
 6 files changed, 63 insertions(+), 12 deletions(-)

diff --git a/client/tarantool/tc_opt.c b/client/tarantool/tc_opt.c
index 15d80e3910..5d771bdc08 100644
--- a/client/tarantool/tc_opt.c
+++ b/client/tarantool/tc_opt.c
@@ -49,6 +49,8 @@ static const void *tc_options_def = gopt_start(
 		    gopt_longs("admin-port"), " <port>", "server admin port"),
 	gopt_option('C', GOPT_ARG, gopt_shorts('C'),
 		    gopt_longs("cat"), " <file>", "print xlog or snapshot file content"),
+	gopt_option('I', 0, gopt_shorts('C'),
+		    gopt_longs("catin"), NULL, "print xlog content from stdin"),
 	gopt_option('P', GOPT_ARG, gopt_shorts('P'),
 		    gopt_longs("play"), " <file>", "replay xlog file to the specified server"),
 	gopt_option('S', GOPT_ARG, gopt_shorts('S'),
@@ -59,6 +61,8 @@ static const void *tc_options_def = gopt_start(
 		    gopt_longs("to"), " <lsn>", "stop on specified xlog lsn"),
 	gopt_option('M', GOPT_ARG, gopt_shorts('M'),
 		    gopt_longs("format"), " <name>", "cat output format (tarantool, raw)"),
+	gopt_option('H', 0, gopt_shorts('H'),
+		    gopt_longs("header"), NULL, "add file headers for the raw output"),
 	gopt_option('R', GOPT_ARG, gopt_shorts('R'),
 		    gopt_longs("rpl"), " <lsn>", "act as replica for the specified server"),
 	gopt_option('?', 0, gopt_shorts(0), gopt_longs("help"),
@@ -142,6 +146,10 @@ enum tc_opt_mode tc_opt_init(struct tc_opt *opt, int argc, char **argv)
 	if (gopt_arg(tc_options, 'M', &arg))
 		opt->format = arg;
 
+	opt->raw_with_headers = 0;
+	if (gopt(tc_options, 'H'))
+		opt->raw_with_headers = 1;
+
 	/* replica mode */
 	if (gopt_arg(tc_options, 'R', &arg)) {
 		opt->mode = TC_OPT_RPL;
@@ -155,6 +163,13 @@ enum tc_opt_mode tc_opt_init(struct tc_opt *opt, int argc, char **argv)
 		goto done;
 	}
 
+	/* wal-cat mode from stdin */
+	if (gopt(tc_options, 'I')) {
+		opt->mode = TC_OPT_WAL_CAT;
+		opt->file = NULL;
+		goto done;
+	}
+
 	/* wal-play mode */
 	if (gopt_arg(tc_options, 'P', &opt->file)) {
 		opt->mode = TC_OPT_WAL_PLAY;
diff --git a/client/tarantool/tc_opt.h b/client/tarantool/tc_opt.h
index b5e83a274a..931e95150f 100644
--- a/client/tarantool/tc_opt.h
+++ b/client/tarantool/tc_opt.h
@@ -56,6 +56,7 @@ struct tc_opt {
 	int space_set;
 	const char *format;
 	int raw;
+	int raw_with_headers;
 	void *printer;
 	const char *file;
 	char **cmdv;
diff --git a/client/tarantool/tc_print.c b/client/tarantool/tc_print.c
index a0479362a1..566034fbe8 100644
--- a/client/tarantool/tc_print.c
+++ b/client/tarantool/tc_print.c
@@ -157,6 +157,10 @@ tc_printer_tarantool(struct tnt_log_header_v11 *hdr,
 static void
 tc_printer_raw(struct tnt_log_header_v11 *hdr, struct tnt_request *r)
 {
+	if (tc.opt.raw_with_headers) {
+		fwrite(&tnt_log_marker_v11,
+		       sizeof(tnt_log_marker_v11), 1, stdout);
+	}
 	fwrite(hdr, sizeof(*hdr), 1, stdout);
 	fwrite(r->origin, r->origin_size, 1, stdout);
 }
diff --git a/client/tarantool/tc_store.c b/client/tarantool/tc_store.c
index d212df33bf..93fb58abef 100644
--- a/client/tarantool/tc_store.c
+++ b/client/tarantool/tc_store.c
@@ -126,6 +126,10 @@ static int tc_snapshot_printer(struct tnt_iter *i) {
 	struct tnt_stream_snapshot *ss =
 		TNT_SSNAPSHOT_CAST(TNT_ISTORAGE_STREAM(i));
 	if (tc.opt.raw) {
+		if (tc.opt.raw_with_headers) {
+			fwrite(&tnt_log_marker_v11,
+			       sizeof(tnt_log_marker_v11), 1, stdout);
+		}
 		fwrite(&ss->log.current.row_snap,
 		       sizeof(ss->log.current.row_snap), 1, stdout);
 		fwrite(tu->data, tu->size, 1, stdout);
@@ -176,15 +180,34 @@ static int tc_store_foreach_snapshot(tc_iter_t cb) {
 
 int tc_store_cat(void)
 {
-	switch (tnt_log_guess((char*)tc.opt.file)) {
+	enum tnt_log_type type = tnt_log_guess((char*)tc.opt.file);
+	if (type == TNT_LOG_NONE)
+		return 1;
+	int print_headers = tc.opt.raw && tc.opt.raw_with_headers;
+	if (print_headers) {
+		char *h = (type == TNT_LOG_SNAPSHOT ?
+		           TNT_LOG_MAGIC_SNAP : TNT_LOG_MAGIC_XLOG);
+		fputs(h, stdout);
+		fputs(TNT_LOG_VERSION, stdout);
+		fputs("\n", stdout);
+	}
+	int rc;
+	switch (type) {
 	case TNT_LOG_SNAPSHOT:
-		return tc_store_foreach_snapshot(tc_snapshot_printer);
+		rc = tc_store_foreach_snapshot(tc_snapshot_printer);
+		break;
 	case TNT_LOG_XLOG:
-		return tc_store_foreach_xlog(tc_store_printer);
+		rc = tc_store_foreach_xlog(tc_store_printer);
+		break;
 	case TNT_LOG_NONE:
+		rc = 1;
 		break;
 	}
-	return 1;
+	if (rc == 0 && print_headers) {
+		fwrite(&tnt_log_marker_eof_v11,
+		       sizeof(tnt_log_marker_eof_v11), 1, stdout);
+	}
+	return rc;
 }
 
 static int tc_store_resender(struct tnt_iter *i) {
diff --git a/connector/c/include/tarantool/tnt_log.h b/connector/c/include/tarantool/tnt_log.h
index cd54dd6482..72eb3f5e64 100644
--- a/connector/c/include/tarantool/tnt_log.h
+++ b/connector/c/include/tarantool/tnt_log.h
@@ -98,6 +98,9 @@ struct tnt_log {
 	int errno_;
 };
 
+extern const uint32_t tnt_log_marker_v11;
+extern const uint32_t tnt_log_marker_eof_v11;
+
 enum tnt_log_type tnt_log_guess(char *file);
 
 enum tnt_log_error
diff --git a/connector/c/tntrpl/tnt_log.c b/connector/c/tntrpl/tnt_log.c
index 5b92ff3da4..8ba1fb2198 100644
--- a/connector/c/tntrpl/tnt_log.c
+++ b/connector/c/tntrpl/tnt_log.c
@@ -43,6 +43,8 @@
 #include <connector/c/include/tarantool/tnt_log.h>
 
 enum tnt_log_type tnt_log_guess(char *file) {
+	if (file == NULL)
+		return TNT_LOG_XLOG;
 	char *ext = strrchr(file, '.');
 	if (ext == NULL)
 		return TNT_LOG_NONE;
@@ -61,8 +63,8 @@ tnt_log_seterr(struct tnt_log *l, enum tnt_log_error e) {
 	return -1;
 }
 
-static const uint32_t tnt_log_marker_v11 = 0xba0babed;
-static const uint32_t tnt_log_marker_eof_v11 = 0x10adab1e;
+const uint32_t tnt_log_marker_v11 = 0xba0babed;
+const uint32_t tnt_log_marker_eof_v11 = 0x10adab1e;
 
 inline static int
 tnt_log_eof(struct tnt_log *l, char *data) {
@@ -225,9 +227,13 @@ tnt_log_open(struct tnt_log *l, char *file, enum tnt_log_type type)
 	char *rc, *magic = "\0";
 	l->type = type;
 	/* trying to open file */
-	l->fd = fopen(file, "r");
-	if (l->fd == NULL)
-		return tnt_log_open_err(l, TNT_LOG_ESYSTEM);
+	if (file) {
+		l->fd = fopen(file, "r");
+		if (l->fd == NULL)
+			return tnt_log_open_err(l, TNT_LOG_ESYSTEM);
+	} else {
+		l->fd = stdin;
+	}
 	/* reading xlog filetype */
 	rc = fgets(filetype, sizeof(filetype), l->fd);
 	if (rc == NULL)
@@ -270,10 +276,9 @@ tnt_log_open(struct tnt_log *l, char *file, enum tnt_log_type type)
 }
 
 void tnt_log_close(struct tnt_log *l) {
-	if (l->fd) {
+	if (l->fd && l->fd != stdin)
 		fclose(l->fd);
-		l->fd = NULL;
-	}
+	l->fd = NULL;
 }
 
 enum tnt_log_error tnt_log_error(struct tnt_log *l) {
-- 
GitLab