Merge pull request #3759 from libgit2/cmn/faster-header odb: avoid inflating the full delta to read the header
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95
diff --git a/src/delta-apply.c b/src/delta-apply.c
index 89745fa..6e86a81 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 d7d99d0..eeeb786 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 e7003e6..6a700e2 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