summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndreas Ericsson <ae@op5.se>2008-11-29 15:28:12 +0100
committerShawn O. Pearce <spearce@spearce.org>2008-12-02 09:17:42 -0800
commit4188d28f1c38240392d896fc79561cc461fb12c0 (patch)
tree3d40a87326d25342300fb50d78744671440c5408
parentec250c6e18e56d12714f9010e1b15e5feec5f473 (diff)
downloadlibgit2-4188d28f1c38240392d896fc79561cc461fb12c0.tar.gz
Add an io caching layer to the gitfo api
The idea is taken from Junio's work in read-cache.c, where it's used for writing out the index without tap-dancing on the poor harddrive. Since it's almost certainly useful for cached writing of packfiles too, we turn it into a generic API, making it perfectly simple to reuse it later. gitfo_write_cached() has the same contract as gitfo_write(), it returns GIT_SUCCESS if all bytes are successfully written (or were at least buffered for later writing), and <0 if an error occurs during buffer writing. Signed-off-by: Andreas Ericsson <ae@op5.se> Signed-off-by: Shawn O. Pearce <spearce@spearce.org>
-rw-r--r--src/fileops.c87
-rw-r--r--src/fileops.h6
2 files changed, 93 insertions, 0 deletions
diff --git a/src/fileops.c b/src/fileops.c
index 1ca0fbb08..62da145b9 100644
--- a/src/fileops.c
+++ b/src/fileops.c
@@ -47,3 +47,90 @@ off_t gitfo_size(git_file fd)
return -1;
return sb.st_size;
}
+
+/* cached diskio */
+struct gitfo_cache {
+ git_file fd;
+ unsigned int cache_size, pos;
+ void *cache;
+};
+
+gitfo_cache *gitfo_enable_caching(git_file fd, size_t cache_size)
+{
+ gitfo_cache *ioc;
+
+ ioc = malloc(sizeof(*ioc));
+ if (!ioc)
+ return NULL;
+
+ ioc->pos = 0;
+ ioc->cache_size = cache_size;
+ ioc->cache = malloc(cache_size);
+ if (!ioc->cache) {
+ free(ioc);
+ return NULL;
+ }
+
+ return ioc;
+}
+
+static inline void gitfo_add_to_cache(gitfo_cache *ioc, void *buf, size_t len)
+{
+ memcpy(ioc->cache + ioc->pos, buf, len);
+ ioc->pos += len;
+}
+
+int gitfo_flush_cached(gitfo_cache *ioc)
+{
+ int result = GIT_SUCCESS;
+
+ if (ioc->pos) {
+ result = gitfo_write(ioc->fd, ioc->cache, ioc->pos);
+ ioc->pos = 0;
+ }
+
+ return result;
+}
+
+int gitfo_write_cached(gitfo_cache *ioc, void *buf, size_t len)
+{
+ for (;;) {
+ size_t space_left = ioc->cache_size - ioc->pos;
+ /* cache if it's small */
+ if (space_left > len) {
+ gitfo_add_to_cache(ioc, buf, len);
+ return GIT_SUCCESS;
+ }
+
+ /* flush the cache if it doesn't fit */
+ if (ioc->pos) {
+ int rc;
+ gitfo_add_to_cache(ioc, buf, space_left);
+ rc = gitfo_flush_cached(ioc);
+ if (rc < 0)
+ return rc;
+
+ len -= space_left;
+ buf += space_left;
+ }
+
+ /* write too-large chunks immediately */
+ if (len > ioc->cache_size)
+ return gitfo_write(ioc->fd, buf, len);
+ }
+ return GIT_SUCCESS;
+}
+
+int gitfo_close_cached(gitfo_cache *ioc)
+{
+ git_file fd;
+
+ if (gitfo_flush_cached(ioc) < 0)
+ return -1;
+
+ fd = ioc->fd;
+ free(ioc->cache);
+ free(ioc);
+
+ return gitfo_close(fd);
+}
diff --git a/src/fileops.h b/src/fileops.h
index 32d6b9111..56d0888fe 100644
--- a/src/fileops.h
+++ b/src/fileops.h
@@ -21,6 +21,7 @@
typedef int git_file;
typedef struct stat gitfo_statbuf;
+typedef struct gitfo_cache gitfo_cache;
#define gitfo_open(path, flags) open(path, flags)
#define gitfo_close(fd) close(fd)
@@ -34,4 +35,9 @@ extern off_t gitfo_size(git_file fd);
#define gitfo_stat(path, buf) stat(path, buf)
#define gitfo_fsync(fd) fsync(fd)
+extern gitfo_cache *gitfo_enable_caching(git_file fd, size_t cache_size);
+extern int gitfo_write_cached(gitfo_cache *ioc, void *buf, size_t len);
+extern int gitfo_flush_cached(gitfo_cache *ioc);
+extern int gitfo_close_cached(gitfo_cache *ioc);
+
#endif /* INCLUDE_fileops_h__ */