Commit 4188d28f by Andreas Ericsson Committed by Shawn O. Pearce

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>
parent ec250c6e
...@@ -47,3 +47,90 @@ off_t gitfo_size(git_file fd) ...@@ -47,3 +47,90 @@ off_t gitfo_size(git_file fd)
return -1; return -1;
return sb.st_size; 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);
}
...@@ -21,6 +21,7 @@ ...@@ -21,6 +21,7 @@
typedef int git_file; typedef int git_file;
typedef struct stat gitfo_statbuf; typedef struct stat gitfo_statbuf;
typedef struct gitfo_cache gitfo_cache;
#define gitfo_open(path, flags) open(path, flags) #define gitfo_open(path, flags) open(path, flags)
#define gitfo_close(fd) close(fd) #define gitfo_close(fd) close(fd)
...@@ -34,4 +35,9 @@ extern off_t gitfo_size(git_file fd); ...@@ -34,4 +35,9 @@ extern off_t gitfo_size(git_file fd);
#define gitfo_stat(path, buf) stat(path, buf) #define gitfo_stat(path, buf) stat(path, buf)
#define gitfo_fsync(fd) fsync(fd) #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__ */ #endif /* INCLUDE_fileops_h__ */
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