mirror of
https://git.proxmox.com/git/libgit2
synced 2025-05-29 12:24:11 +00:00
Factor out the mmap window code
This code is useful for more things than just the packfile handling code. Factor it out so it can be reused. Signed-off-by: Carlos Martín Nieto <carlos@cmartin.tk>
This commit is contained in:
parent
03d88ed415
commit
7bfdb3d22b
271
src/mwindow.c
Normal file
271
src/mwindow.c
Normal file
@ -0,0 +1,271 @@
|
||||
/*
|
||||
* This file is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License, version 2,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* In addition to the permissions in the GNU General Public License,
|
||||
* the authors give you unlimited permission to link the compiled
|
||||
* version of this file into combinations with other programs,
|
||||
* and to distribute those combinations without any restriction
|
||||
* coming from the use of this file. (The General Public License
|
||||
* restrictions do apply in other respects; for example, they cover
|
||||
* modification of the file, and distribution when not linked into
|
||||
* a combined executable.)
|
||||
*
|
||||
* This file is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; see the file COPYING. If not, write to
|
||||
* the Free Software Foundation, 51 Franklin Street, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include "common.h"
|
||||
#include "mwindow.h"
|
||||
#include "vector.h"
|
||||
#include "fileops.h"
|
||||
#include "map.h"
|
||||
|
||||
#define DEFAULT_WINDOW_SIZE \
|
||||
(sizeof(void*) >= 8 \
|
||||
? 1 * 1024 * 1024 * 1024 \
|
||||
: 32 * 1024 * 1024)
|
||||
|
||||
#define DEFAULT_MAPPED_LIMIT \
|
||||
((1024L * 1024L) * (sizeof(void*) >= 8 ? 8192 : 256))
|
||||
|
||||
/*
|
||||
* We need this because each process is only allowed a specific amount
|
||||
* of memory. Making it writable should generate one instance per
|
||||
* process, but we still need to set a couple of variables.
|
||||
*/
|
||||
|
||||
static git_mwindow_ctl ctl = {
|
||||
.window_size = DEFAULT_WINDOW_SIZE,
|
||||
.mapped_limit = DEFAULT_MAPPED_LIMIT
|
||||
};
|
||||
|
||||
/*
|
||||
* Free all the windows in a sequence, typically because we're done
|
||||
* with the file
|
||||
*/
|
||||
void git_mwindow_free_all(git_mwindow_file *mwf)
|
||||
{
|
||||
unsigned int i;
|
||||
/*
|
||||
* Remove these windows from the global list
|
||||
*/
|
||||
for (i = 0; i < ctl.windowfiles.length; ++i){
|
||||
if (git_vector_get(&ctl.windowfiles, i) == mwf) {
|
||||
git_vector_remove(&ctl.windowfiles, i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (ctl.windowfiles.length == 0) {
|
||||
git_vector_free(&ctl.windowfiles);
|
||||
ctl.windowfiles.contents = NULL;
|
||||
}
|
||||
|
||||
while (mwf->windows) {
|
||||
git_mwindow *w = mwf->windows;
|
||||
assert(w->inuse_cnt == 0);
|
||||
|
||||
ctl.mapped -= w->window_map.len;
|
||||
ctl.open_windows--;
|
||||
|
||||
git_futils_mmap_free(&w->window_map);
|
||||
|
||||
mwf->windows = w->next;
|
||||
free(w);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Check if a window 'win' contains the address 'offset'
|
||||
*/
|
||||
int git_mwindow_contains(git_mwindow *win, off_t offset)
|
||||
{
|
||||
off_t win_off = win->offset;
|
||||
return win_off <= offset
|
||||
&& offset <= (off_t)(win_off + win->window_map.len);
|
||||
}
|
||||
|
||||
/*
|
||||
* Find the least-recently-used window in a file
|
||||
*/
|
||||
void git_mwindow_scan_lru(
|
||||
git_mwindow_file *mwf,
|
||||
git_mwindow **lru_w,
|
||||
git_mwindow **lru_l)
|
||||
{
|
||||
git_mwindow *w, *w_l;
|
||||
|
||||
for (w_l = NULL, w = mwf->windows; w; w = w->next) {
|
||||
if (!w->inuse_cnt) {
|
||||
/*
|
||||
* If the current one is more recent than the last one,
|
||||
* store it in the output parameter. If lru_w is NULL,
|
||||
* it's the first loop, so store it as well.
|
||||
*/
|
||||
if (!*lru_w || w->last_used < (*lru_w)->last_used) {
|
||||
*lru_w = w;
|
||||
*lru_l = w_l;
|
||||
}
|
||||
}
|
||||
w_l = w;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Close the least recently used window. You should check to see if
|
||||
* the file descriptors need closing from time to time.
|
||||
*/
|
||||
int git_mwindow_close_lru(git_mwindow_file *mwf)
|
||||
{
|
||||
unsigned int i;
|
||||
git_mwindow *lru_w = NULL, *lru_l = NULL;
|
||||
|
||||
/* FIMXE: Does this give us any advantage? */
|
||||
if(mwf->windows)
|
||||
git_mwindow_scan_lru(mwf, &lru_w, &lru_l);
|
||||
|
||||
for (i = 0; i < ctl.windowfiles.length; ++i) {
|
||||
git_mwindow_scan_lru(git_vector_get(&ctl.windowfiles, i), &lru_w, &lru_l);
|
||||
}
|
||||
|
||||
if (lru_w) {
|
||||
git_mwindow_close(&lru_w);
|
||||
ctl.mapped -= lru_w->window_map.len;
|
||||
git_futils_mmap_free(&lru_w->window_map);
|
||||
|
||||
if (lru_l)
|
||||
lru_l->next = lru_w->next;
|
||||
else
|
||||
mwf->windows = lru_w->next;
|
||||
|
||||
free(lru_w);
|
||||
ctl.open_windows--;
|
||||
|
||||
return GIT_SUCCESS;
|
||||
}
|
||||
|
||||
return git__throw(GIT_ERROR, "Failed to close memory window. Couln't find LRU");
|
||||
}
|
||||
|
||||
static git_mwindow *new_window(git_mwindow_file *mwf, git_file fd, size_t size, off_t offset)
|
||||
{
|
||||
size_t walign = ctl.window_size / 2;
|
||||
size_t len;
|
||||
git_mwindow *w;
|
||||
|
||||
w = git__malloc(sizeof(*w));
|
||||
if (w == NULL)
|
||||
return w;
|
||||
|
||||
memset(w, 0x0, sizeof(*w));
|
||||
w->offset = (offset / walign) * walign;
|
||||
|
||||
len = size - w->offset;
|
||||
if (len > ctl.window_size)
|
||||
len = ctl.window_size;
|
||||
|
||||
ctl.mapped += len;
|
||||
|
||||
while(ctl.mapped_limit < ctl.mapped &&
|
||||
git_mwindow_close_lru(mwf) == GIT_SUCCESS) {}
|
||||
|
||||
/* FIXME: Shouldn't we error out if there's an error in closing lru? */
|
||||
|
||||
if (git_futils_mmap_ro(&w->window_map, fd, w->offset, len) < GIT_SUCCESS)
|
||||
goto cleanup;
|
||||
|
||||
ctl.mmap_calls++;
|
||||
ctl.open_windows++;
|
||||
|
||||
if (ctl.mapped > ctl.peak_mapped)
|
||||
ctl.peak_mapped = ctl.mapped;
|
||||
|
||||
if (ctl.open_windows > ctl.peak_open_windows)
|
||||
ctl.peak_open_windows = ctl.open_windows;
|
||||
|
||||
return w;
|
||||
|
||||
cleanup:
|
||||
free(w);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Open a new window, closing the least recenty used until we have
|
||||
* enough space. Don't forget to add it to your list
|
||||
*/
|
||||
unsigned char *git_mwindow_open(git_mwindow_file *mwf, git_mwindow **cursor, git_file fd,
|
||||
size_t size, off_t offset, int extra, unsigned int *left)
|
||||
{
|
||||
git_mwindow *w = *cursor;
|
||||
|
||||
if (!w || !git_mwindow_contains(w, offset + extra)) {
|
||||
if (w) {
|
||||
w->inuse_cnt--;
|
||||
}
|
||||
|
||||
for (w = mwf->windows; w; w = w->next) {
|
||||
if (git_mwindow_contains(w, offset + extra))
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* If there isn't a suitable window, we need to create a new
|
||||
* one.
|
||||
*/
|
||||
if (!w) {
|
||||
w = new_window(mwf, fd, size, offset);
|
||||
if (w == NULL)
|
||||
return NULL;
|
||||
w->next = mwf->windows;
|
||||
mwf->windows = w;
|
||||
}
|
||||
}
|
||||
|
||||
/* If we changed w, store it in the cursor */
|
||||
if (w != *cursor) {
|
||||
w->last_used = ctl.used_ctr++;
|
||||
w->inuse_cnt++;
|
||||
*cursor = w;
|
||||
}
|
||||
|
||||
offset -= w->offset;
|
||||
assert(git__is_sizet(offset));
|
||||
|
||||
if (left)
|
||||
*left = w->window_map.len - offset;
|
||||
|
||||
return (unsigned char *) w->window_map.data + offset;
|
||||
|
||||
free(w);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int git_mwindow_file_register(git_mwindow_file *mwf)
|
||||
{
|
||||
int error;
|
||||
|
||||
if (ctl.windowfiles.length == 0 &&
|
||||
(error = git_vector_init(&ctl.windowfiles, 8, NULL)) < GIT_SUCCESS)
|
||||
return error;
|
||||
|
||||
return git_vector_insert(&ctl.windowfiles, mwf);
|
||||
}
|
||||
|
||||
void git_mwindow_close(git_mwindow **window)
|
||||
{
|
||||
git_mwindow *w = *window;
|
||||
if (w) {
|
||||
w->inuse_cnt--;
|
||||
*window = NULL;
|
||||
}
|
||||
}
|
64
src/mwindow.h
Normal file
64
src/mwindow.h
Normal file
@ -0,0 +1,64 @@
|
||||
/*
|
||||
* This file is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License, version 2,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* In addition to the permissions in the GNU General Public License,
|
||||
* the authors give you unlimited permission to link the compiled
|
||||
* version of this file into combinations with other programs,
|
||||
* and to distribute those combinations without any restriction
|
||||
* coming from the use of this file. (The General Public License
|
||||
* restrictions do apply in other respects; for example, they cover
|
||||
* modification of the file, and distribution when not linked into
|
||||
* a combined executable.)
|
||||
*
|
||||
* This file is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; see the file COPYING. If not, write to
|
||||
* the Free Software Foundation, 51 Franklin Street, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef INCLUDE_mwindow__
|
||||
#define INCLUDE_mwindow__
|
||||
|
||||
#include "map.h"
|
||||
#include "vector.h"
|
||||
#include "fileops.h"
|
||||
|
||||
typedef struct git_mwindow {
|
||||
struct git_mwindow *next;
|
||||
git_map window_map;
|
||||
off_t offset;
|
||||
unsigned int last_used;
|
||||
unsigned int inuse_cnt;
|
||||
} git_mwindow;
|
||||
|
||||
typedef struct git_mwindow_file {
|
||||
git_mwindow *windows;
|
||||
} git_mwindow_file;
|
||||
|
||||
typedef struct git_mwindow_ctl {
|
||||
size_t mapped;
|
||||
unsigned int open_windows;
|
||||
size_t window_size; /* needs default value */
|
||||
size_t mapped_limit; /* needs default value */
|
||||
unsigned int mmap_calls;
|
||||
unsigned int peak_open_windows;
|
||||
size_t peak_mapped;
|
||||
size_t used_ctr;
|
||||
git_vector windowfiles;
|
||||
} git_mwindow_ctl;
|
||||
|
||||
int git_mwindow_contains(git_mwindow *win, off_t offset);
|
||||
void git_mwindow_free_all(git_mwindow_file *mwf);
|
||||
unsigned char *git_mwindow_open(git_mwindow_file *mwf, git_mwindow **cursor, git_file fd, size_t size, off_t offset, int extra, unsigned int *left);
|
||||
void git_mwindow_scan_lru(git_mwindow_file *mwf, git_mwindow **lru_w, git_mwindow **lru_l);
|
||||
int git_mwindow_file_register(git_mwindow_file *mwf);
|
||||
void git_mwindow_close(git_mwindow **w_cursor);
|
||||
|
||||
#endif
|
262
src/odb_pack.c
262
src/odb_pack.c
@ -32,17 +32,10 @@
|
||||
#include "odb.h"
|
||||
#include "delta-apply.h"
|
||||
#include "sha1_lookup.h"
|
||||
#include "mwindow.h"
|
||||
|
||||
#include "git2/odb_backend.h"
|
||||
|
||||
#define DEFAULT_WINDOW_SIZE \
|
||||
(sizeof(void*) >= 8 \
|
||||
? 1 * 1024 * 1024 * 1024 \
|
||||
: 32 * 1024 * 1024)
|
||||
|
||||
#define DEFAULT_MAPPED_LIMIT \
|
||||
((1024L * 1024L) * (sizeof(void*) >= 8 ? 8192 : 256))
|
||||
|
||||
#define PACK_SIGNATURE 0x5041434b /* "PACK" */
|
||||
#define PACK_VERSION 2
|
||||
#define pack_version_ok(v) ((v) == htonl(2) || (v) == htonl(3))
|
||||
@ -76,18 +69,11 @@ struct pack_idx_header {
|
||||
uint32_t idx_version;
|
||||
};
|
||||
|
||||
struct pack_window {
|
||||
struct pack_window *next;
|
||||
git_map window_map;
|
||||
off_t offset;
|
||||
unsigned int last_used;
|
||||
unsigned int inuse_cnt;
|
||||
};
|
||||
|
||||
struct pack_file {
|
||||
struct pack_window *windows;
|
||||
int pack_fd;
|
||||
git_mwindow_file mwf;
|
||||
//git_mwindow *windows;
|
||||
off_t pack_size;
|
||||
|
||||
git_map index_map;
|
||||
|
||||
uint32_t num_objects;
|
||||
@ -96,7 +82,6 @@ struct pack_file {
|
||||
|
||||
int index_version;
|
||||
git_time_t mtime;
|
||||
int pack_fd;
|
||||
unsigned pack_local:1, pack_keep:1;
|
||||
git_oid sha1;
|
||||
|
||||
@ -116,19 +101,6 @@ struct pack_backend {
|
||||
struct pack_file *last_found;
|
||||
char *pack_folder;
|
||||
time_t pack_folder_mtime;
|
||||
|
||||
size_t window_size; /* needs default value */
|
||||
|
||||
size_t mapped_limit; /* needs default value */
|
||||
size_t peak_mapped;
|
||||
size_t mapped;
|
||||
|
||||
size_t used_ctr;
|
||||
|
||||
unsigned int peak_open_windows;
|
||||
unsigned int open_windows;
|
||||
|
||||
unsigned int mmap_calls;
|
||||
};
|
||||
|
||||
/**
|
||||
@ -226,8 +198,6 @@ struct pack_backend {
|
||||
*/
|
||||
|
||||
|
||||
|
||||
|
||||
/***********************************************************
|
||||
*
|
||||
* FORWARD DECLARATIONS
|
||||
@ -235,19 +205,10 @@ struct pack_backend {
|
||||
***********************************************************/
|
||||
|
||||
static void pack_window_free_all(struct pack_backend *backend, struct pack_file *p);
|
||||
static int pack_window_contains(struct pack_window *win, off_t offset);
|
||||
static int pack_window_contains(git_mwindow *win, off_t offset);
|
||||
|
||||
static void pack_window_scan_lru(struct pack_file *p, struct pack_file **lru_p,
|
||||
struct pack_window **lru_w, struct pack_window **lru_l);
|
||||
|
||||
static int pack_window_close_lru( struct pack_backend *backend,
|
||||
struct pack_file *current, git_file keep_fd);
|
||||
|
||||
static void pack_window_close(struct pack_window **w_cursor);
|
||||
|
||||
static unsigned char *pack_window_open( struct pack_backend *backend,
|
||||
struct pack_file *p, struct pack_window **w_cursor, off_t offset,
|
||||
unsigned int *left);
|
||||
static unsigned char *pack_window_open(struct pack_file *p,
|
||||
git_mwindow **w_cursor, off_t offset, unsigned int *left);
|
||||
|
||||
static int packfile_sort__cb(const void *a_, const void *b_);
|
||||
|
||||
@ -299,8 +260,7 @@ static int pack_entry_find_prefix(struct pack_entry *e,
|
||||
const git_oid *short_oid,
|
||||
unsigned int len);
|
||||
|
||||
static off_t get_delta_base(struct pack_backend *backend,
|
||||
struct pack_file *p, struct pack_window **w_curs,
|
||||
static off_t get_delta_base(struct pack_file *p, git_mwindow **w_curs,
|
||||
off_t *curpos, git_otype type,
|
||||
off_t delta_obj_offset);
|
||||
|
||||
@ -313,16 +273,14 @@ static unsigned long packfile_unpack_header1(
|
||||
static int packfile_unpack_header(
|
||||
size_t *size_p,
|
||||
git_otype *type_p,
|
||||
struct pack_backend *backend,
|
||||
struct pack_file *p,
|
||||
struct pack_window **w_curs,
|
||||
git_mwindow **w_curs,
|
||||
off_t *curpos);
|
||||
|
||||
static int packfile_unpack_compressed(
|
||||
git_rawobj *obj,
|
||||
struct pack_backend *backend,
|
||||
struct pack_file *p,
|
||||
struct pack_window **w_curs,
|
||||
git_mwindow **w_curs,
|
||||
off_t curpos,
|
||||
size_t size,
|
||||
git_otype type);
|
||||
@ -331,7 +289,7 @@ static int packfile_unpack_delta(
|
||||
git_rawobj *obj,
|
||||
struct pack_backend *backend,
|
||||
struct pack_file *p,
|
||||
struct pack_window **w_curs,
|
||||
git_mwindow **w_curs,
|
||||
off_t curpos,
|
||||
size_t delta_size,
|
||||
git_otype delta_type,
|
||||
@ -350,23 +308,12 @@ static int packfile_unpack(git_rawobj *obj, struct pack_backend *backend,
|
||||
*
|
||||
***********************************************************/
|
||||
|
||||
void pack_window_free_all(struct pack_backend *backend, struct pack_file *p)
|
||||
GIT_INLINE(void) pack_window_free_all(struct pack_backend *GIT_UNUSED(backend), struct pack_file *p)
|
||||
{
|
||||
while (p->windows) {
|
||||
struct pack_window *w = p->windows;
|
||||
assert(w->inuse_cnt == 0);
|
||||
|
||||
backend->mapped -= w->window_map.len;
|
||||
backend->open_windows--;
|
||||
|
||||
git_futils_mmap_free(&w->window_map);
|
||||
|
||||
p->windows = w->next;
|
||||
free(w);
|
||||
}
|
||||
git_mwindow_free_all(&p->mwf);
|
||||
}
|
||||
|
||||
GIT_INLINE(int) pack_window_contains(struct pack_window *win, off_t offset)
|
||||
GIT_INLINE(int) pack_window_contains(git_mwindow *win, off_t offset)
|
||||
{
|
||||
/* We must promise at least 20 bytes (one hash) after the
|
||||
* offset is available from this window, otherwise the offset
|
||||
@ -374,86 +321,15 @@ GIT_INLINE(int) pack_window_contains(struct pack_window *win, off_t offset)
|
||||
* has that one hash excess) must be used. This is to support
|
||||
* the object header and delta base parsing routines below.
|
||||
*/
|
||||
off_t win_off = win->offset;
|
||||
return win_off <= offset
|
||||
&& (offset + 20) <= (off_t)(win_off + win->window_map.len);
|
||||
}
|
||||
|
||||
static void pack_window_scan_lru(
|
||||
struct pack_file *p,
|
||||
struct pack_file **lru_p,
|
||||
struct pack_window **lru_w,
|
||||
struct pack_window **lru_l)
|
||||
{
|
||||
struct pack_window *w, *w_l;
|
||||
|
||||
for (w_l = NULL, w = p->windows; w; w = w->next) {
|
||||
if (!w->inuse_cnt) {
|
||||
if (!*lru_w || w->last_used < (*lru_w)->last_used) {
|
||||
*lru_p = p;
|
||||
*lru_w = w;
|
||||
*lru_l = w_l;
|
||||
}
|
||||
}
|
||||
w_l = w;
|
||||
}
|
||||
}
|
||||
|
||||
static int pack_window_close_lru(
|
||||
struct pack_backend *backend,
|
||||
struct pack_file *current,
|
||||
git_file keep_fd)
|
||||
{
|
||||
struct pack_file *lru_p = NULL;
|
||||
struct pack_window *lru_w = NULL, *lru_l = NULL;
|
||||
size_t i;
|
||||
|
||||
if (current)
|
||||
pack_window_scan_lru(current, &lru_p, &lru_w, &lru_l);
|
||||
|
||||
for (i = 0; i < backend->packs.length; ++i)
|
||||
pack_window_scan_lru(git_vector_get(&backend->packs, i), &lru_p, &lru_w, &lru_l);
|
||||
|
||||
if (lru_p) {
|
||||
backend->mapped -= lru_w->window_map.len;
|
||||
git_futils_mmap_free(&lru_w->window_map);
|
||||
|
||||
if (lru_l)
|
||||
lru_l->next = lru_w->next;
|
||||
else {
|
||||
lru_p->windows = lru_w->next;
|
||||
if (!lru_p->windows && lru_p->pack_fd != keep_fd) {
|
||||
p_close(lru_p->pack_fd);
|
||||
lru_p->pack_fd = -1;
|
||||
}
|
||||
}
|
||||
|
||||
free(lru_w);
|
||||
backend->open_windows--;
|
||||
return GIT_SUCCESS;
|
||||
}
|
||||
|
||||
return git__throw(GIT_ERROR, "Failed to close pack window");
|
||||
}
|
||||
|
||||
static void pack_window_close(struct pack_window **w_cursor)
|
||||
{
|
||||
struct pack_window *w = *w_cursor;
|
||||
if (w) {
|
||||
w->inuse_cnt--;
|
||||
*w_cursor = NULL;
|
||||
}
|
||||
return git_mwindow_contains(win, offset + 20);
|
||||
}
|
||||
|
||||
static unsigned char *pack_window_open(
|
||||
struct pack_backend *backend,
|
||||
struct pack_file *p,
|
||||
struct pack_window **w_cursor,
|
||||
git_mwindow **w_cursor,
|
||||
off_t offset,
|
||||
unsigned int *left)
|
||||
{
|
||||
struct pack_window *win = *w_cursor;
|
||||
|
||||
if (p->pack_fd == -1 && packfile_open(p) < GIT_SUCCESS)
|
||||
return NULL;
|
||||
|
||||
@ -465,74 +341,9 @@ static unsigned char *pack_window_open(
|
||||
if (offset > (p->pack_size - 20))
|
||||
return NULL;
|
||||
|
||||
if (!win || !pack_window_contains(win, offset)) {
|
||||
|
||||
if (win)
|
||||
win->inuse_cnt--;
|
||||
|
||||
for (win = p->windows; win; win = win->next) {
|
||||
if (pack_window_contains(win, offset))
|
||||
break;
|
||||
return git_mwindow_open(&p->mwf, w_cursor, p->pack_fd, p->pack_size, offset, 20, left);
|
||||
}
|
||||
|
||||
if (!win) {
|
||||
size_t window_align = backend->window_size / 2;
|
||||
size_t len;
|
||||
|
||||
win = git__calloc(1, sizeof(*win));
|
||||
if (win == NULL)
|
||||
return NULL;
|
||||
|
||||
win->offset = (offset / window_align) * window_align;
|
||||
|
||||
len = (size_t)(p->pack_size - win->offset);
|
||||
if (len > backend->window_size)
|
||||
len = backend->window_size;
|
||||
|
||||
backend->mapped += len;
|
||||
|
||||
while (backend->mapped_limit < backend->mapped &&
|
||||
pack_window_close_lru(backend, p, p->pack_fd) == GIT_SUCCESS) {}
|
||||
|
||||
if (git_futils_mmap_ro(&win->window_map, p->pack_fd,
|
||||
win->offset, len) < GIT_SUCCESS) {
|
||||
free(win);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
backend->mmap_calls++;
|
||||
backend->open_windows++;
|
||||
|
||||
if (backend->mapped > backend->peak_mapped)
|
||||
backend->peak_mapped = backend->mapped;
|
||||
|
||||
if (backend->open_windows > backend->peak_open_windows)
|
||||
backend->peak_open_windows = backend->open_windows;
|
||||
|
||||
win->next = p->windows;
|
||||
p->windows = win;
|
||||
}
|
||||
}
|
||||
|
||||
if (win != *w_cursor) {
|
||||
win->last_used = backend->used_ctr++;
|
||||
win->inuse_cnt++;
|
||||
*w_cursor = win;
|
||||
}
|
||||
|
||||
offset -= win->offset;
|
||||
assert(git__is_sizet(offset));
|
||||
|
||||
if (left)
|
||||
*left = win->window_map.len - (size_t)offset;
|
||||
|
||||
return (unsigned char *)win->window_map.data + offset;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/***********************************************************
|
||||
@ -766,6 +577,11 @@ static int packfile_open(struct pack_file *p)
|
||||
if (p->pack_fd < 0 || p_fstat(p->pack_fd, &st) < GIT_SUCCESS)
|
||||
return git__throw(GIT_EOSERR, "Failed to open packfile. File appears to be corrupted");
|
||||
|
||||
if (git_mwindow_file_register(&p->mwf) < GIT_SUCCESS) {
|
||||
p_close(p->pack_fd);
|
||||
return git__throw(GIT_ERROR, "Failed to register packfile windows");
|
||||
}
|
||||
|
||||
/* If we created the struct before we had the pack we lack size. */
|
||||
if (!p->pack_size) {
|
||||
if (!S_ISREG(st.st_mode))
|
||||
@ -1210,9 +1026,8 @@ static unsigned long packfile_unpack_header1(
|
||||
static int packfile_unpack_header(
|
||||
size_t *size_p,
|
||||
git_otype *type_p,
|
||||
struct pack_backend *backend,
|
||||
struct pack_file *p,
|
||||
struct pack_window **w_curs,
|
||||
git_mwindow **w_curs,
|
||||
off_t *curpos)
|
||||
{
|
||||
unsigned char *base;
|
||||
@ -1225,7 +1040,7 @@ static int packfile_unpack_header(
|
||||
* the maximum deflated object size is 2^137, which is just
|
||||
* insane, so we know won't exceed what we have been given.
|
||||
*/
|
||||
base = pack_window_open(backend, p, w_curs, *curpos, &left);
|
||||
base = pack_window_open(p, w_curs, *curpos, &left);
|
||||
if (base == NULL)
|
||||
return GIT_ENOMEM;
|
||||
|
||||
@ -1240,9 +1055,8 @@ static int packfile_unpack_header(
|
||||
|
||||
static int packfile_unpack_compressed(
|
||||
git_rawobj *obj,
|
||||
struct pack_backend *backend,
|
||||
struct pack_file *p,
|
||||
struct pack_window **w_curs,
|
||||
git_mwindow **w_curs,
|
||||
off_t curpos,
|
||||
size_t size,
|
||||
git_otype type)
|
||||
@ -1265,7 +1079,7 @@ static int packfile_unpack_compressed(
|
||||
}
|
||||
|
||||
do {
|
||||
in = pack_window_open(backend, p, w_curs, curpos, &stream.avail_in);
|
||||
in = pack_window_open(p, w_curs, curpos, &stream.avail_in);
|
||||
stream.next_in = in;
|
||||
st = inflate(&stream, Z_FINISH);
|
||||
|
||||
@ -1289,14 +1103,13 @@ static int packfile_unpack_compressed(
|
||||
}
|
||||
|
||||
static off_t get_delta_base(
|
||||
struct pack_backend *backend,
|
||||
struct pack_file *p,
|
||||
struct pack_window **w_curs,
|
||||
git_mwindow **w_curs,
|
||||
off_t *curpos,
|
||||
git_otype type,
|
||||
off_t delta_obj_offset)
|
||||
{
|
||||
unsigned char *base_info = pack_window_open(backend, p, w_curs, *curpos, NULL);
|
||||
unsigned char *base_info = pack_window_open(p, w_curs, *curpos, NULL);
|
||||
off_t base_offset;
|
||||
git_oid unused;
|
||||
|
||||
@ -1336,7 +1149,7 @@ static int packfile_unpack_delta(
|
||||
git_rawobj *obj,
|
||||
struct pack_backend *backend,
|
||||
struct pack_file *p,
|
||||
struct pack_window **w_curs,
|
||||
git_mwindow **w_curs,
|
||||
off_t curpos,
|
||||
size_t delta_size,
|
||||
git_otype delta_type,
|
||||
@ -1346,11 +1159,11 @@ static int packfile_unpack_delta(
|
||||
git_rawobj base, delta;
|
||||
int error;
|
||||
|
||||
base_offset = get_delta_base(backend, p, w_curs, &curpos, delta_type, obj_offset);
|
||||
base_offset = get_delta_base(p, w_curs, &curpos, delta_type, obj_offset);
|
||||
if (base_offset == 0)
|
||||
return git__throw(GIT_EOBJCORRUPTED, "Delta offset is zero");
|
||||
|
||||
pack_window_close(w_curs);
|
||||
git_mwindow_close(w_curs);
|
||||
error = packfile_unpack(&base, backend, p, base_offset);
|
||||
|
||||
/* TODO: git.git tries to load the base from other packfiles
|
||||
@ -1358,7 +1171,7 @@ static int packfile_unpack_delta(
|
||||
if (error < GIT_SUCCESS)
|
||||
return git__rethrow(error, "Corrupted delta");
|
||||
|
||||
error = packfile_unpack_compressed(&delta, backend, p, w_curs, curpos, delta_size, delta_type);
|
||||
error = packfile_unpack_compressed(&delta, p, w_curs, curpos, delta_size, delta_type);
|
||||
if (error < GIT_SUCCESS) {
|
||||
free(base.data);
|
||||
return git__rethrow(error, "Corrupted delta");
|
||||
@ -1383,7 +1196,7 @@ static int packfile_unpack(
|
||||
struct pack_file *p,
|
||||
off_t obj_offset)
|
||||
{
|
||||
struct pack_window *w_curs = NULL;
|
||||
git_mwindow *w_curs = NULL;
|
||||
off_t curpos = obj_offset;
|
||||
int error;
|
||||
|
||||
@ -1398,7 +1211,7 @@ static int packfile_unpack(
|
||||
obj->len = 0;
|
||||
obj->type = GIT_OBJ_BAD;
|
||||
|
||||
error = packfile_unpack_header(&size, &type, backend, p, &w_curs, &curpos);
|
||||
error = packfile_unpack_header(&size, &type, p, &w_curs, &curpos);
|
||||
if (error < GIT_SUCCESS)
|
||||
return git__rethrow(error, "Failed to unpack packfile");
|
||||
|
||||
@ -1415,7 +1228,7 @@ static int packfile_unpack(
|
||||
case GIT_OBJ_BLOB:
|
||||
case GIT_OBJ_TAG:
|
||||
error = packfile_unpack_compressed(
|
||||
obj, backend, p, &w_curs, curpos,
|
||||
obj, p, &w_curs, curpos,
|
||||
size, type);
|
||||
break;
|
||||
|
||||
@ -1424,7 +1237,7 @@ static int packfile_unpack(
|
||||
break;
|
||||
}
|
||||
|
||||
pack_window_close(&w_curs);
|
||||
git_mwindow_close(&w_curs);
|
||||
return error == GIT_SUCCESS ? GIT_SUCCESS : git__rethrow(error, "Failed to unpack packfile");
|
||||
}
|
||||
|
||||
@ -1551,9 +1364,6 @@ int git_odb_backend_pack(git_odb_backend **backend_out, const char *objects_dir)
|
||||
return GIT_ENOMEM;
|
||||
}
|
||||
|
||||
backend->window_size = DEFAULT_WINDOW_SIZE;
|
||||
backend->mapped_limit = DEFAULT_MAPPED_LIMIT;
|
||||
|
||||
git_path_join(path, objects_dir, "pack");
|
||||
if (git_futils_isdir(path) == GIT_SUCCESS) {
|
||||
backend->pack_folder = git__strdup(path);
|
||||
|
Loading…
Reference in New Issue
Block a user