[PATCH 11/16] vcs-svn: Add code to maintain a sliding view of a file

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Subversion's delta format has the convenient property that applying
each section of the delta only requires examining (and keeping in
memory) a small portion of the preimage.  At any moment, this portion
begins at a well-defined file offset and has a well-defined length,
and as the delta is applied, it moves from the beginning to the end
of the file.  Add a move_window() function to keep track of such a
window into a file.

You can use it like this:

	struct line_buffer preimage = LINE_BUFFER_INIT;
	buffer_init(&preimage, NULL);
	struct view window = {&preimage, 0, STRBUF_INIT};
	move_window(&window, 3, 7);	/* (1) */
	move_window(&window, 5, 5);	/* (2) */
	move_window(&window, 12, 2);	/* (3) */
	strbuf_release(&window.buf);
	buffer_deinit(&preimage);

In this example: (1) reads 10 bytes and discards the first 3;
(2) discards the first 2, which are not needed any more; and (3)
skips 2 bytes and reads 2 new bytes to work with.

Whenever move_window() returns, the file position indicator is at
position window->off + window->buf.len and the data from positions
window->off to the current file position are stored in window->buf.

This function does only sequential access and never seeks, so it
can be safely used on pipes and sockets.

On end-of-file, move_window() just silently reads less than the
caller requested.  On other errors, it prints a message to stderr
and returns -1.

Helped-by: David Barr <david.barr@xxxxxxxxxxxx>
Signed-off-by: Jonathan Nieder <jrnieder@xxxxxxxxx>
---
 Makefile                 |    5 ++-
 vcs-svn/sliding_window.c |   65 ++++++++++++++++++++++++++++++++++++++++++++++
 vcs-svn/sliding_window.h |   14 ++++++++++
 vcs-svn/LICENSE          |    2 +
 4 files changed, 84 insertions(+), 2 deletions(-)
 create mode 100644 vcs-svn/sliding_window.c
 create mode 100644 vcs-svn/sliding_window.h

diff --git a/Makefile b/Makefile
index 1f1ce04..d99da33 100644
--- a/Makefile
+++ b/Makefile
@@ -1765,7 +1765,8 @@ endif
 XDIFF_OBJS = xdiff/xdiffi.o xdiff/xprepare.o xdiff/xutils.o xdiff/xemit.o \
 	xdiff/xmerge.o xdiff/xpatience.o
 VCSSVN_OBJS = vcs-svn/string_pool.o vcs-svn/line_buffer.o \
-	vcs-svn/repo_tree.o vcs-svn/fast_export.o vcs-svn/svndump.o
+	vcs-svn/repo_tree.o vcs-svn/fast_export.o vcs-svn/svndump.o \
+	vcs-svn/sliding_window.o
 OBJECTS := $(GIT_OBJS) $(XDIFF_OBJS) $(VCSSVN_OBJS)
 
 dep_files := $(foreach f,$(OBJECTS),$(dir $f).depend/$(notdir $f).d)
@@ -1892,7 +1893,7 @@ xdiff-interface.o $(XDIFF_OBJS): \
 $(VCSSVN_OBJS): \
 	vcs-svn/obj_pool.h vcs-svn/trp.h vcs-svn/string_pool.h \
 	vcs-svn/line_buffer.h vcs-svn/repo_tree.h vcs-svn/fast_export.h \
-	vcs-svn/svndump.h
+	vcs-svn/svndump.h vcs-svn/sliding_window.h
 endif
 
 exec_cmd.s exec_cmd.o: EXTRA_CPPFLAGS = \
diff --git a/vcs-svn/sliding_window.c b/vcs-svn/sliding_window.c
new file mode 100644
index 0000000..8273970
--- /dev/null
+++ b/vcs-svn/sliding_window.c
@@ -0,0 +1,65 @@
+/*
+ * Licensed under a two-clause BSD-style license.
+ * See LICENSE for details.
+ */
+
+#include "git-compat-util.h"
+#include "sliding_window.h"
+#include "line_buffer.h"
+#include "strbuf.h"
+
+static void strbuf_remove_from_left(struct strbuf *sb, size_t nbytes)
+{
+	assert(nbytes <= sb->len);
+	memmove(sb->buf, sb->buf + nbytes, sb->len - nbytes);
+	strbuf_setlen(sb, sb->len - nbytes);
+}
+
+static int check_overflow(off_t a, size_t b)
+{
+	if ((off_t) b < 0)
+		return error("Unrepresentable length: "
+				"%"PRIu64" > OFF_MAX", (uint64_t) b);
+	if (signed_add_overflows(a, (off_t) b))
+		return error("Unrepresentable offset: "
+				"%"PRIu64" + %"PRIu64" > OFF_MAX",
+				(uint64_t) a, (uint64_t) b);
+	return 0;
+}
+
+int move_window(struct view *view, off_t off, size_t len)
+{
+	off_t file_offset;
+	assert(view && view->file);
+	assert(!check_overflow(view->off, view->buf.len));
+
+	if (check_overflow(off, len))
+		return -1;
+	if (off < view->off || off + len < view->off + view->buf.len)
+		return error("Invalid delta: window slides left");
+
+	file_offset = view->off + view->buf.len;
+	if (off < file_offset)
+		/* Move the overlapping region into place. */
+		strbuf_remove_from_left(&view->buf, off - view->off);
+	else
+		strbuf_setlen(&view->buf, 0);
+	if (off > file_offset) {
+		/* Seek ahead to skip the gap. */
+		const off_t gap = off - file_offset;
+		const off_t nread = buffer_skip_bytes(view->file, gap);
+		if (nread != gap) {
+			if (!buffer_ferror(view->file))	/* View ends early. */
+				goto done;
+			return error("Cannot seek forward in input: %s",
+				     strerror(errno));
+		}
+		file_offset += gap;
+	}
+	buffer_read_binary(&view->buf, len - view->buf.len, view->file);
+	if (buffer_ferror(view->file))
+		return error("Cannot read preimage: %s", strerror(errno));
+ done:
+	view->off = off;
+	return 0;
+}
diff --git a/vcs-svn/sliding_window.h b/vcs-svn/sliding_window.h
new file mode 100644
index 0000000..b9f0552
--- /dev/null
+++ b/vcs-svn/sliding_window.h
@@ -0,0 +1,14 @@
+#ifndef SLIDING_WINDOW_H_
+#define SLIDING_WINDOW_H_
+
+#include "strbuf.h"
+
+struct view {
+	struct line_buffer *file;
+	off_t off;
+	struct strbuf buf;
+};
+
+extern int move_window(struct view *view, off_t off, size_t len);
+
+#endif
diff --git a/vcs-svn/LICENSE b/vcs-svn/LICENSE
index 0a5e3c4..805882c 100644
--- a/vcs-svn/LICENSE
+++ b/vcs-svn/LICENSE
@@ -1,6 +1,8 @@
 Copyright (C) 2010 David Barr <david.barr@xxxxxxxxxxxx>.
 All rights reserved.
 
+Copyright (C) 2010 Jonathan Nieder <jrnieder@xxxxxxxxx>.
+
 Copyright (C) 2008 Jason Evans <jasone@xxxxxxxxxxxxx>.
 All rights reserved.
 
-- 
1.7.2.3

--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[Index of Archives]     [Linux Kernel Development]     [Gcc Help]     [IETF Annouce]     [DCCP]     [Netdev]     [Networking]     [Security]     [V4L]     [Bugtraq]     [Yosemite]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux SCSI]     [Fedora Users]