From 8c82534d89cef9260c12768e74eb4ef6c54f7217 Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Sun, 24 Dec 2006 00:46:13 -0500 Subject: Default core.packdGitWindowSize to 1 MiB if NO_MMAP. If the compiler has asked us to disable use of mmap() on their platform then we are forced to use git_mmap and its emulation via pread. In this case large (e.g. 32 MiB) windows for pack access are simply too big as a command will wind up reading a lot more data than it will ever need, significantly reducing response time. To prevent a high latency when NO_MMAP has been selected we now use a default of 1 MiB for core.packedGitWindowSize. Credit goes to Linus and Junio for recommending this more reasonable setting. [jc: upcased the name of the symbolic constant, and made another hardcoded constant into a symbolic constant while at it. ] Signed-off-by: Shawn O. Pearce Signed-off-by: Junio C Hamano --- git-compat-util.h | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'git-compat-util.h') diff --git a/git-compat-util.h b/git-compat-util.h index 5d9eb2615b..4764087d85 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -92,12 +92,17 @@ extern void set_warn_routine(void (*routine)(const char *warn, va_list params)); extern void *git_mmap(void *start, size_t length, int prot, int flags, int fd, off_t offset); extern int git_munmap(void *start, size_t length); +#define DEFAULT_PACKED_GIT_WINDOW_SIZE (1 * 1024 * 1024) + #else /* NO_MMAP */ #include +#define DEFAULT_PACKED_GIT_WINDOW_SIZE (32 * 1024 * 1024) #endif /* NO_MMAP */ +#define DEFAULT_PACKED_GIT_LIMIT (256 * 1024 * 1024) + #ifdef NO_SETENV #define setenv gitsetenv extern int gitsetenv(const char *, const char *, int); -- cgit v1.2.3 From 97bfeb34df1aa8a1cf232278624a5a5c924ee380 Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Sun, 24 Dec 2006 00:47:19 -0500 Subject: Release pack windows before reporting out of memory. If we are about to fail because this process has run out of memory we should first try to automatically control our appetite for address space by releasing enough least-recently-used pack windows to gain back enough memory such that we might actually be able to meet the current allocation request. This should help users who have fairly large repositories but are working on systems with relatively small virtual address space. Many times we see reports on the mailing list of these users running out of memory during various Git operations. Dynamically decreasing the amount of pack memory used when the demand for heap memory is increasing is an intelligent solution to this problem. Signed-off-by: Shawn O. Pearce Signed-off-by: Junio C Hamano --- git-compat-util.h | 40 ++++++++++++++++++++++++++++++++-------- 1 file changed, 32 insertions(+), 8 deletions(-) (limited to 'git-compat-util.h') diff --git a/git-compat-util.h b/git-compat-util.h index 4764087d85..0f856747e5 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -123,11 +123,17 @@ extern char *gitstrcasestr(const char *haystack, const char *needle); extern size_t gitstrlcpy(char *, const char *, size_t); #endif +extern void release_pack_memory(size_t); + static inline char* xstrdup(const char *str) { char *ret = strdup(str); - if (!ret) - die("Out of memory, strdup failed"); + if (!ret) { + release_pack_memory(strlen(str) + 1); + ret = strdup(str); + if (!ret) + die("Out of memory, strdup failed"); + } return ret; } @@ -136,8 +142,14 @@ static inline void *xmalloc(size_t size) void *ret = malloc(size); if (!ret && !size) ret = malloc(1); - if (!ret) - die("Out of memory, malloc failed"); + if (!ret) { + release_pack_memory(size); + ret = malloc(size); + if (!ret && !size) + ret = malloc(1); + if (!ret) + die("Out of memory, malloc failed"); + } #ifdef XMALLOC_POISON memset(ret, 0xA5, size); #endif @@ -149,8 +161,14 @@ static inline void *xrealloc(void *ptr, size_t size) void *ret = realloc(ptr, size); if (!ret && !size) ret = realloc(ptr, 1); - if (!ret) - die("Out of memory, realloc failed"); + if (!ret) { + release_pack_memory(size); + ret = realloc(ptr, size); + if (!ret && !size) + ret = realloc(ptr, 1); + if (!ret) + die("Out of memory, realloc failed"); + } return ret; } @@ -159,8 +177,14 @@ static inline void *xcalloc(size_t nmemb, size_t size) void *ret = calloc(nmemb, size); if (!ret && (!nmemb || !size)) ret = calloc(1, 1); - if (!ret) - die("Out of memory, calloc failed"); + if (!ret) { + release_pack_memory(nmemb * size); + ret = calloc(nmemb, size); + if (!ret && (!nmemb || !size)) + ret = calloc(1, 1); + if (!ret) + die("Out of memory, calloc failed"); + } return ret; } -- cgit v1.2.3 From c4712e4553f13d87d655325a57538f299402d457 Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Sun, 24 Dec 2006 00:47:23 -0500 Subject: Replace mmap with xmmap, better handling MAP_FAILED. In some cases we did not even bother to check the return value of mmap() and just assume it worked. This is bad, because if we are out of virtual address space the kernel returned MAP_FAILED and we would attempt to dereference that address, segfaulting without any real error output to the user. We are replacing all calls to mmap() with xmmap() and moving all MAP_FAILED checking into that single location. If a mmap call fails we try to release enough least-recently-used pack windows to possibly succeed, then retry the mmap() attempt. If we cannot mmap even after releasing pack memory then we die() as none of our callers have any reasonable recovery strategy for a failed mmap. Signed-off-by: Shawn O. Pearce Signed-off-by: Junio C Hamano --- git-compat-util.h | 13 +++++++++++++ 1 file changed, 13 insertions(+) (limited to 'git-compat-util.h') diff --git a/git-compat-util.h b/git-compat-util.h index 0f856747e5..f243b86d32 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -188,6 +188,19 @@ static inline void *xcalloc(size_t nmemb, size_t size) return ret; } +static inline void *xmmap(void *start, size_t length, + int prot, int flags, int fd, off_t offset) +{ + void *ret = mmap(start, length, prot, flags, fd, offset); + if (ret == MAP_FAILED) { + release_pack_memory(length); + ret = mmap(start, length, prot, flags, fd, offset); + if (ret == MAP_FAILED) + die("Out of memory? mmap failed: %s", strerror(errno)); + } + return ret; +} + static inline ssize_t xread(int fd, void *buf, size_t len) { ssize_t nr; -- cgit v1.2.3 From 22bac0ea528fd419cb833cab5de79a36fad91524 Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Thu, 4 Jan 2007 22:28:08 -0500 Subject: Increase packedGit{Limit,WindowSize} on 64 bit systems. If we have a 64 bit address space we can easily afford to commit a larger amount of virtual address space to pack file access. So on these platforms we should increase the default settings of core.packedGit{Limit,WindowSize} to something that will better handle very large projects. Thanks to Andy Whitcroft for pointing out that we can safely increase these defaults on such systems. Signed-off-by: Shawn O. Pearce Signed-off-by: Junio C Hamano --- git-compat-util.h | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) (limited to 'git-compat-util.h') diff --git a/git-compat-util.h b/git-compat-util.h index f243b86d32..55456da37c 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -97,11 +97,17 @@ extern int git_munmap(void *start, size_t length); #else /* NO_MMAP */ #include -#define DEFAULT_PACKED_GIT_WINDOW_SIZE (32 * 1024 * 1024) +#define DEFAULT_PACKED_GIT_WINDOW_SIZE \ + (sizeof(void*) >= 8 \ + ? 1 * 1024 * 1024 * 1024 \ + : 32 * 1024 * 1024) #endif /* NO_MMAP */ -#define DEFAULT_PACKED_GIT_LIMIT (256 * 1024 * 1024) +#define DEFAULT_PACKED_GIT_LIMIT \ + (sizeof(void*) >= 8 \ + ? 8 * 1024 * 1024 * 1024 \ + : 256 * 1024 * 1024) #ifdef NO_SETENV #define setenv gitsetenv -- cgit v1.2.3 From ecaebf4af1212f8a74bc560a66c76c22e7c87131 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Sun, 7 Jan 2007 00:11:11 -0800 Subject: Spell default packedgitlimit slightly differently This is shorter and easier to read, and also makes sure the constant expression does not overflow integer range. Signed-off-by: Junio C Hamano --- git-compat-util.h | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'git-compat-util.h') diff --git a/git-compat-util.h b/git-compat-util.h index 55456da37c..e023bf1413 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -105,9 +105,7 @@ extern int git_munmap(void *start, size_t length); #endif /* NO_MMAP */ #define DEFAULT_PACKED_GIT_LIMIT \ - (sizeof(void*) >= 8 \ - ? 8 * 1024 * 1024 * 1024 \ - : 256 * 1024 * 1024) + ((1024L * 1024L) * (sizeof(void*) >= 8 ? 8192 : 256)) #ifdef NO_SETENV #define setenv gitsetenv -- cgit v1.2.3 From 6900679c2f6d937a5a6ef616869c8887690ad19d Mon Sep 17 00:00:00 2001 From: "Stefan-W. Hahn" Date: Tue, 9 Jan 2007 22:04:12 +0100 Subject: Replacing the system call pread() with lseek()/xread()/lseek() sequence. Using cygwin with cygwin.dll before 1.5.22 the system call pread() is buggy. This patch introduces NO_PREAD. If NO_PREAD is set git uses a sequence of lseek()/xread()/lseek() to emulate pread. Signed-off-by: Stefan-W. Hahn Signed-off-by: Junio C Hamano --- git-compat-util.h | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'git-compat-util.h') diff --git a/git-compat-util.h b/git-compat-util.h index e023bf1413..f8d46d587b 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -107,6 +107,11 @@ extern int git_munmap(void *start, size_t length); #define DEFAULT_PACKED_GIT_LIMIT \ ((1024L * 1024L) * (sizeof(void*) >= 8 ? 8192 : 256)) +#ifdef NO_PREAD +#define pread git_pread +extern ssize_t git_pread(int fd, void *buf, size_t count, off_t offset); +#endif + #ifdef NO_SETENV #define setenv gitsetenv extern int gitsetenv(const char *, const char *, int); -- cgit v1.2.3 From 9130ac1e1966adb9922e64f645730d0d45383495 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Thu, 11 Jan 2007 14:09:31 -0800 Subject: Better error messages for corrupt databases This fixes another problem that Andy's case showed: git-fsck-objects reports nonsensical results for corrupt objects. There were actually two independent and confusing problems: - when we had a zero-sized file and used map_sha1_file, mmap() would return EINVAL, and git-fsck-objects would report that as an insane and confusing error. I don't know when this was introduced, it might have been there forever. - when "parse_object()" returned NULL, fsck would say "object not found", which can be very confusing, since obviously the object might "exist", it's just unparseable because it's totally corrupt. So this just makes "xmmap()" return NULL for a zero-sized object (which is a valid thing pointer, exactly the same way "malloc()" can return NULL for a zero-sized allocation). That fixes the first problem (but we could have fixed it in the caller too - I don't personally much care whichever way it goes, but maybe somebody should check that the NO_MMAP case does something sane in this case too?). And the second problem is solved by just making the error message slightly clearer - the failure to parse an object may be because it's missing or corrupt, not necessarily because it's not "found". Signed-off-by: Linus Torvalds Signed-off-by: Junio C Hamano --- git-compat-util.h | 2 ++ 1 file changed, 2 insertions(+) (limited to 'git-compat-util.h') diff --git a/git-compat-util.h b/git-compat-util.h index f8d46d587b..8781e8e22d 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -202,6 +202,8 @@ static inline void *xmmap(void *start, size_t length, { void *ret = mmap(start, length, prot, flags, fd, offset); if (ret == MAP_FAILED) { + if (!length) + return NULL; release_pack_memory(length); ret = mmap(start, length, prot, flags, fd, offset); if (ret == MAP_FAILED) -- cgit v1.2.3