mirror of
https://git.proxmox.com/git/libgit2
synced 2025-05-21 14:39:10 +00:00
odb: avoid inflating the full delta to read the header
When we read the header, we want to know the size and type of the object. We're currently inflating the full delta in order to read the first few bytes. This can mean hundreds of kB needlessly inflated for large objects. Instead use a packfile stream to read just enough so we can read the two varints in the header and avoid inflating most of the delta.
This commit is contained in:
parent
88284dfb79
commit
a97b769a0e
@ -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,
|
||||
|
@ -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
|
||||
|
11
src/pack.c
11
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
|
||||
|
Loading…
Reference in New Issue
Block a user