All of lore.kernel.org
 help / color / mirror / Atom feed
* [Cluster-devel] [PATCH] mkfs.gfs2: Add a progress indicator to mkfs.gfs2
@ 2015-09-24 18:08 Paul Evans
  2015-09-25  8:38 ` Andrew Price
  0 siblings, 1 reply; 4+ messages in thread
From: Paul Evans @ 2015-09-24 18:08 UTC (permalink / raw)
  To: cluster-devel.redhat.com

Add a progress indicator to libgfs2 based on an adapted version of
the simple progress indicator used in e2fsprogs.

Update mkfs.gfs2 to make use of this progress bar allowing progress
to be reported during the creation of journals and resource groups
during filesystem creation.

Added unit tests into the test suite to validate progress bar
functions.

Signed-off-by: Paul Evans <pevans@redhat.com>
---
 gfs2/libgfs2/Makefile.am |   3 +-
 gfs2/libgfs2/libgfs2.h   |  12 ++++++
 gfs2/libgfs2/progress.c  |  90 ++++++++++++++++++++++++++++++++++++++++
 gfs2/mkfs/main_mkfs.c    |  31 ++++++++++++++
 tests/Makefile.am        |  10 ++++-
 tests/check_progress.c   | 104 +++++++++++++++++++++++++++++++++++++++++++++++
 tests/libgfs2.at         |   4 ++
 7 files changed, 252 insertions(+), 2 deletions(-)
 create mode 100644 gfs2/libgfs2/progress.c
 create mode 100644 tests/check_progress.c

diff --git a/gfs2/libgfs2/Makefile.am b/gfs2/libgfs2/Makefile.am
index 2b7aa16..25ae4f7 100644
--- a/gfs2/libgfs2/Makefile.am
+++ b/gfs2/libgfs2/Makefile.am
@@ -42,7 +42,8 @@ libgfs2_la_SOURCES = \
 	meta.c \
 	lang.c \
 	parser.y \
-	lexer.l
+	lexer.l \
+	progress.c
 
 libgfs2_la_CPPFLAGS = \
 	-D_FILE_OFFSET_BITS=64 \
diff --git a/gfs2/libgfs2/libgfs2.h b/gfs2/libgfs2/libgfs2.h
index ccae721..a500b73 100644
--- a/gfs2/libgfs2/libgfs2.h
+++ b/gfs2/libgfs2/libgfs2.h
@@ -791,6 +791,18 @@ extern int lgfs2_lang_result_print(struct lgfs2_lang_result *result);
 extern void lgfs2_lang_result_free(struct lgfs2_lang_result **result);
 extern void lgfs2_lang_free(struct lgfs2_lang_state **state);
 
+/* Progress bar functions */
+
+struct lgfs2_progress_bar {
+	uint64_t max;
+	int max_digits;
+	int skip_progress;
+};
+
+extern void lgfs2_progress_init(struct lgfs2_progress_bar *progress, uint64_t max, const char *message, int quiet);
+extern void lgfs2_progress_update(struct lgfs2_progress_bar *progress, uint64_t value);
+extern void lgfs2_progress_close(struct lgfs2_progress_bar *progress, const char *message);
+
 __END_DECLS
 
 #endif /* __LIBGFS2_DOT_H__ */
diff --git a/gfs2/libgfs2/progress.c b/gfs2/libgfs2/progress.c
new file mode 100644
index 0000000..eb41fa5
--- /dev/null
+++ b/gfs2/libgfs2/progress.c
@@ -0,0 +1,90 @@
+/**
+ * Progress bar to give updates for operations in gfs2-utils.
+ * Adapted from the simple progress bar in e2fsprogs progress.c
+ *
+ */
+
+#include <time.h>
+#include <string.h>
+
+#include "libgfs2.h"
+
+static char spaces[44], backspaces[44];
+static time_t last_update;
+
+static int number_of_digits(int value)
+{
+	int digits = 0;
+
+	do {
+		value /= 10;
+		digits++;
+	} while (value != 0);
+
+	return digits;
+}
+
+void lgfs2_progress_init(struct lgfs2_progress_bar *progress, uint64_t max, const char *message, int quiet)
+{
+	/**
+	 * NOTE:
+	 *
+	 * Default operation is to output the progress indication
+	 * in full. Although we will honor the quiet flag in the
+	 * application, if this is set we skip progress bar any
+	 * update operations and output.
+	 *
+	 */
+
+	memset(spaces, ' ', sizeof(spaces)-1);
+	spaces[sizeof(spaces)-1] = 0;
+
+	memset(backspaces, '\b', sizeof(backspaces)-1);
+	backspaces[sizeof(backspaces)-1] = 0;
+
+	memset(progress, 0, sizeof(*progress));
+
+	if (quiet) {
+		progress->skip_progress++;
+		return;
+	}
+
+	progress->max = max;
+	progress->max_digits = number_of_digits(max);
+
+	if (message) {
+		fputs(message, stdout);
+		fflush(stdout);
+	}
+	last_update = 0;
+}
+
+extern void lgfs2_progress_update(struct lgfs2_progress_bar *progress, uint64_t value)
+{
+	time_t current_time;
+
+	if (progress->skip_progress)
+		return;
+
+	current_time = time(0);
+	if (current_time == last_update)
+		return;
+	last_update = current_time;
+
+	printf("[%*"PRIu64"/%*"PRIu64"]", progress->max_digits, value,
+		progress->max_digits, progress->max);
+
+	fprintf(stdout, "%.*s", (2 * progress->max_digits) + 3, backspaces);
+}
+
+extern void lgfs2_progress_close(struct lgfs2_progress_bar *progress, const char *message)
+{
+	if (progress->skip_progress)
+		return;
+
+	fprintf(stdout, "%.*s", (2 * progress->max_digits) + 3, spaces);
+	fprintf(stdout, "%.*s", (2 * progress->max_digits) + 3, backspaces);
+
+	if (message)
+		fputs(message, stdout);
+}
diff --git a/gfs2/mkfs/main_mkfs.c b/gfs2/mkfs/main_mkfs.c
index d3d8edf..245ddba 100644
--- a/gfs2/mkfs/main_mkfs.c
+++ b/gfs2/mkfs/main_mkfs.c
@@ -653,10 +653,14 @@ static int add_rgrp(lgfs2_rgrps_t rgs, uint64_t *addr, uint32_t len, lgfs2_rgrp_
 
 static int place_journals(struct gfs2_sbd *sdp, lgfs2_rgrps_t rgs, struct mkfs_opts *opts, uint64_t *rgaddr)
 {
+	struct lgfs2_progress_bar progress;
 	uint64_t jfsize = lgfs2_space_for_data(sdp, sdp->bsize, opts->jsize << 20);
 	uint32_t rgsize = lgfs2_rgsize_for_data(jfsize, sdp->bsize);
 	unsigned j;
 
+	/* Initialise a progress bar for resource group creation. */
+	lgfs2_progress_init(&progress, opts->journals, _("\nAdding journals: "), opts->quiet);
+
 	/* We'll build the jindex later so remember where we put the journals */
 	mkfs_journals = calloc(opts->journals, sizeof(*mkfs_journals));
 	if (mkfs_journals == NULL)
@@ -668,6 +672,9 @@ static int place_journals(struct gfs2_sbd *sdp, lgfs2_rgrps_t rgs, struct mkfs_o
 		lgfs2_rgrp_t rg;
 		struct gfs2_inode in = {0};
 
+		/* Update progress bar for journal creation. */
+		lgfs2_progress_update(&progress, (j + 1));
+
 		if (opts->debug)
 			printf(_("Placing resource group for journal%u\n"), j);
 
@@ -715,12 +722,14 @@ static int place_journals(struct gfs2_sbd *sdp, lgfs2_rgrps_t rgs, struct mkfs_o
 		}
 		mkfs_journals[j] = in.i_di.di_num;
 	}
+	lgfs2_progress_close(&progress, _("Done\n"));
 
 	return 0;
 }
 
 static int place_rgrps(struct gfs2_sbd *sdp, lgfs2_rgrps_t rgs, struct mkfs_opts *opts)
 {
+        struct lgfs2_progress_bar progress;
 	uint64_t rgaddr = lgfs2_rgrp_align_addr(rgs, sdp->sb_addr + 1);
 	uint32_t rgblks = ((opts->rgsize << 20) / sdp->bsize);
 	int result;
@@ -729,6 +738,9 @@ static int place_rgrps(struct gfs2_sbd *sdp, lgfs2_rgrps_t rgs, struct mkfs_opts
 	if (result != 0)
 		return result;
 
+	/* Initialise a progress bar for resource group creation (after journal creation). */
+        lgfs2_progress_init(&progress, (opts->dev.size / sdp->bsize), _("Building resource groups: "), opts->quiet);
+
 	lgfs2_rgrps_plan(rgs, sdp->device.length - rgaddr, rgblks);
 
 	while (1) {
@@ -744,7 +756,12 @@ static int place_rgrps(struct gfs2_sbd *sdp, lgfs2_rgrps_t rgs, struct mkfs_opts
 			fprintf(stderr, _("Failed to build resource groups\n"));
 			return result;
 		}
+
+		/* Update progress bar with resource group address. */
+		lgfs2_progress_update(&progress, rgaddr);
 	}
+	lgfs2_progress_close(&progress, _("Done\n"));
+
 	return 0;
 }
 
@@ -949,11 +966,17 @@ int main(int argc, char *argv[])
 		fprintf(stderr, _("Error building '%s': %s\n"), "rindex", strerror(errno));
 		exit(EXIT_FAILURE);
 	}
+	if (!opts.quiet) {
+		printf("%s", _("Creating quota file: "));
+		fflush(stdout);
+	}
 	error = build_quota(&sbd);
 	if (error) {
 		fprintf(stderr, _("Error building '%s': %s\n"), "quota", strerror(errno));
 		exit(EXIT_FAILURE);
 	}
+	if (!opts.quiet)
+		printf("%s", _("Done\n"));
 
 	build_root(&sbd);
 	sb.sb_root_dir = sbd.md.rooti->i_di.di_num;
@@ -973,6 +996,11 @@ int main(int argc, char *argv[])
 
 	lgfs2_rgrps_free(&rgs);
 
+	if (!opts.quiet) {
+		printf("%s", _("Writing superblock and syncing: "));
+		fflush(stdout);
+	}
+
 	error = lgfs2_sb_write(&sb, opts.dev.fd, sbd.bsize);
 	if (error) {
 		perror(_("Failed to write superblock\n"));
@@ -992,6 +1020,9 @@ int main(int argc, char *argv[])
 	}
 
 	if (!opts.quiet)
+		printf("%s", _("Done\n\n"));
+
+	if (!opts.quiet)
 		print_results(&sb, &opts, sbd.rgrps, sbd.fssize);
 
 	return 0;
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 5a37319..b201448 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -14,7 +14,8 @@ CLEANFILES = testvol
 if HAVE_CHECK
 UNIT_TESTS = \
 	check_meta \
-	check_rgrp
+	check_rgrp \
+	check_progress
 UNIT_SOURCES = \
 	$(top_srcdir)/gfs2/libgfs2/libgfs2.h
 UNIT_CFLAGS = \
@@ -44,6 +45,13 @@ check_rgrp_SOURCES = \
 check_rgrp_CFLAGS = $(UNIT_CFLAGS)
 check_rgrp_LDADD = $(UNIT_LDADD)
 check_rgrp_CPPFLAGS = $(UNIT_CPPFLAGS)
+
+check_progress_SOURCES = \
+	$(UNIT_SOURCES) \
+	check_progress.c
+check_progress_CFLAGS = $(UNIT_CFLAGS)
+check_progress_LDADD = $(UNIT_LDADD)
+check_progress_CPPFLAGS = $(UNIT_CPPFLAGS)
 endif
 
 # The `:;' works around a Bash 3.2 bug when the output is not writable.
diff --git a/tests/check_progress.c b/tests/check_progress.c
new file mode 100644
index 0000000..a266788
--- /dev/null
+++ b/tests/check_progress.c
@@ -0,0 +1,104 @@
+#include <check.h>
+#include <stdint.h>
+
+#include "libgfs2.h"
+
+// TODO: Remove this when the extern is removed from libgfs2
+void print_it(const char *label, const char *fmt, const char *fmt2, ...) {}
+
+START_TEST(test_progress_init)
+{
+	struct lgfs2_progress_bar progress;
+	int quiet = 0;
+
+	lgfs2_progress_init(&progress, 15, "\nTest 0: ", quiet);
+	
+	fail_unless(progress.max == 15);
+}
+END_TEST
+
+START_TEST(test_progress_init_quiet)
+{
+	struct lgfs2_progress_bar progress;
+	int quiet = 1;
+
+	lgfs2_progress_init(&progress, 15, "\nTest 1: ", quiet);
+
+	fail_unless(progress.skip_progress == 1);
+}
+END_TEST
+
+START_TEST(test_progress_init_max)
+{
+	struct lgfs2_progress_bar progress;
+	int quiet = 0;
+
+	lgfs2_progress_init(&progress, UINT64_MAX, "\nTest 2: ", quiet);
+
+	fail_unless(progress.max == UINT64_MAX);
+}
+END_TEST
+
+START_TEST(test_progress_init_max_plus)
+{
+	struct lgfs2_progress_bar progress;
+	int quiet = 0;
+
+	lgfs2_progress_init(&progress, UINT64_MAX + 1, "\nTest 3: ", quiet);
+
+	fail_unless(progress.max == 0);
+}
+END_TEST
+
+START_TEST(test_progress_init_min)
+{
+	struct lgfs2_progress_bar progress;
+	int quiet = 0;
+
+	lgfs2_progress_init(&progress, 0, "\nTest 4: ", quiet);
+
+	fail_unless(progress.max == 0);
+}
+END_TEST
+
+START_TEST(test_progress_init_min_minus)
+{
+	struct lgfs2_progress_bar progress;
+	int quiet = 0;
+
+	lgfs2_progress_init(&progress, -1, "\nTest 4: ", quiet);
+
+	fail_unless(progress.max == UINT64_MAX);
+}
+END_TEST
+
+static Suite * libgfs2_suite(void)
+{
+
+	Suite *s = suite_create("libgfs2");
+
+	TCase *tc_progress = tcase_create("progress");
+
+	tcase_add_test(tc_progress, test_progress_init);
+	tcase_add_test(tc_progress, test_progress_init_quiet);
+	tcase_add_test(tc_progress, test_progress_init_max);
+	tcase_add_test(tc_progress, test_progress_init_max_plus);
+	tcase_add_test(tc_progress, test_progress_init_min);
+	tcase_add_test(tc_progress, test_progress_init_min_minus);
+
+	tcase_set_timeout(tc_progress, 120);
+	suite_add_tcase(s, tc_progress);
+
+	return s;
+}
+
+int main(void)
+{
+	int failures;
+	Suite *s = libgfs2_suite();
+	SRunner *sr = srunner_create(s);
+	srunner_run_all(sr, CK_NORMAL);
+	failures = srunner_ntests_failed(sr);
+	srunner_free(sr);
+	return failures ? EXIT_FAILURE : EXIT_SUCCESS;
+}
diff --git a/tests/libgfs2.at b/tests/libgfs2.at
index 1d2243c..9b258ec 100644
--- a/tests/libgfs2.at
+++ b/tests/libgfs2.at
@@ -7,3 +7,7 @@ AT_CLEANUP
 GFS_UNIT_TEST([rgrp.c],[libgfs2])
 AT_CHECK([check_rgrp], 0, [ignore], [ignore])
 AT_CLEANUP
+
+GFS_UNIT_TEST([progress.c], [libgfs2])
+AT_CHECK([check_progress], 0, [ignore], [ignore])
+AT_CLEANUP
-- 
1.9.3



^ permalink raw reply related	[flat|nested] 4+ messages in thread

* [Cluster-devel] [PATCH] mkfs.gfs2: Add a progress indicator to mkfs.gfs2
  2015-09-24 18:08 [Cluster-devel] [PATCH] mkfs.gfs2: Add a progress indicator to mkfs.gfs2 Paul Evans
@ 2015-09-25  8:38 ` Andrew Price
  2015-10-11 13:37   ` Paul Evans
  0 siblings, 1 reply; 4+ messages in thread
From: Andrew Price @ 2015-09-25  8:38 UTC (permalink / raw)
  To: cluster-devel.redhat.com

Hi Paul,

Some comments below...

On 24/09/15 19:08, Paul Evans wrote:
> Add a progress indicator to libgfs2 based on an adapted version of
> the simple progress indicator used in e2fsprogs.
>
> Update mkfs.gfs2 to make use of this progress bar allowing progress
> to be reported during the creation of journals and resource groups
> during filesystem creation.
>
> Added unit tests into the test suite to validate progress bar
> functions.
>
> Signed-off-by: Paul Evans <pevans@redhat.com>
> ---
>   gfs2/libgfs2/Makefile.am |   3 +-
>   gfs2/libgfs2/libgfs2.h   |  12 ++++++
>   gfs2/libgfs2/progress.c  |  90 ++++++++++++++++++++++++++++++++++++++++
>   gfs2/mkfs/main_mkfs.c    |  31 ++++++++++++++
>   tests/Makefile.am        |  10 ++++-
>   tests/check_progress.c   | 104 +++++++++++++++++++++++++++++++++++++++++++++++
>   tests/libgfs2.at         |   4 ++
>   7 files changed, 252 insertions(+), 2 deletions(-)
>   create mode 100644 gfs2/libgfs2/progress.c
>   create mode 100644 tests/check_progress.c
>
> diff --git a/gfs2/libgfs2/Makefile.am b/gfs2/libgfs2/Makefile.am
> index 2b7aa16..25ae4f7 100644
> --- a/gfs2/libgfs2/Makefile.am
> +++ b/gfs2/libgfs2/Makefile.am
> @@ -42,7 +42,8 @@ libgfs2_la_SOURCES = \
>   	meta.c \
>   	lang.c \
>   	parser.y \
> -	lexer.l
> +	lexer.l \
> +	progress.c
>
>   libgfs2_la_CPPFLAGS = \
>   	-D_FILE_OFFSET_BITS=64 \
> diff --git a/gfs2/libgfs2/libgfs2.h b/gfs2/libgfs2/libgfs2.h
> index ccae721..a500b73 100644
> --- a/gfs2/libgfs2/libgfs2.h
> +++ b/gfs2/libgfs2/libgfs2.h
> @@ -791,6 +791,18 @@ extern int lgfs2_lang_result_print(struct lgfs2_lang_result *result);
>   extern void lgfs2_lang_result_free(struct lgfs2_lang_result **result);
>   extern void lgfs2_lang_free(struct lgfs2_lang_state **state);
>
> +/* Progress bar functions */
> +
> +struct lgfs2_progress_bar {
> +	uint64_t max;
> +	int max_digits;
> +	int skip_progress;
> +};
> +
> +extern void lgfs2_progress_init(struct lgfs2_progress_bar *progress, uint64_t max, const char *message, int quiet);
> +extern void lgfs2_progress_update(struct lgfs2_progress_bar *progress, uint64_t value);
> +extern void lgfs2_progress_close(struct lgfs2_progress_bar *progress, const char *message);
> +
>   __END_DECLS
>
>   #endif /* __LIBGFS2_DOT_H__ */

We shouldn't put user interface code in libgfs2, so this should all be 
moved into gfs2/mkfs/ really. The API looks nice and clean to me, though.

> diff --git a/gfs2/libgfs2/progress.c b/gfs2/libgfs2/progress.c
> new file mode 100644
> index 0000000..eb41fa5
> --- /dev/null
> +++ b/gfs2/libgfs2/progress.c
> @@ -0,0 +1,90 @@
> +/**
> + * Progress bar to give updates for operations in gfs2-utils.
> + * Adapted from the simple progress bar in e2fsprogs progress.c
> + *
> + */
> +
> +#include <time.h>
> +#include <string.h>
> +
> +#include "libgfs2.h"
> +
> +static char spaces[44], backspaces[44];
> +static time_t last_update;
> +
> +static int number_of_digits(int value)
> +{
> +	int digits = 0;
> +
> +	do {
> +		value /= 10;
> +		digits++;
> +	} while (value != 0);
> +
> +	return digits;
> +}
> +
> +void lgfs2_progress_init(struct lgfs2_progress_bar *progress, uint64_t max, const char *message, int quiet)
> +{
> +	/**
> +	 * NOTE:
> +	 *
> +	 * Default operation is to output the progress indication
> +	 * in full. Although we will honor the quiet flag in the
> +	 * application, if this is set we skip progress bar any
> +	 * update operations and output.
> +	 *
> +	 */
> +
> +	memset(spaces, ' ', sizeof(spaces)-1);
> +	spaces[sizeof(spaces)-1] = 0;
> +
> +	memset(backspaces, '\b', sizeof(backspaces)-1);
> +	backspaces[sizeof(backspaces)-1] = 0;
> +
> +	memset(progress, 0, sizeof(*progress));
> +
> +	if (quiet) {
> +		progress->skip_progress++;
> +		return;
> +	}
> +
> +	progress->max = max;
> +	progress->max_digits = number_of_digits(max);
> +
> +	if (message) {
> +		fputs(message, stdout);
> +		fflush(stdout);
> +	}
> +	last_update = 0;
> +}
> +
> +extern void lgfs2_progress_update(struct lgfs2_progress_bar *progress, uint64_t value)
> +{
> +	time_t current_time;
> +
> +	if (progress->skip_progress)
> +		return;
> +
> +	current_time = time(0);
> +	if (current_time == last_update)
> +		return;
> +	last_update = current_time;
> +
> +	printf("[%*"PRIu64"/%*"PRIu64"]", progress->max_digits, value,
> +		progress->max_digits, progress->max);
> +
> +	fprintf(stdout, "%.*s", (2 * progress->max_digits) + 3, backspaces);

I tested the patch and it didn't show any progress messages for me, it 
only showed the "Done" message. stdout is line-buffered so flushing it 
at this point should fix that.

Also, when I redirected the output to a file it still printed all of the 
backspace characters (which my editor displays as ^H^H^H...) so perhaps 
it would be a good idea to skip printing the updates if 
(!isatty(STDOUT_FILENO)).

> +}
> +
> +extern void lgfs2_progress_close(struct lgfs2_progress_bar *progress, const char *message)
> +{
> +	if (progress->skip_progress)
> +		return;
> +
> +	fprintf(stdout, "%.*s", (2 * progress->max_digits) + 3, spaces);
> +	fprintf(stdout, "%.*s", (2 * progress->max_digits) + 3, backspaces);
> +
> +	if (message)
> +		fputs(message, stdout);
> +}
> diff --git a/gfs2/mkfs/main_mkfs.c b/gfs2/mkfs/main_mkfs.c
> index d3d8edf..245ddba 100644
> --- a/gfs2/mkfs/main_mkfs.c
> +++ b/gfs2/mkfs/main_mkfs.c
> @@ -653,10 +653,14 @@ static int add_rgrp(lgfs2_rgrps_t rgs, uint64_t *addr, uint32_t len, lgfs2_rgrp_
>
>   static int place_journals(struct gfs2_sbd *sdp, lgfs2_rgrps_t rgs, struct mkfs_opts *opts, uint64_t *rgaddr)
>   {
> +	struct lgfs2_progress_bar progress;
>   	uint64_t jfsize = lgfs2_space_for_data(sdp, sdp->bsize, opts->jsize << 20);
>   	uint32_t rgsize = lgfs2_rgsize_for_data(jfsize, sdp->bsize);
>   	unsigned j;
>
> +	/* Initialise a progress bar for resource group creation. */
> +	lgfs2_progress_init(&progress, opts->journals, _("\nAdding journals: "), opts->quiet);

It's a good convention to avoid putting '\n' at the beginning of 
strings, that way it's easier to keep track of who "owns" the newline so 
that they're not duplicated or omitted when different streams/levels of 
output are involved. It likely simplifies translation too. It looks like 
this is intended to leave a blank line though, and I would rather it not 
do that.

> +
>   	/* We'll build the jindex later so remember where we put the journals */
>   	mkfs_journals = calloc(opts->journals, sizeof(*mkfs_journals));
>   	if (mkfs_journals == NULL)
> @@ -668,6 +672,9 @@ static int place_journals(struct gfs2_sbd *sdp, lgfs2_rgrps_t rgs, struct mkfs_o
>   		lgfs2_rgrp_t rg;
>   		struct gfs2_inode in = {0};
>
> +		/* Update progress bar for journal creation. */
> +		lgfs2_progress_update(&progress, (j + 1));
> +
>   		if (opts->debug)
>   			printf(_("Placing resource group for journal%u\n"), j);
>
> @@ -715,12 +722,14 @@ static int place_journals(struct gfs2_sbd *sdp, lgfs2_rgrps_t rgs, struct mkfs_o
>   		}
>   		mkfs_journals[j] = in.i_di.di_num;
>   	}
> +	lgfs2_progress_close(&progress, _("Done\n"));
>
>   	return 0;
>   }
>
>   static int place_rgrps(struct gfs2_sbd *sdp, lgfs2_rgrps_t rgs, struct mkfs_opts *opts)
>   {
> +        struct lgfs2_progress_bar progress;

Should be indented with tab.

>   	uint64_t rgaddr = lgfs2_rgrp_align_addr(rgs, sdp->sb_addr + 1);
>   	uint32_t rgblks = ((opts->rgsize << 20) / sdp->bsize);
>   	int result;
> @@ -729,6 +738,9 @@ static int place_rgrps(struct gfs2_sbd *sdp, lgfs2_rgrps_t rgs, struct mkfs_opts
>   	if (result != 0)
>   		return result;
>
> +	/* Initialise a progress bar for resource group creation (after journal creation). */
> +        lgfs2_progress_init(&progress, (opts->dev.size / sdp->bsize), _("Building resource groups: "), opts->quiet);

Ditto.

> +
>   	lgfs2_rgrps_plan(rgs, sdp->device.length - rgaddr, rgblks);
>
>   	while (1) {
> @@ -744,7 +756,12 @@ static int place_rgrps(struct gfs2_sbd *sdp, lgfs2_rgrps_t rgs, struct mkfs_opts
>   			fprintf(stderr, _("Failed to build resource groups\n"));
>   			return result;
>   		}
> +
> +		/* Update progress bar with resource group address. */
> +		lgfs2_progress_update(&progress, rgaddr);

Would a running rgrp count/total be a more natural progress indicator 
than the rgrp address I wonder?

>   	}
> +	lgfs2_progress_close(&progress, _("Done\n"));
> +
>   	return 0;
>   }
>
> @@ -949,11 +966,17 @@ int main(int argc, char *argv[])
>   		fprintf(stderr, _("Error building '%s': %s\n"), "rindex", strerror(errno));
>   		exit(EXIT_FAILURE);
>   	}
> +	if (!opts.quiet) {
> +		printf("%s", _("Creating quota file: "));
> +		fflush(stdout);
> +	}
>   	error = build_quota(&sbd);
>   	if (error) {
>   		fprintf(stderr, _("Error building '%s': %s\n"), "quota", strerror(errno));
>   		exit(EXIT_FAILURE);
>   	}
> +	if (!opts.quiet)
> +		printf("%s", _("Done\n"));
>
>   	build_root(&sbd);
>   	sb.sb_root_dir = sbd.md.rooti->i_di.di_num;
> @@ -973,6 +996,11 @@ int main(int argc, char *argv[])
>
>   	lgfs2_rgrps_free(&rgs);
>
> +	if (!opts.quiet) {
> +		printf("%s", _("Writing superblock and syncing: "));
> +		fflush(stdout);
> +	}
> +
>   	error = lgfs2_sb_write(&sb, opts.dev.fd, sbd.bsize);
>   	if (error) {
>   		perror(_("Failed to write superblock\n"));
> @@ -992,6 +1020,9 @@ int main(int argc, char *argv[])
>   	}
>
>   	if (!opts.quiet)
> +		printf("%s", _("Done\n\n"));

If the second '\n' is needed, it would be better to print it separately 
so that translators only need to translate "Done\n" and not "Done\n\n" 
as well :) (But see my earlier comment on blank lines).

> +
> +	if (!opts.quiet)
>   		print_results(&sb, &opts, sbd.rgrps, sbd.fssize);

This if-statement could be merged with the previous one.

>
>   	return 0;
> diff --git a/tests/Makefile.am b/tests/Makefile.am
> index 5a37319..b201448 100644
> --- a/tests/Makefile.am
> +++ b/tests/Makefile.am
> @@ -14,7 +14,8 @@ CLEANFILES = testvol
>   if HAVE_CHECK
>   UNIT_TESTS = \
>   	check_meta \
> -	check_rgrp
> +	check_rgrp \
> +	check_progress
>   UNIT_SOURCES = \
>   	$(top_srcdir)/gfs2/libgfs2/libgfs2.h
>   UNIT_CFLAGS = \
> @@ -44,6 +45,13 @@ check_rgrp_SOURCES = \
>   check_rgrp_CFLAGS = $(UNIT_CFLAGS)
>   check_rgrp_LDADD = $(UNIT_LDADD)
>   check_rgrp_CPPFLAGS = $(UNIT_CPPFLAGS)
> +
> +check_progress_SOURCES = \
> +	$(UNIT_SOURCES) \
> +	check_progress.c
> +check_progress_CFLAGS = $(UNIT_CFLAGS)
> +check_progress_LDADD = $(UNIT_LDADD)
> +check_progress_CPPFLAGS = $(UNIT_CPPFLAGS)
>   endif
>
>   # The `:;' works around a Bash 3.2 bug when the output is not writable.
> diff --git a/tests/check_progress.c b/tests/check_progress.c
> new file mode 100644
> index 0000000..a266788
> --- /dev/null
> +++ b/tests/check_progress.c
> @@ -0,0 +1,104 @@
> +#include <check.h>
> +#include <stdint.h>
> +
> +#include "libgfs2.h"
> +
> +// TODO: Remove this when the extern is removed from libgfs2
> +void print_it(const char *label, const char *fmt, const char *fmt2, ...) {}
> +
> +START_TEST(test_progress_init)
> +{
> +	struct lgfs2_progress_bar progress;
> +	int quiet = 0;
> +
> +	lgfs2_progress_init(&progress, 15, "\nTest 0: ", quiet);
> +	
> +	fail_unless(progress.max == 15);
> +}
> +END_TEST
> +
> +START_TEST(test_progress_init_quiet)
> +{
> +	struct lgfs2_progress_bar progress;
> +	int quiet = 1;
> +
> +	lgfs2_progress_init(&progress, 15, "\nTest 1: ", quiet);
> +
> +	fail_unless(progress.skip_progress == 1);
> +}
> +END_TEST
> +
> +START_TEST(test_progress_init_max)
> +{
> +	struct lgfs2_progress_bar progress;
> +	int quiet = 0;
> +
> +	lgfs2_progress_init(&progress, UINT64_MAX, "\nTest 2: ", quiet);
> +
> +	fail_unless(progress.max == UINT64_MAX);
> +}
> +END_TEST
> +
> +START_TEST(test_progress_init_max_plus)
> +{
> +	struct lgfs2_progress_bar progress;
> +	int quiet = 0;
> +
> +	lgfs2_progress_init(&progress, UINT64_MAX + 1, "\nTest 3: ", quiet);
> +
> +	fail_unless(progress.max == 0);
> +}
> +END_TEST
> +
> +START_TEST(test_progress_init_min)
> +{
> +	struct lgfs2_progress_bar progress;
> +	int quiet = 0;
> +
> +	lgfs2_progress_init(&progress, 0, "\nTest 4: ", quiet);
> +
> +	fail_unless(progress.max == 0);
> +}
> +END_TEST
> +
> +START_TEST(test_progress_init_min_minus)
> +{
> +	struct lgfs2_progress_bar progress;
> +	int quiet = 0;
> +
> +	lgfs2_progress_init(&progress, -1, "\nTest 4: ", quiet);
> +
> +	fail_unless(progress.max == UINT64_MAX);
> +}
> +END_TEST

I appreciate the inclusion of tests but I'm not really sure what they're 
meant to be testing here. As they're all void functions (which is fine) 
there are no failure modes to test and passing the different values is 
just demonstrating that assignments are happening in progress_init, 
which should be apparent by looking at the code and the output. I guess 
checking the output of progress_update and progress_close based on what 
was passed to progress_init earlier might be useful but writing tests 
like that is probably more trouble than it's worth in this case.

Overall, I think it's a good approach and I think users will like it too.

Thanks,
Andy

> +
> +static Suite * libgfs2_suite(void)
> +{
> +
> +	Suite *s = suite_create("libgfs2");
> +
> +	TCase *tc_progress = tcase_create("progress");
> +
> +	tcase_add_test(tc_progress, test_progress_init);
> +	tcase_add_test(tc_progress, test_progress_init_quiet);
> +	tcase_add_test(tc_progress, test_progress_init_max);
> +	tcase_add_test(tc_progress, test_progress_init_max_plus);
> +	tcase_add_test(tc_progress, test_progress_init_min);
> +	tcase_add_test(tc_progress, test_progress_init_min_minus);
> +
> +	tcase_set_timeout(tc_progress, 120);
> +	suite_add_tcase(s, tc_progress);
> +
> +	return s;
> +}
> +
> +int main(void)
> +{
> +	int failures;
> +	Suite *s = libgfs2_suite();
> +	SRunner *sr = srunner_create(s);
> +	srunner_run_all(sr, CK_NORMAL);
> +	failures = srunner_ntests_failed(sr);
> +	srunner_free(sr);
> +	return failures ? EXIT_FAILURE : EXIT_SUCCESS;
> +}
> diff --git a/tests/libgfs2.at b/tests/libgfs2.at
> index 1d2243c..9b258ec 100644
> --- a/tests/libgfs2.at
> +++ b/tests/libgfs2.at
> @@ -7,3 +7,7 @@ AT_CLEANUP
>   GFS_UNIT_TEST([rgrp.c],[libgfs2])
>   AT_CHECK([check_rgrp], 0, [ignore], [ignore])
>   AT_CLEANUP
> +
> +GFS_UNIT_TEST([progress.c], [libgfs2])
> +AT_CHECK([check_progress], 0, [ignore], [ignore])
> +AT_CLEANUP
>



^ permalink raw reply	[flat|nested] 4+ messages in thread

* [Cluster-devel] [PATCH] mkfs.gfs2: Add a progress indicator to mkfs.gfs2
  2015-09-25  8:38 ` Andrew Price
@ 2015-10-11 13:37   ` Paul Evans
  2015-10-12 15:37     ` Andrew Price
  0 siblings, 1 reply; 4+ messages in thread
From: Paul Evans @ 2015-10-11 13:37 UTC (permalink / raw)
  To: cluster-devel.redhat.com

Hi Andy,

On 25/09/15 09:38, Andrew Price wrote:
> Hi Paul,
>
> Some comments below...
>
> We shouldn't put user interface code in libgfs2, so this should all be 
> moved into gfs2/mkfs/ really. The API looks nice and clean to me, though.
>

I shall move this out of libgfs2 and straight into mkfs.

> I tested the patch and it didn't show any progress messages for me, it 
> only showed the "Done" message. stdout is line-buffered so flushing it 
> at this point should fix that.
>
> Also, when I redirected the output to a file it still printed all of 
> the backspace characters (which my editor displays as ^H^H^H...) so 
> perhaps it would be a good idea to skip printing the updates if 
> (!isatty(STDOUT_FILENO)).

Cheers for pointing this out, everything seemed to be giving correct 
output without the "^H^H^H" with my default editor but on closer 
inspection with others it showed up for me also.

>
> It's a good convention to avoid putting '\n' at the beginning of 
> strings, that way it's easier to keep track of who "owns" the newline 
> so that they're not duplicated or omitted when different 
> streams/levels of output are involved. It likely simplifies 
> translation too. It looks like this is intended to leave a blank line 
> though, and I would rather it not do that.

Taken note.

>
> Would a running rgrp count/total be a more natural progress indicator 
> than the rgrp address I wonder?

I would agree that a running rgrp count/total would be a more natural 
progress but I did not see a way to check the total number of resource 
groups that were needed. It appears that the total is only known after 
all the rgrps have all been built and placed (sdp->rgrps is only updated 
after the resource group has been placed).

If I have missed out on another location to find the total number of 
resource groups to be built beforehand I am more than happy to move away 
from the rgrp address here.

>
>
> This if-statement could be merged with the previous one.
>

Agreed.

>
> I appreciate the inclusion of tests but I'm not really sure what 
> they're meant to be testing here. As they're all void functions (which 
> is fine) there are no failure modes to test and passing the different 
> values is just demonstrating that assignments are happening in 
> progress_init, which should be apparent by looking at the code and the 
> output. I guess checking the output of progress_update and 
> progress_close based on what was passed to progress_init earlier might 
> be useful but writing tests like that is probably more trouble than 
> it's worth in this case.

Yeah, on a second look through these are a little pointless in their 
current state, especially being void functions. I'll look at removing these.

>
> Overall, I think it's a good approach and I think users will like it too.
>
> Thanks,
> Andy
>

I shall work towards getting a V2 of the patch with the changed suggested.

Cheers,

Paul



^ permalink raw reply	[flat|nested] 4+ messages in thread

* [Cluster-devel] [PATCH] mkfs.gfs2: Add a progress indicator to mkfs.gfs2
  2015-10-11 13:37   ` Paul Evans
@ 2015-10-12 15:37     ` Andrew Price
  0 siblings, 0 replies; 4+ messages in thread
From: Andrew Price @ 2015-10-12 15:37 UTC (permalink / raw)
  To: cluster-devel.redhat.com

On 11/10/15 14:37, Paul Evans wrote:
> On 25/09/15 09:38, Andrew Price wrote:
>> Would a running rgrp count/total be a more natural progress indicator
>> than the rgrp address I wonder?
>
> I would agree that a running rgrp count/total would be a more natural
> progress but I did not see a way to check the total number of resource
> groups that were needed. It appears that the total is only known after
> all the rgrps have all been built and placed (sdp->rgrps is only updated
> after the resource group has been placed).
>
> If I have missed out on another location to find the total number of
> resource groups to be built beforehand I am more than happy to move away
> from the rgrp address here.

The information is available once lgfs2_rgrps_plan() has been called but 
until now it has been hidden away. I've just sent a patch to fix that by 
returning the planned rgrp count from that function instead of a rgrp 
size (which mkfs.gfs2 currently throws away).

Cheers,
Andy



^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2015-10-12 15:37 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-09-24 18:08 [Cluster-devel] [PATCH] mkfs.gfs2: Add a progress indicator to mkfs.gfs2 Paul Evans
2015-09-25  8:38 ` Andrew Price
2015-10-11 13:37   ` Paul Evans
2015-10-12 15:37     ` Andrew Price

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.