Commit 58152669 by Carlos Martín Nieto

Merge branch 'cmn/global-mwf'

parents 35757155 b3b66c57
...@@ -18,6 +18,8 @@ ...@@ -18,6 +18,8 @@
#include "oidmap.h" #include "oidmap.h"
#include "zstream.h" #include "zstream.h"
extern git_mutex git__mwindow_mutex;
#define UINT31_MAX (0x7FFFFFFF) #define UINT31_MAX (0x7FFFFFFF)
struct entry { struct entry {
...@@ -1044,6 +1046,11 @@ void git_indexer_free(git_indexer *idx) ...@@ -1044,6 +1046,11 @@ void git_indexer_free(git_indexer *idx)
} }
git_vector_free_deep(&idx->deltas); git_vector_free_deep(&idx->deltas);
if (!git_mutex_lock(&git__mwindow_mutex)) {
git_packfile_free(idx->pack); git_packfile_free(idx->pack);
git_mutex_unlock(&git__mwindow_mutex);
}
git__free(idx); git__free(idx);
} }
...@@ -11,6 +11,10 @@ ...@@ -11,6 +11,10 @@
#include "fileops.h" #include "fileops.h"
#include "map.h" #include "map.h"
#include "global.h" #include "global.h"
#include "strmap.h"
#include "pack.h"
GIT__USE_STRMAP;
#define DEFAULT_WINDOW_SIZE \ #define DEFAULT_WINDOW_SIZE \
(sizeof(void*) >= 8 \ (sizeof(void*) >= 8 \
...@@ -26,20 +30,126 @@ size_t git_mwindow__mapped_limit = DEFAULT_MAPPED_LIMIT; ...@@ -26,20 +30,126 @@ size_t git_mwindow__mapped_limit = DEFAULT_MAPPED_LIMIT;
/* Whenever you want to read or modify this, grab git__mwindow_mutex */ /* Whenever you want to read or modify this, grab git__mwindow_mutex */
static git_mwindow_ctl mem_ctl; static git_mwindow_ctl mem_ctl;
/* /* Global list of mwindow files, to open packs once across repos */
* Free all the windows in a sequence, typically because we're done git_strmap *git__pack_cache = NULL;
* with the file
/**
* Run under mwindow lock
*/ */
void git_mwindow_free_all(git_mwindow_file *mwf) int git_mwindow_files_init(void)
{ {
git_mwindow_ctl *ctl = &mem_ctl; if (git__pack_cache)
size_t i; return 0;
return git_strmap_alloc(&git__pack_cache);
}
void git_mwindow_files_free(void)
{
git_strmap *tmp = git__pack_cache;
git__pack_cache = NULL;
git_strmap_free(tmp);
}
int git_mwindow_get_pack(struct git_pack_file **out, const char *path)
{
int error;
char *packname;
git_strmap_iter pos;
struct git_pack_file *pack;
if ((error = git_packfile__name(&packname, path)) < 0)
return error;
if (git_mutex_lock(&git__mwindow_mutex) < 0)
return -1;
if (git_mwindow_files_init() < 0) {
git_mutex_unlock(&git__mwindow_mutex);
return -1;
}
pos = git_strmap_lookup_index(git__pack_cache, packname);
git__free(packname);
if (git_strmap_valid_index(git__pack_cache, pos)) {
pack = git_strmap_value_at(git__pack_cache, pos);
git_atomic_inc(&pack->refcount);
git_mutex_unlock(&git__mwindow_mutex);
*out = pack;
return 0;
}
/* If we didn't find it, we need to create it */
if ((error = git_packfile_alloc(&pack, path)) < 0) {
git_mutex_unlock(&git__mwindow_mutex);
return error;
}
git_atomic_inc(&pack->refcount);
git_strmap_insert(git__pack_cache, pack->pack_name, pack, error);
git_mutex_unlock(&git__mwindow_mutex);
if (error < 0)
return -1;
*out = pack;
return 0;
}
int git_mwindow_put_pack(struct git_pack_file *pack)
{
int count;
git_strmap_iter pos;
if (git_mutex_lock(&git__mwindow_mutex) < 0)
return -1;
if (git_mwindow_files_init() < 0) {
git_mutex_unlock(&git__mwindow_mutex);
return -1;
}
pos = git_strmap_lookup_index(git__pack_cache, pack->pack_name);
if (!git_strmap_valid_index(git__pack_cache, pos)) {
git_mutex_unlock(&git__mwindow_mutex);
return GIT_ENOTFOUND;
}
count = git_atomic_dec(&pack->refcount);
if (count == 0) {
git_strmap_delete_at(git__pack_cache, pos);
git_packfile_free(pack);
}
git_mutex_unlock(&git__mwindow_mutex);
return 0;
}
void git_mwindow_free_all(git_mwindow_file *mwf)
{
if (git_mutex_lock(&git__mwindow_mutex)) { if (git_mutex_lock(&git__mwindow_mutex)) {
giterr_set(GITERR_THREAD, "unable to lock mwindow mutex"); giterr_set(GITERR_THREAD, "unable to lock mwindow mutex");
return; return;
} }
git_mwindow_free_all_locked(mwf);
git_mutex_unlock(&git__mwindow_mutex);
}
/*
* Free all the windows in a sequence, typically because we're done
* with the file
*/
void git_mwindow_free_all_locked(git_mwindow_file *mwf)
{
git_mwindow_ctl *ctl = &mem_ctl;
size_t i;
/* /*
* Remove these windows from the global list * Remove these windows from the global list
*/ */
...@@ -67,8 +177,6 @@ void git_mwindow_free_all(git_mwindow_file *mwf) ...@@ -67,8 +177,6 @@ void git_mwindow_free_all(git_mwindow_file *mwf)
mwf->windows = w->next; mwf->windows = w->next;
git__free(w); git__free(w);
} }
git_mutex_unlock(&git__mwindow_mutex);
} }
/* /*
......
...@@ -36,10 +36,18 @@ typedef struct git_mwindow_ctl { ...@@ -36,10 +36,18 @@ typedef struct git_mwindow_ctl {
} git_mwindow_ctl; } git_mwindow_ctl;
int git_mwindow_contains(git_mwindow *win, git_off_t offset); int git_mwindow_contains(git_mwindow *win, git_off_t offset);
void git_mwindow_free_all(git_mwindow_file *mwf); void git_mwindow_free_all(git_mwindow_file *mwf); /* locks */
void git_mwindow_free_all_locked(git_mwindow_file *mwf); /* run under lock */
unsigned char *git_mwindow_open(git_mwindow_file *mwf, git_mwindow **cursor, git_off_t offset, size_t extra, unsigned int *left); unsigned char *git_mwindow_open(git_mwindow_file *mwf, git_mwindow **cursor, git_off_t offset, size_t extra, unsigned int *left);
int git_mwindow_file_register(git_mwindow_file *mwf); int git_mwindow_file_register(git_mwindow_file *mwf);
void git_mwindow_file_deregister(git_mwindow_file *mwf); void git_mwindow_file_deregister(git_mwindow_file *mwf);
void git_mwindow_close(git_mwindow **w_cursor); void git_mwindow_close(git_mwindow **w_cursor);
int git_mwindow_files_init(void);
void git_mwindow_files_free(void);
struct git_pack_file; /* just declaration to avoid cyclical includes */
int git_mwindow_get_pack(struct git_pack_file **out, const char *path);
int git_mwindow_put_pack(struct git_pack_file *pack);
#endif #endif
...@@ -210,7 +210,7 @@ static int packfile_load__cb(void *data, git_buf *path) ...@@ -210,7 +210,7 @@ static int packfile_load__cb(void *data, git_buf *path)
return 0; return 0;
} }
error = git_packfile_alloc(&pack, path->ptr); error = git_mwindow_get_pack(&pack, path->ptr);
/* ignore missing .pack file as git does */ /* ignore missing .pack file as git does */
if (error == GIT_ENOTFOUND) { if (error == GIT_ENOTFOUND) {
...@@ -605,7 +605,7 @@ static void pack_backend__free(git_odb_backend *_backend) ...@@ -605,7 +605,7 @@ static void pack_backend__free(git_odb_backend *_backend)
for (i = 0; i < backend->packs.length; ++i) { for (i = 0; i < backend->packs.length; ++i) {
struct git_pack_file *p = git_vector_get(&backend->packs, i); struct git_pack_file *p = git_vector_get(&backend->packs, i);
git_packfile_free(p); git_mwindow_put_pack(p);
} }
git_vector_free(&backend->packs); git_vector_free(&backend->packs);
...@@ -647,7 +647,7 @@ int git_odb_backend_one_pack(git_odb_backend **backend_out, const char *idx) ...@@ -647,7 +647,7 @@ int git_odb_backend_one_pack(git_odb_backend **backend_out, const char *idx)
if (pack_backend__alloc(&backend, 1) < 0) if (pack_backend__alloc(&backend, 1) < 0)
return -1; return -1;
if (git_packfile_alloc(&packfile, idx) < 0 || if (git_mwindow_get_pack(&packfile, idx) < 0 ||
git_vector_insert(&backend->packs, packfile) < 0) git_vector_insert(&backend->packs, packfile) < 0)
{ {
pack_backend__free((git_odb_backend *)backend); pack_backend__free((git_odb_backend *)backend);
...@@ -664,6 +664,9 @@ int git_odb_backend_pack(git_odb_backend **backend_out, const char *objects_dir) ...@@ -664,6 +664,9 @@ int git_odb_backend_pack(git_odb_backend **backend_out, const char *objects_dir)
struct pack_backend *backend = NULL; struct pack_backend *backend = NULL;
git_buf path = GIT_BUF_INIT; git_buf path = GIT_BUF_INIT;
if (git_mwindow_files_init() < 0)
return -1;
if (pack_backend__alloc(&backend, 8) < 0) if (pack_backend__alloc(&backend, 8) < 0)
return -1; return -1;
......
...@@ -968,7 +968,7 @@ void git_packfile_free(struct git_pack_file *p) ...@@ -968,7 +968,7 @@ void git_packfile_free(struct git_pack_file *p)
cache_free(&p->bases); cache_free(&p->bases);
git_mwindow_free_all(&p->mwf); git_mwindow_free_all_locked(&p->mwf);
if (p->mwf.fd >= 0) if (p->mwf.fd >= 0)
p_close(p->mwf.fd); p_close(p->mwf.fd);
...@@ -1063,6 +1063,23 @@ cleanup: ...@@ -1063,6 +1063,23 @@ cleanup:
return -1; return -1;
} }
int git_packfile__name(char **out, const char *path)
{
size_t path_len;
git_buf buf = GIT_BUF_INIT;
path_len = strlen(path);
if (path_len < strlen(".idx"))
return git_odb__error_notfound("invalid packfile path", NULL);
if (git_buf_printf(&buf, "%.*s.pack", (int)(path_len - strlen(".idx")), path) < 0)
return -1;
*out = git_buf_detach(&buf);
return 0;
}
int git_packfile_alloc(struct git_pack_file **pack_out, const char *path) int git_packfile_alloc(struct git_pack_file **pack_out, const char *path)
{ {
struct stat st; struct stat st;
......
...@@ -90,6 +90,7 @@ struct git_pack_file { ...@@ -90,6 +90,7 @@ struct git_pack_file {
git_mwindow_file mwf; git_mwindow_file mwf;
git_map index_map; git_map index_map;
git_mutex lock; /* protect updates to mwf and index_map */ git_mutex lock; /* protect updates to mwf and index_map */
git_atomic refcount;
uint32_t num_objects; uint32_t num_objects;
uint32_t num_bad_objects; uint32_t num_bad_objects;
...@@ -123,6 +124,8 @@ typedef struct git_packfile_stream { ...@@ -123,6 +124,8 @@ typedef struct git_packfile_stream {
size_t git_packfile__object_header(unsigned char *hdr, size_t size, git_otype type); size_t git_packfile__object_header(unsigned char *hdr, size_t size, git_otype type);
int git_packfile__name(char **out, const char *path);
int git_packfile_unpack_header( int git_packfile_unpack_header(
size_t *size_p, size_t *size_p,
git_otype *type_p, git_otype *type_p,
......
#include "clar_libgit2.h"
#include <git2.h>
#include "strmap.h"
#include "mwindow.h"
#include "pack.h"
extern git_strmap *git__pack_cache;
void test_pack_sharing__open_two_repos(void)
{
git_repository *repo1, *repo2;
git_object *obj1, *obj2;
git_oid id;
git_strmap_iter pos;
void *data;
int error;
cl_git_pass(git_repository_open(&repo1, cl_fixture("testrepo.git")));
cl_git_pass(git_repository_open(&repo2, cl_fixture("testrepo.git")));
git_oid_fromstr(&id, "a65fedf39aefe402d3bb6e24df4d4f5fe4547750");
cl_git_pass(git_object_lookup(&obj1, repo1, &id, GIT_OBJ_ANY));
cl_git_pass(git_object_lookup(&obj2, repo2, &id, GIT_OBJ_ANY));
pos = 0;
while ((error = git_strmap_next(&data, &pos, git__pack_cache)) == 0) {
struct git_pack_file *pack = (struct git_pack_file *) data;
cl_assert_equal_i(2, pack->refcount.val);
}
cl_assert_equal_i(3, git_strmap_num_entries(git__pack_cache));
git_object_free(obj1);
git_object_free(obj2);
git_repository_free(repo1);
git_repository_free(repo2);
/* we don't want to keep the packs open after the repos go away */
cl_assert_equal_i(0, git_strmap_num_entries(git__pack_cache));
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment