diff mbox

Diff using send-receive code / RFC

Message ID 20130210221902.GA7270@suse.de (mailing list archive)
State New, archived
Headers show

Commit Message

Arvin Schnell Feb. 10, 2013, 10:19 p.m. UTC
On Sun, Feb 10, 2013 at 10:21:31PM +0530, nafisa mandliwala wrote:
> Hello,
>         We're a team of 4 final year computer science students and are
> working on generating a diff between file system snapshots using the
> send receive code.

This was just implemented in snapper. Unfortunately I was in a
hurry so the code doesn't look so good. Instead of improving the
code in snapper (C++) I thought about implementing it in C so
that it can be included in btrfsprogs (and libbtrfs).

Here is an example:

# btrfs send -a -p /testsuite/.snapshots/1/snapshot /testsuite/.snapshots/2/snapshot | cat
At subvol /testsuite/.snapshots/2/snapshot
Comparing testsuite/.snapshots/1/snapshot and testsuite/.snapshots/2/snapshot.
+.... /foo
+.... /foo/bar
+.... /foo/bar/world

Attached you can find my current state. It's completely
unfinished and only works from some test-cases. To get it
compiled you either need some patches posted here earlier
(e.g. NO_FILE_DATA) or must make minor modifications.

But I would like to get feedback about this feature on the list.

Kind Regards,
  Arvin
diff mbox

Patch

diff --git a/cmds-send.c b/cmds-send.c
index 9b47e70..340a4d2 100644
--- a/cmds-send.c
+++ b/cmds-send.c
@@ -39,6 +39,7 @@ 
 
 #include "send.h"
 #include "send-utils.h"
+#include "send-analyser.h"
 
 static int g_verbose = 0;
 
@@ -52,6 +53,9 @@  struct btrfs_send {
 
 	char *root_path;
 	struct subvol_uuid_search sus;
+
+	int do_analyse;
+	struct btrfs_stream_analyser analyser;
 };
 
 int find_mount_root(const char *path, char **mount_root)
@@ -209,21 +213,34 @@  static void *dump_thread(void *arg_)
 	char buf[4096];
 	int readed;
 
-	while (1) {
-		readed = read(s->send_fd, buf, sizeof(buf));
-		if (readed < 0) {
-			ret = -errno;
-			fprintf(stderr, "ERROR: failed to read stream from "
+	if (!s->do_analyse)
+	{
+		while (1) {
+			readed = read(s->send_fd, buf, sizeof(buf));
+			if (readed < 0) {
+				ret = -errno;
+				fprintf(stderr, "ERROR: failed to read stream from "
 					"kernel. %s\n", strerror(-ret));
-			goto out;
+				goto out;
+			}
+			if (!readed) {
+				ret = 0;
+				goto out;
+			}
+			ret = write_buf(s->dump_fd, buf, readed);
+			if (ret < 0)
+				goto out;
 		}
-		if (!readed) {
-			ret = 0;
-			goto out;
+	}
+	else
+	{
+		while (1) {
+			ret = analyser_process(&s->analyser, s->send_fd);
+			if (ret == 0)
+				goto out;
+			if (ret < 0)
+				goto out;
 		}
-		ret = write_buf(s->dump_fd, buf, readed);
-		if (ret < 0)
-			goto out;
 	}
 
 out:
@@ -234,6 +251,31 @@  out:
 	return ERR_PTR(ret);
 }
 
+
+static void setup(struct btrfs_send *s, u64 root_id1, u64 root_id2)
+{
+	struct subvol_info *si1 = subvol_uuid_search(&s->sus, root_id1, NULL, 0,
+						     NULL, subvol_search_by_root_id);
+	assert(si1);
+	s->analyser.fd1 = open(si1->path, O_RDONLY | O_NOATIME);
+
+	struct subvol_info *si2 = subvol_uuid_search(&s->sus, root_id2, NULL, 0,
+						     NULL, subvol_search_by_root_id);
+	assert(si2);
+	s->analyser.fd2 = open(si2->path, O_RDONLY | O_NOATIME);
+
+	fprintf(stderr, "Comparing %s and %s.\n", si1->path, si2->path);
+}
+
+
+static void output(const char *path, unsigned int status, void *user)
+{
+	char *s = analyser_status_to_string(status);
+	printf("%s %s\n", s, path);
+	free(s);
+}
+
+
 static int do_send(struct btrfs_send *send, u64 root_id, u64 parent_root)
 {
 	int ret;
@@ -274,6 +316,13 @@  static int do_send(struct btrfs_send *send, u64 root_id, u64 parent_root)
 	io_send.send_fd = pipefd[1];
 	send->send_fd = pipefd[0];
 
+	if (send->do_analyse)
+	{
+		analyser_create(&send->analyser);
+		setup(send, parent_root, root_id);
+		io_send.flags = BTRFS_SEND_FLAG_NO_FILE_DATA;
+	}
+
 	if (!ret)
 		ret = pthread_create(&t_read, &t_attr, dump_thread,
 					send);
@@ -321,6 +370,11 @@  static int do_send(struct btrfs_send *send, u64 root_id, u64 parent_root)
 
 	ret = 0;
 
+	if (send->do_analyse)
+	{
+		analyser_result(&send->analyser, output, NULL);
+	}
+
 out:
 	if (subvol_fd != -1)
 		close(subvol_fd);
@@ -427,7 +481,7 @@  int cmd_send_start(int argc, char **argv)
 	memset(&send, 0, sizeof(send));
 	send.dump_fd = fileno(stdout);
 
-	while ((c = getopt(argc, argv, "vf:i:p:")) != -1) {
+	while ((c = getopt(argc, argv, "vf:i:p:a")) != -1) {
 		switch (c) {
 		case 'v':
 			g_verbose++;
@@ -468,6 +522,9 @@  int cmd_send_start(int argc, char **argv)
 				goto out;
 			}
 			break;
+		case 'a':
+			send.do_analyse = 1;
+			break;
 		case '?':
 		default:
 			fprintf(stderr, "ERROR: send args invalid.\n");
@@ -630,6 +687,7 @@  static const char * const cmd_send_usage[] = {
 	"-v               Enable verbose debug output. Each",
 	"                 occurrency of this option increases the",
 	"                 verbose level more.",
+	"-a               Analyse the stream.",
 	"-i <subvol>      Informs btrfs send that this subvolume,",
 	"                 can be taken as 'clone source'. This can",
 	"                 be used for incremental sends.",