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
install: all
cp era_copy era_apply /usr/local/bin
era_copy: era_copy.c
gcc -o era_copy -Wall era_copy.c
era_apply: era_apply.c

View File

@ -21,7 +21,7 @@
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;
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;
}
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 total = 0, prev_total = 0; // for printing progress
long long *ptr_total = NULL, *ptr_prev_total = NULL;
int r;
if (print_progress)
{
setvbuf(stderr, NULL, _IONBF, 0);
ptr_total = &total;
ptr_prev_total = &prev_total;
}
while (1)
{
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");
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;
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));
exit(1);
}
read_era_copy_and_apply(0, dst);
read_era_copy_and_apply(0, dst, print_progress);
// fsync and close
fsync(dst);
close(dst);
@ -127,16 +148,17 @@ void era_apply(char *dst_path)
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,
"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"
"\n"
"USAGE:\nera_apply DESTINATION < era_copy_output.bin\n"
"USAGE:\nera_apply [--progress] DESTINATION < era_copy_output.bin\n"
);
exit(1);
}
era_apply(args[1]);
era_apply(args[print_progress ? 2 : 1], print_progress);
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
char buf[XML_BUFSIZE] = { 0 };
char c = 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)
{
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;
length = length*era_block_size*512;
if (src >= 0)
if (offsets_len >= offsets_alloc)
{
// write a very simple binary format: SIGNATURE, start, length, data, ...
write(1, SIGNATURE, 8);
write(1, &start, 8);
write(1, &length, 8);
copy_blocks(src, 1, start, length);
}
else
{
// calculate diff size
total += length;
offsets_alloc += 4096/sizeof(long long);
offsets = (long long*)realloc(offsets, offsets_alloc*2*sizeof(long long));
}
offsets[offsets_len++] = start;
offsets[offsets_len++] = length;
// calculate diff size
total += length;
}
if (sscanf(buf, " </blocks > %c", &c) == 0 || c != 0)
{
fprintf(stderr, "</blocks> expected, but \"%s\" found\n", buf);
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;
if (src_path != NULL)
@ -108,7 +129,7 @@ void era_copy(char *src_path, int era_block_size)
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)
{
close(src);
@ -117,29 +138,30 @@ void era_copy(char *src_path, int era_block_size)
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,
"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"
"\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"
"When invoked without <DATA_DEVICE>, era_copy only calculates the future diff size and prints it\n"
"\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"
"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);
}
int bs = atoi(args[1]);
int bs = atoi(args[print_progress ? 2 : 1]);
if (bs < 1)
{
fprintf(stderr, "Incorrect era_block_size = %d\n", bs);
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;
}