summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEdward Thomson <ethomson@github.com>2016-05-02 13:59:51 -0400
committerEdward Thomson <ethomson@github.com>2016-05-02 13:59:51 -0400
commit4d384d6bbe3efc72fb212a2c5c71c8064a2cee54 (patch)
treedf228889566a8eeb149d796e65a2ee6416c86098
parentd24425fa8ea3349f2ce7087dac3cba19481cc389 (diff)
parenta97b769a0ef7fe8b301c07280c9b80233bb77643 (diff)
downloadlibgit2-4d384d6bbe3efc72fb212a2c5c71c8064a2cee54.tar.gz
Merge pull request #3759 from libgit2/cmn/faster-header
odb: avoid inflating the full delta to read the header
-rw-r--r--src/delta-apply.c31
-rw-r--r--src/delta-apply.h12
-rw-r--r--src/pack.c11
3 files changed, 48 insertions, 6 deletions
diff --git a/src/delta-apply.c b/src/delta-apply.c
index 89745faa0..6e86a81db 100644
--- a/src/delta-apply.c
+++ b/src/delta-apply.c
@@ -49,6 +49,37 @@ int git__delta_read_header(
return 0;
}
+#define DELTA_HEADER_BUFFER_LEN 16
+int git__delta_read_header_fromstream(size_t *base_sz, size_t *res_sz, git_packfile_stream *stream)
+{
+ static const size_t buffer_len = DELTA_HEADER_BUFFER_LEN;
+ unsigned char buffer[DELTA_HEADER_BUFFER_LEN];
+ const unsigned char *delta, *delta_end;
+ size_t len;
+ ssize_t read;
+
+ len = read = 0;
+ while (len < buffer_len) {
+ read = git_packfile_stream_read(stream, &buffer[len], buffer_len - len);
+
+ if (read == 0)
+ break;
+
+ if (read == GIT_EBUFS)
+ continue;
+
+ len += read;
+ }
+
+ delta = buffer;
+ delta_end = delta + len;
+ if ((hdr_sz(base_sz, &delta, delta_end) < 0) ||
+ (hdr_sz(res_sz, &delta, delta_end) < 0))
+ return -1;
+
+ return 0;
+}
+
int git__delta_apply(
git_rawobj *out,
const unsigned char *base,
diff --git a/src/delta-apply.h b/src/delta-apply.h
index d7d99d04c..eeeb78682 100644
--- a/src/delta-apply.h
+++ b/src/delta-apply.h
@@ -8,6 +8,7 @@
#define INCLUDE_delta_apply_h__
#include "odb.h"
+#include "pack.h"
/**
* Apply a git binary delta to recover the original content.
@@ -47,4 +48,15 @@ extern int git__delta_read_header(
size_t *base_sz,
size_t *res_sz);
+/**
+ * Read the header of a git binary delta
+ *
+ * This variant reads just enough from the packfile stream to read the
+ * delta header.
+ */
+extern int git__delta_read_header_fromstream(
+ size_t *base_sz,
+ size_t *res_sz,
+ git_packfile_stream *stream);
+
#endif
diff --git a/src/pack.c b/src/pack.c
index e7003e66d..6a700e29f 100644
--- a/src/pack.c
+++ b/src/pack.c
@@ -499,15 +499,14 @@ int git_packfile_resolve_header(
if (type == GIT_OBJ_OFS_DELTA || type == GIT_OBJ_REF_DELTA) {
size_t base_size;
- git_rawobj delta;
+ git_packfile_stream stream;
+
base_offset = get_delta_base(p, &w_curs, &curpos, type, offset);
git_mwindow_close(&w_curs);
- error = packfile_unpack_compressed(&delta, p, &w_curs, &curpos, size, type);
- git_mwindow_close(&w_curs);
- if (error < 0)
+ if ((error = git_packfile_stream_open(&stream, p, curpos)) < 0)
return error;
- error = git__delta_read_header(delta.data, delta.len, &base_size, size_p);
- git__free(delta.data);
+ error = git__delta_read_header_fromstream(&base_size, size_p, &stream);
+ git_packfile_stream_free(&stream);
if (error < 0)
return error;
} else