Experimental read cache patches, part 4 of 4
Dave Collier-Brown
davec-b at rogers.com
Thu May 29 02:07:11 GMT 2003
--- fileio.old.c Tue May 27 20:05:13 2003
+++ fileio.c Wed May 28 21:37:09 2003
@@ -23,6 +23,11 @@
#include "includes.h"
static BOOL setup_write_cache(files_struct *, SMB_OFF_T);
+static BOOL setup_read_cache(files_struct *);
+static int copy_from_cache(write_cache *, char *, size_t);
+static int read_from_read_cache(files_struct *,char
*,SMB_OFF_T,size_t);
+static void delete_cache(write_cache *cp);
+
/****************************************************************************
Seek a file. Try to avoid the seek if possible.
@@ -71,6 +76,109 @@ static BOOL read_from_write_cache(files_
return True;
}
+/*
+ * Read from the read cache, too.
+ */
+static int read_from_read_cache(files_struct *fsp, char *data,
+ SMB_OFF_T pos, size_t n)
+{
+ write_cache *rcp;
+ int rc,
+ ncopied = 0;
+
+ DEBUG(10,("read_from_read_cache\n"));
+ rcp = fsp->rcp;
+ if (rcp == NULL && fsp->wcp != NULL) {
+ /* There is a write cache, and it takes precedence. */
+ return 0;
+ }
+ else if (rcp == NULL) {
+ /* There is no write cache, so make a read cache. */
+ if (setup_read_cache(fsp) == False) {
+ return 0;
+ }
+ else {
+ /* Reload our copy of rcp. */
+ rcp = fsp->rcp;
+ }
+ }
+
+
+ if (rcp->data_size == -1) {
+ /* We are already at eof. */
+ return EOF;
+ }
+ else if (n <= rcp->data_size) {
+ /* It can be read straight from the buffer. */
+ (void) copy_from_cache(rcp, &data[ncopied], n);
+ return n;
+ }
+ else {
+ /* It requires a buffer-refilling loop. */
+ ncopied = 0;
+ rc = copy_from_cache(rcp, &data[ncopied],
rcp->data_size);
+ ncopied += rc;
+ n -= rc;
+
+ while ((rc = reload_read_cache(fsp)) != 0 && rc != -1) {
+ if (n <= rc) {
+ rc = copy_from_cache(rcp,
&data[ncopied], n);
+ ncopied += rc;
+ return ncopied;
+ }
+ else {
+ rc = copy_from_cache(rcp,
&data[ncopied], rcp->data_size);
+ ncopied += rc;
+ n -= rc;
+ }
+ }
+ }
+
+ /* DO_PROFILE_INC(readcache_read_hits); */
+ return ncopied;
+}
+
+
+/*
+ * copy_from_cache -- do the bookkeeping in one place.
+ */
+ static int
+copy_from_cache(write_cache *rcp, char *data, size_t size) {
+ size_t i = MIN(size, rcp->data_size);
+
+ (void) memcpy(data, rcp->at, i);
+ rcp->at += i;
+ rcp->offset += i;
+ rcp->data_size -= i;
+ return i;
+}
+
+
+/*
+ * reload_read_cache -- return a non-zero length or EOF.
+ */
+ int
+reload_read_cache(files_struct *fsp) {
+ write_cache *rcp = fsp->rcp; /* The read cache. */
+ int nread;
+
+ rcp->at = rcp->data;
+ nread = read(fsp->fd, rcp->data, rcp->alloc_size);
+ if (nread == -1 || nread == 0) {
+ rcp->data_size = -1; /* We hit EOF. */
+ return -1;
+ }
+ else {
+ rcp->data_size = nread;
+ rcp->data[nread] = '\0';
+ return nread;
+ }
+}
+
+
+
+
+
/****************************************************************************
Read from a file.
****************************************************************************/
@@ -83,6 +191,16 @@ ssize_t read_file(files_struct *fsp,char
if (fsp->print_file)
return -1;
+
+ /*
+ * Serve from read cache if we can. If not, we'll
+ * continue to the write cache and one last direct read.
+ */
+ if ((ret = read_from_read_cache(fsp, data, pos, n)) > 0) {
+ return ret;
+ }
+
+
/*
* Serve from write cache if we can.
*/
@@ -96,7 +214,24 @@ ssize_t read_file(files_struct *fsp,char
DEBUG(3,("read_file: Failed to seek to
%.0f\n",(double)pos));
return(ret);
}
-
+
+
+ ret = really_read_file(fsp, data, pos, n);
+
+ DEBUG(10,("read_file (%s): pos = %.0f, size = %lu, returned
%lu\n",
+ fsp->fsp_name, (double)pos, (unsigned long)n, (long)ret
));
+
+ return(ret);
+}
+
+/*
+ * really_read_file -- read with optional retry hack.
+ */
+ int
+really_read_file(files_struct *fsp, char *data, SMB_OFF_T pos, size_t
n) {
+ int ret, readret;
+
+
if (n > 0) {
#ifdef DMF_FIX
int numretries = 3;
@@ -628,30 +763,41 @@ n = %u, wcp->offset=%.0f, wcp->data_size
}
/****************************************************************************
- Delete the write cache structure.
+ Delete the read/write cache structures.
****************************************************************************/
void delete_write_cache(files_struct *fsp)
{
- write_cache *wcp;
-
- if(!fsp)
- return;
-
- if(!(wcp = fsp->wcp))
- return;
+ if (fsp) {
+ delete_cache(fsp->wcp);
+ DEBUG(10,("delete_write_cache: File %s deleted write
cache\n",fsp->fsp_name ));
- DO_PROFILE_DEC(writecache_allocated_write_caches);
- allocated_write_caches--;
-
- SMB_ASSERT(wcp->data_size == 0);
+ }
+}
- SAFE_FREE(wcp->data);
- SAFE_FREE(fsp->wcp);
+void delete_read_cache(files_struct *fsp)
+{
+ if (fsp) {
+ delete_cache(fsp->rcp);
+ DEBUG(10,("delete_read_cache: File %s deleted read
cache\n", fsp->fsp_name ));
+ }
+}
- DEBUG(10,("delete_write_cache: File %s deleted write cache\n",
fsp->fsp_name ));
+static void delete_cache(write_cache *cp) {
+
+ if (cp == NULL)
+ return;
+
+ DO_PROFILE_DEC(writecache_allocated_write_caches);
+ allocated_write_caches--;
+
+ SMB_ASSERT(cp->data_size == 0);
+
+ SAFE_FREE(cp->data);
+ SAFE_FREE(cp);
}
+
/****************************************************************************
Setup the write cache structure.
****************************************************************************/
@@ -694,6 +840,51 @@ static BOOL setup_write_cache(files_stru
return True;
}
+
+/* Setup read cache -- use same cache pool as write caches. */
+static BOOL setup_read_cache(files_struct *fsp)
+{
+ ssize_t alloc_size = lp_read_cache_size(SNUM(fsp->conn));
+ write_cache *rcp;
+
+ DEBUG(10,("setup_read_cache\n"));
+ if (alloc_size == 0) {
+ return False;
+ }
+ if (allocated_write_caches >= MAX_WRITE_CACHES)
+ return False;
+
+ if (fsp->rcp)
+ return False;
+
+ if((rcp = (write_cache *)malloc(sizeof(write_cache))) == NULL) {
+ DEBUG(0,("setup_read_cache: malloc fail.\n"));
+ return False;
+ }
+
+
+ rcp->file_size = 0; /* Junk value.*/
+ rcp->offset = 0; /* -1 would mean EOF. */
+ rcp->alloc_size = alloc_size;
+ rcp->data_size = 0;
+ if((rcp->data = malloc(rcp->alloc_size)) == NULL) {
+ DEBUG(0,("setup_write_cache: malloc fail for buffer size
%u.\n",
+ (unsigned int)rcp->alloc_size ));
+ SAFE_FREE(rcp);
+ return False;
+ }
+ rcp->at = rcp->data;
+
+ fsp->rcp = rcp;
+ /* DO_PROFILE_INC(writecache_allocated_read_caches); */
+ allocated_write_caches++;
+
+ DEBUG(10,("setup_read_cache: File %s allocated read cache size
%u\n",
+ fsp->fsp_name, rcp->alloc_size ));
+
+ return True;
+ }
+
/****************************************************************************
Cope with a size change.
More information about the samba-technical
mailing list