Print progress

master
Vitaliy Filippov 2019-02-20 01:02:10 +03:00
parent 2881ba7e3a
commit bbc706a5c7
3 changed files with 75 additions and 29 deletions

View File

@ -1,4 +1,6 @@
all: era_copy era_apply all: era_copy era_apply
install: all
cp era_copy era_apply /usr/local/bin
era_copy: era_copy.c era_copy: era_copy.c
gcc -o era_copy -Wall era_copy.c gcc -o era_copy -Wall era_copy.c
era_apply: era_apply.c era_apply: era_apply.c

View File

@ -21,7 +21,7 @@
static void* copy_buffer = NULL; static void* copy_buffer = NULL;
void apply_blocks(int src, int dst, off64_t start, off64_t length) void apply_blocks(int src, int dst, off64_t start, off64_t length, long long *total, long long *prev_total)
{ {
off64_t copied = 0; off64_t copied = 0;
ssize_t fact = 0, written = 0, fact_write = 0; ssize_t fact = 0, written = 0, fact_write = 0;
@ -59,13 +59,30 @@ void apply_blocks(int src, int dst, off64_t start, off64_t length)
written += fact_write; written += fact_write;
} }
copied += fact; copied += fact;
if (total != NULL)
{
*total += fact;
if (*total > *prev_total + 1048576)
{
fprintf(stderr, "\r%lld MB...", *total/1048576);
*prev_total = *total;
}
}
} }
} }
void read_era_copy_and_apply(int src, int dst) void read_era_copy_and_apply(int src, int dst, int print_progress)
{ {
long long sign = 0, start = 0, length = 0; long long sign = 0, start = 0, length = 0;
long long total = 0, prev_total = 0; // for printing progress
long long *ptr_total = NULL, *ptr_prev_total = NULL;
int r; int r;
if (print_progress)
{
setvbuf(stderr, NULL, _IONBF, 0);
ptr_total = &total;
ptr_prev_total = &prev_total;
}
while (1) while (1)
{ {
r = read(src, &sign, 8); r = read(src, &sign, 8);
@ -88,11 +105,15 @@ void read_era_copy_and_apply(int src, int dst)
fprintf(stderr, "era_copy signature does not match\n"); fprintf(stderr, "era_copy signature does not match\n");
exit(1); exit(1);
} }
apply_blocks(src, dst, start, length); apply_blocks(src, dst, start, length, ptr_total, ptr_prev_total);
}
if (print_progress)
{
fprintf(stderr, "\n");
} }
} }
void era_apply(char *dst_path) void era_apply(char *dst_path, int print_progress)
{ {
struct stat sb; struct stat sb;
int dst, flags = O_WRONLY | O_LARGEFILE; int dst, flags = O_WRONLY | O_LARGEFILE;
@ -119,7 +140,7 @@ void era_apply(char *dst_path)
fprintf(stderr, "Failed to open %s for writing: %s\n", dst_path, strerror(errno)); fprintf(stderr, "Failed to open %s for writing: %s\n", dst_path, strerror(errno));
exit(1); exit(1);
} }
read_era_copy_and_apply(0, dst); read_era_copy_and_apply(0, dst, print_progress);
// fsync and close // fsync and close
fsync(dst); fsync(dst);
close(dst); close(dst);
@ -127,16 +148,17 @@ void era_apply(char *dst_path)
int main(int narg, char *args[]) int main(int narg, char *args[])
{ {
if (narg < 2) int print_progress = 0;
if (narg < 2 || ((print_progress = !strcmp(args[1], "--progress")) && narg < 3))
{ {
fprintf(stderr, fprintf(stderr,
"era_apply - applies era_copy output to a file or block device\n" "era_apply - applies era_copy output to a file or block device\n"
"(c) Vitaliy Filippov, 2019+, distributed under the terms of GNU GPLv3.0 or later license\n" "(c) Vitaliy Filippov, 2019+, distributed under the terms of GNU GPLv3.0 or later license\n"
"\n" "\n"
"USAGE:\nera_apply DESTINATION < era_copy_output.bin\n" "USAGE:\nera_apply [--progress] DESTINATION < era_copy_output.bin\n"
); );
exit(1); exit(1);
} }
era_apply(args[1]); era_apply(args[print_progress ? 2 : 1], print_progress);
return 0; return 0;
} }

View File

@ -39,12 +39,14 @@ void copy_blocks(int src, int dst, off64_t start, off64_t length)
} }
} }
void read_era_invalidate_and_copy(FILE *fp, int src, int era_block_size) void read_era_invalidate_and_copy(FILE *fp, int src, int era_block_size, int print_progress)
{ {
// read input XML // read input XML
char buf[XML_BUFSIZE] = { 0 }; char buf[XML_BUFSIZE] = { 0 };
char c = 0; char c = 0;
long long start = 0, length = 0, total = 0; long long start = 0, length = 0, total = 0;
long long *offsets = NULL;
int i, offsets_alloc = 0, offsets_len = 0;
if (fgets(buf, XML_BUFSIZE, fp) == NULL) if (fgets(buf, XML_BUFSIZE, fp) == NULL)
{ {
fprintf(stderr, "Input block list is empty\n"); fprintf(stderr, "Input block list is empty\n");
@ -71,32 +73,51 @@ void read_era_invalidate_and_copy(FILE *fp, int src, int era_block_size)
} }
start = start*era_block_size*512; start = start*era_block_size*512;
length = length*era_block_size*512; length = length*era_block_size*512;
if (src >= 0) if (offsets_len >= offsets_alloc)
{ {
// write a very simple binary format: SIGNATURE, start, length, data, ... offsets_alloc += 4096/sizeof(long long);
write(1, SIGNATURE, 8); offsets = (long long*)realloc(offsets, offsets_alloc*2*sizeof(long long));
write(1, &start, 8);
write(1, &length, 8);
copy_blocks(src, 1, start, length);
}
else
{
// calculate diff size
total += length;
} }
offsets[offsets_len++] = start;
offsets[offsets_len++] = length;
// calculate diff size
total += length;
} }
if (sscanf(buf, " </blocks > %c", &c) == 0 || c != 0) if (sscanf(buf, " </blocks > %c", &c) == 0 || c != 0)
{ {
fprintf(stderr, "</blocks> expected, but \"%s\" found\n", buf); fprintf(stderr, "</blocks> expected, but \"%s\" found\n", buf);
exit(1); exit(1);
} }
if (src < 0) if (src >= 0)
{ {
printf("%lld bytes\n", total); long long copied = 0, prev_copied = 0;
if (print_progress)
{
setvbuf(stderr, NULL, _IONBF, 0);
}
for (i = 0; i < offsets_len; i += 2)
{
if (print_progress && (!copied || copied >= prev_copied + 1048576))
{
fprintf(stderr, "\rDone %lld MB / %lld MB, copying next %lld MB...", copied/1048576, total/1048576, offsets[i+1]/1048576);
prev_copied = copied;
}
// write a very simple binary format: SIGNATURE, start, length, data, ...
write(1, SIGNATURE, 8);
write(1, offsets+i, 8);
write(1, offsets+i+1, 8);
copy_blocks(src, 1, offsets[i], offsets[i+1]);
copied += offsets[i+1];
}
fprintf(stderr, "\n");
}
else
{
printf("%lld bytes to copy\n", total);
} }
} }
void era_copy(char *src_path, int era_block_size) void era_copy(char *src_path, int era_block_size, int print_progress)
{ {
int src = -1; int src = -1;
if (src_path != NULL) if (src_path != NULL)
@ -108,7 +129,7 @@ void era_copy(char *src_path, int era_block_size)
exit(1); exit(1);
} }
} }
read_era_invalidate_and_copy(stdin, src, era_block_size); read_era_invalidate_and_copy(stdin, src, era_block_size, print_progress);
if (src_path != NULL) if (src_path != NULL)
{ {
close(src); close(src);
@ -117,29 +138,30 @@ void era_copy(char *src_path, int era_block_size)
int main(int narg, char *args[]) int main(int narg, char *args[])
{ {
if (narg < 2) int print_progress = 0;
if (narg < 2 || ((print_progress = !strcmp(args[1], "--progress")) && narg < 3))
{ {
fprintf(stderr, fprintf(stderr,
"era_copy - parses era_invalidate output and saves changed blocks to a stream\n" "era_copy - parses era_invalidate output and saves changed blocks to a stream\n"
"(c) Vitaliy Filippov, 2019+, distributed under the terms of GNU GPLv3.0 or later license\n" "(c) Vitaliy Filippov, 2019+, distributed under the terms of GNU GPLv3.0 or later license\n"
"\n" "\n"
"USAGE:\nera_invalidate --metadata-snapshot --written-since <ERA> <META_DEVICE> |\\\n" "USAGE:\nera_invalidate --metadata-snapshot --written-since <ERA> <META_DEVICE> |\\\n"
" era_copy <ERA_BLOCK_SIZE> [<DATA_DEVICE>] > era_copy.bin\n" " era_copy [--progress] <ERA_BLOCK_SIZE> [<DATA_DEVICE>] > era_copy.bin\n"
"\n" "\n"
"When invoked without <DATA_DEVICE>, era_copy only calculates the future diff size and prints it\n" "When invoked without <DATA_DEVICE>, era_copy only calculates the future diff size and prints it\n"
"\n" "\n"
"ERA_BLOCK_SIZE is dm-era's granularity in 512-byte sectors you used when creating dm-era device\n" "ERA_BLOCK_SIZE is dm-era's granularity in 512-byte sectors you used when creating dm-era device\n"
"You can take it from `dmsetup table <DATA_DEVICE>`: it's the last number in DM table\n" "You can take it from `dmsetup table <DATA_DEVICE>`: it's the last number in DM table\n"
"For example, in `0 3625546496 era 259:3 259:2 65536` it's 65536\n" "For example, in `0 3625546496 era 259:3 259:2 1024` it's 1024\n"
); );
exit(1); exit(1);
} }
int bs = atoi(args[1]); int bs = atoi(args[print_progress ? 2 : 1]);
if (bs < 1) if (bs < 1)
{ {
fprintf(stderr, "Incorrect era_block_size = %d\n", bs); fprintf(stderr, "Incorrect era_block_size = %d\n", bs);
exit(1); exit(1);
} }
era_copy(narg == 2 ? NULL : args[2], bs); era_copy(narg == (print_progress ? 3 : 2) ? NULL : args[print_progress ? 3 : 2], bs, print_progress);
return 0; return 0;
} }