diff options
author | Andreas Ericsson <ae@op5.se> | 2008-11-29 15:28:12 +0100 |
---|---|---|
committer | Shawn O. Pearce <spearce@spearce.org> | 2008-12-02 09:17:42 -0800 |
commit | 4188d28f1c38240392d896fc79561cc461fb12c0 (patch) | |
tree | 3d40a87326d25342300fb50d78744671440c5408 | |
parent | ec250c6e18e56d12714f9010e1b15e5feec5f473 (diff) | |
download | libgit2-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.c | 87 | ||||
-rw-r--r-- | src/fileops.h | 6 |
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__ */ |