summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPhilip Kelley <phkelley@hotmail.com>2014-05-17 11:38:03 -0400
committerPhilip Kelley <phkelley@hotmail.com>2014-05-17 11:38:03 -0400
commitbf6a5b6143a733dc171878140f46c419160e1660 (patch)
tree9297aa8e7e7c802678c073d1fb162e3d3099baea
parent191ff93609efd393bcb2d4747d5cb9779a78a73f (diff)
parent0731a5b4db086eefac1a842e37526ef7bdbaa7de (diff)
downloadlibgit2-bf6a5b6143a733dc171878140f46c419160e1660.tar.gz
Merge remote-tracking branch 'upstream/cmn/indexer-mmap' into development
-rw-r--r--src/indexer.c156
-rw-r--r--src/map.h1
-rw-r--r--src/posix.c7
-rw-r--r--src/posix.h1
-rw-r--r--src/unix/map.c6
-rw-r--r--src/win32/map.c5
-rw-r--r--src/win32/posix.h6
-rw-r--r--src/win32/posix_w32.c2
8 files changed, 111 insertions, 73 deletions
diff --git a/src/indexer.c b/src/indexer.c
index 68496ceea..ebfdffb47 100644
--- a/src/indexer.c
+++ b/src/indexer.c
@@ -34,7 +34,6 @@ struct git_indexer {
have_delta :1;
struct git_pack_header hdr;
struct git_pack_file *pack;
- git_filebuf pack_file;
unsigned int mode;
git_off_t off;
git_off_t entry_start;
@@ -67,33 +66,18 @@ const git_oid *git_indexer_hash(const git_indexer *idx)
return &idx->hash;
}
-static int open_pack(struct git_pack_file **out, const char *filename)
-{
- struct git_pack_file *pack;
-
- if (git_packfile_alloc(&pack, filename) < 0)
- return -1;
-
- if ((pack->mwf.fd = p_open(pack->pack_name, O_RDONLY)) < 0) {
- giterr_set(GITERR_OS, "Failed to open packfile.");
- git_packfile_free(pack);
- return -1;
- }
-
- *out = pack;
- return 0;
-}
-
static int parse_header(struct git_pack_header *hdr, struct git_pack_file *pack)
{
int error;
+ git_map map;
- /* Verify we recognize this pack file format. */
- if ((error = p_read(pack->mwf.fd, hdr, sizeof(*hdr))) < 0) {
- giterr_set(GITERR_OS, "Failed to read in pack header");
+ if ((error = p_mmap(&map, sizeof(*hdr), GIT_PROT_READ, GIT_MAP_SHARED, pack->mwf.fd, 0)) < 0)
return error;
- }
+ memcpy(hdr, map.data, sizeof(*hdr));
+ p_munmap(&map);
+
+ /* Verify we recognize this pack file format. */
if (hdr->hdr_signature != ntohl(PACK_SIGNATURE)) {
giterr_set(GITERR_INDEXER, "Wrong pack signature");
return -1;
@@ -124,9 +108,9 @@ int git_indexer_new(
void *progress_payload)
{
git_indexer *idx;
- git_buf path = GIT_BUF_INIT;
+ git_buf path = GIT_BUF_INIT, tmp_path = GIT_BUF_INIT;
static const char suff[] = "/pack";
- int error;
+ int error, fd;
idx = git__calloc(1, sizeof(git_indexer));
GITERR_CHECK_ALLOC(idx);
@@ -140,19 +124,30 @@ int git_indexer_new(
if (error < 0)
goto cleanup;
- error = git_filebuf_open(&idx->pack_file, path.ptr,
- GIT_FILEBUF_TEMPORARY | GIT_FILEBUF_DO_NOT_BUFFER,
- idx->mode);
+ fd = git_futils_mktmp(&tmp_path, git_buf_cstr(&path), idx->mode);
git_buf_free(&path);
+ if (fd < 0)
+ goto cleanup;
+
+ error = git_packfile_alloc(&idx->pack, git_buf_cstr(&tmp_path));
+ git_buf_free(&tmp_path);
+
if (error < 0)
goto cleanup;
+ idx->pack->mwf.fd = fd;
+ if ((error = git_mwindow_file_register(&idx->pack->mwf)) < 0)
+ goto cleanup;
+
*out = idx;
return 0;
cleanup:
+ if (fd != -1)
+ p_close(fd);
+
git_buf_free(&path);
- git_filebuf_cleanup(&idx->pack_file);
+ git_buf_free(&tmp_path);
git__free(idx);
return -1;
}
@@ -429,6 +424,42 @@ static void hash_partially(git_indexer *idx, const uint8_t *data, size_t size)
idx->inbuf_len += size - to_expell;
}
+static int write_at(git_indexer *idx, const void *data, git_off_t offset, size_t size)
+{
+ git_file fd = idx->pack->mwf.fd;
+ long page_size = git__page_size();
+ git_off_t page_start, page_offset;
+ unsigned char *map_data;
+ git_map map;
+ int error;
+
+ /* the offset needs to be at the beginning of the a page boundary */
+ page_start = (offset / page_size) * page_size;
+ page_offset = offset - page_start;
+
+ if ((error = p_mmap(&map, page_offset + size, GIT_PROT_WRITE, GIT_MAP_SHARED, fd, page_start)) < 0)
+ return error;
+
+ map_data = (unsigned char *)map.data;
+ memcpy(map_data + page_offset, data, size);
+ p_munmap(&map);
+
+ return 0;
+}
+
+static int append_to_pack(git_indexer *idx, const void *data, size_t size)
+{
+ git_off_t current_size = idx->pack->mwf.size;
+
+ /* add the extra space we need at the end */
+ if (p_ftruncate(idx->pack->mwf.fd, current_size + size) < 0) {
+ giterr_system_set(errno);
+ return -1;
+ }
+
+ return write_at(idx, data, idx->pack->mwf.size, size);
+}
+
int git_indexer_append(git_indexer *idx, const void *data, size_t size, git_transfer_progress *stats)
{
int error = -1;
@@ -440,22 +471,13 @@ int git_indexer_append(git_indexer *idx, const void *data, size_t size, git_tran
processed = stats->indexed_objects;
- if ((error = git_filebuf_write(&idx->pack_file, data, size)) < 0)
+ if ((error = append_to_pack(idx, data, size)) < 0)
return error;
hash_partially(idx, data, (int)size);
/* Make sure we set the new size of the pack */
- if (idx->opened_pack) {
- idx->pack->mwf.size += size;
- } else {
- if ((error = open_pack(&idx->pack, idx->pack_file.path_lock)) < 0)
- return error;
- idx->opened_pack = 1;
- mwf = &idx->pack->mwf;
- if ((error = git_mwindow_file_register(&idx->pack->mwf)) < 0)
- return error;
- }
+ idx->pack->mwf.size += size;
if (!idx->parsed_header) {
unsigned int total_objects;
@@ -616,17 +638,10 @@ static int index_path(git_buf *path, git_indexer *idx, const char *suffix)
* Rewind the packfile by the trailer, as we might need to fix the
* packfile by injecting objects at the tail and must overwrite it.
*/
-static git_off_t seek_back_trailer(git_indexer *idx)
+static void seek_back_trailer(git_indexer *idx)
{
- git_off_t off;
-
- if ((off = p_lseek(idx->pack_file.fd, -GIT_OID_RAWSZ, SEEK_CUR)) < 0)
- return -1;
-
idx->pack->mwf.size -= GIT_OID_RAWSZ;
git_mwindow_free_all(&idx->pack->mwf);
-
- return off;
}
static int inject_object(git_indexer *idx, git_oid *id)
@@ -642,7 +657,8 @@ static int inject_object(git_indexer *idx, git_oid *id)
size_t len, hdr_len;
int error;
- entry_start = seek_back_trailer(idx);
+ seek_back_trailer(idx);
+ entry_start = idx->pack->mwf.size;
if (git_odb_read(&obj, idx->odb, id) < 0)
return -1;
@@ -657,7 +673,9 @@ static int inject_object(git_indexer *idx, git_oid *id)
/* Write out the object header */
hdr_len = git_packfile__object_header(hdr, len, git_odb_object_type(obj));
- git_filebuf_write(&idx->pack_file, hdr, hdr_len);
+ if ((error = append_to_pack(idx, hdr, hdr_len)) < 0)
+ goto cleanup;
+
idx->pack->mwf.size += hdr_len;
entry->crc = crc32(entry->crc, hdr, (uInt)hdr_len);
@@ -665,13 +683,16 @@ static int inject_object(git_indexer *idx, git_oid *id)
goto cleanup;
/* And then the compressed object */
- git_filebuf_write(&idx->pack_file, buf.ptr, buf.size);
+ if ((error = append_to_pack(idx, buf.ptr, buf.size)) < 0)
+ goto cleanup;
+
idx->pack->mwf.size += buf.size;
entry->crc = htonl(crc32(entry->crc, (unsigned char *)buf.ptr, (uInt)buf.size));
git_buf_free(&buf);
/* Write a fake trailer so the pack functions play ball */
- if ((error = git_filebuf_write(&idx->pack_file, &foo, GIT_OID_RAWSZ)) < 0)
+
+ if ((error = append_to_pack(idx, &foo, GIT_OID_RAWSZ)) < 0)
goto cleanup;
idx->pack->mwf.size += GIT_OID_RAWSZ;
@@ -817,19 +838,12 @@ static int update_header_and_rehash(git_indexer *idx, git_transfer_progress *sta
ctx = &idx->trailer;
git_hash_ctx_init(ctx);
- git_mwindow_free_all(mwf);
+
/* Update the header to include the numer of local objects we injected */
idx->hdr.hdr_entries = htonl(stats->total_objects + stats->local_objects);
- if (p_lseek(idx->pack_file.fd, 0, SEEK_SET) < 0) {
- giterr_set(GITERR_OS, "failed to seek to the beginning of the pack");
+ if (write_at(idx, &idx->hdr, 0, sizeof(struct git_pack_header)) < 0)
return -1;
- }
-
- if (p_write(idx->pack_file.fd, &idx->hdr, sizeof(struct git_pack_header)) < 0) {
- giterr_set(GITERR_OS, "failed to update the pack header");
- return -1;
- }
/*
* We now use the same technique as before to determine the
@@ -837,6 +851,7 @@ static int update_header_and_rehash(git_indexer *idx, git_transfer_progress *sta
* hash_partially() keep the existing trailer out of the
* calculation.
*/
+ git_mwindow_free_all(mwf);
idx->inbuf_len = 0;
while (hashed < mwf->size) {
ptr = git_mwindow_open(mwf, &w, hashed, chunk, &left);
@@ -906,13 +921,7 @@ int git_indexer_commit(git_indexer *idx, git_transfer_progress *stats)
return -1;
git_hash_final(&trailer_hash, &idx->trailer);
- if (p_lseek(idx->pack_file.fd, -GIT_OID_RAWSZ, SEEK_END) < 0)
- return -1;
-
- if (p_write(idx->pack_file.fd, &trailer_hash, GIT_OID_RAWSZ) < 0) {
- giterr_set(GITERR_OS, "failed to update pack trailer");
- return -1;
- }
+ write_at(idx, &trailer_hash, idx->pack->mwf.size - GIT_OID_RAWSZ, GIT_OID_RAWSZ);
}
git_vector_sort(&idx->objects);
@@ -995,14 +1004,18 @@ int git_indexer_commit(git_indexer *idx, git_transfer_progress *stats)
git_mwindow_free_all(&idx->pack->mwf);
/* We need to close the descriptor here so Windows doesn't choke on commit_at */
- p_close(idx->pack->mwf.fd);
+ if (p_close(idx->pack->mwf.fd) < 0) {
+ giterr_set(GITERR_OS, "failed to close packfile");
+ goto on_error;
+ }
+
idx->pack->mwf.fd = -1;
if (index_path(&filename, idx, ".pack") < 0)
goto on_error;
+
/* And don't forget to rename the packfile to its new place. */
- if (git_filebuf_commit_at(&idx->pack_file, filename.ptr) < 0)
- return -1;
+ p_rename(idx->pack->pack_name, git_buf_cstr(&filename));
git_buf_free(&filename);
return 0;
@@ -1022,7 +1035,7 @@ void git_indexer_free(git_indexer *idx)
git_vector_free_deep(&idx->objects);
- if (idx->pack) {
+ if (idx->pack && idx->pack->idx_cache) {
struct git_pack_entry *pentry;
kh_foreach_value(
idx->pack->idx_cache, pentry, { git__free(pentry); });
@@ -1032,6 +1045,5 @@ void git_indexer_free(git_indexer *idx)
git_vector_free_deep(&idx->deltas);
git_packfile_free(idx->pack);
- git_filebuf_cleanup(&idx->pack_file);
git__free(idx);
}
diff --git a/src/map.h b/src/map.h
index da3d1e19a..722eb7a30 100644
--- a/src/map.h
+++ b/src/map.h
@@ -42,5 +42,6 @@ typedef struct { /* memory mapped buffer */
extern int p_mmap(git_map *out, size_t len, int prot, int flags, int fd, git_off_t offset);
extern int p_munmap(git_map *map);
+extern long git__page_size(void);
#endif /* INCLUDE_map_h__ */
diff --git a/src/posix.c b/src/posix.c
index 7484ac0d8..7aeb0e6c1 100644
--- a/src/posix.c
+++ b/src/posix.c
@@ -207,6 +207,13 @@ int p_write(git_file fd, const void *buf, size_t cnt)
#include "map.h"
+long git__page_size(void)
+{
+ /* dummy; here we don't need any alignment anyway */
+ return 4096;
+}
+
+
int p_mmap(git_map *out, size_t len, int prot, int flags, int fd, git_off_t offset)
{
GIT_MMAP_VALIDATE(out, len, prot, flags);
diff --git a/src/posix.h b/src/posix.h
index f85b1aebd..965cd98d5 100644
--- a/src/posix.h
+++ b/src/posix.h
@@ -73,6 +73,7 @@ extern int p_rename(const char *from, const char *to);
#define p_rmdir(p) rmdir(p)
#define p_chmod(p,m) chmod(p, m)
#define p_access(p,m) access(p,m)
+#define p_ftruncate(fd, sz) ftruncate(fd, sz)
#define p_recv(s,b,l,f) recv(s,b,l,f)
#define p_send(s,b,l,f) send(s,b,l,f)
typedef int GIT_SOCKET;
diff --git a/src/unix/map.c b/src/unix/map.c
index e62ab3e76..3d0cbbaf8 100644
--- a/src/unix/map.c
+++ b/src/unix/map.c
@@ -10,8 +10,14 @@
#include "map.h"
#include <sys/mman.h>
+#include <unistd.h>
#include <errno.h>
+long git__page_size(void)
+{
+ return sysconf(_SC_PAGE_SIZE);
+}
+
int p_mmap(git_map *out, size_t len, int prot, int flags, int fd, git_off_t offset)
{
int mprot = 0;
diff --git a/src/win32/map.c b/src/win32/map.c
index 902ea3994..ef83f882e 100644
--- a/src/win32/map.c
+++ b/src/win32/map.c
@@ -23,6 +23,11 @@ static DWORD get_page_size(void)
return page_size;
}
+long git__page_size(void)
+{
+ return (long)get_page_size();
+}
+
int p_mmap(git_map *out, size_t len, int prot, int flags, int fd, git_off_t offset)
{
HANDLE fh = (HANDLE)_get_osfhandle(fd);
diff --git a/src/win32/posix.h b/src/win32/posix.h
index 7f9d57cc3..2cbea1807 100644
--- a/src/win32/posix.h
+++ b/src/win32/posix.h
@@ -19,6 +19,12 @@
# define EAFNOSUPPORT (INT_MAX-1)
#endif
+#ifdef _MSC_VER
+# define p_ftruncate(fd, sz) _chsize_s(fd, sz)
+#else /* MinGW */
+# define p_ftruncate(fd, sz) _chsize(fd, sz)
+#endif
+
GIT_INLINE(int) p_link(const char *old, const char *new)
{
GIT_UNUSED(old);
diff --git a/src/win32/posix_w32.c b/src/win32/posix_w32.c
index 73bf92572..34938431a 100644
--- a/src/win32/posix_w32.c
+++ b/src/win32/posix_w32.c
@@ -578,7 +578,7 @@ int p_mkstemp(char *tmp_path)
return -1;
#endif
- return p_creat(tmp_path, 0744); //-V536
+ return p_open(tmp_path, O_RDWR | O_CREAT | O_EXCL, 0744); //-V536
}
int p_access(const char* path, mode_t mode)