[Patch update] updated draft read cache patch
Dave Collier-Brown
davec-b at rogers.com
Sat Jun 21 18:48:42 GMT 2003
This was created with
cvs diff -u >all.diff
from last night's CVS, (20 June 2003), then tortured
overnight with the same sucesses and failures as the
unpatched copy from CVS.
I added
1) a belt-and-suspenders case: when the read
cache is not where the program wants to
read, invalidate the cache as before, but now
add a seek to the new location, so the following
real_read is **sure** to read from the specified
location.
2) a check to see that the file is oplocked.
I'll update regularly, and more often if requested (;-))
--dave
--
David Collier-Brown, | Always do right. This will gratify
Americas Customer Eng | some people and astonish the rest.
at Sun Canada | -- Mark Twain
(905) 415-2849 | davecb at spamcop.net
-------------- next part --------------
? Makefile.cscope
? all.diff
? cscope.out
? diff_file
Index: include/smb.h
===================================================================
RCS file: /cvsroot/samba/source/include/smb.h,v
retrieving revision 1.424.2.43
diff -u -r1.424.2.43 smb.h
--- include/smb.h 6 Jun 2003 05:15:14 -0000 1.424.2.43
+++ include/smb.h 21 Jun 2003 01:03:02 -0000
@@ -366,6 +366,7 @@
size_t alloc_size;
size_t data_size;
char *data;
+ char *at; /* Used only in read buffers. */
} write_cache;
typedef struct
@@ -394,6 +395,7 @@
uint16 vuid;
write_bmpx_struct *wbmpx_ptr;
write_cache *wcp;
+ write_cache *rcp; /* Read cache. */
struct timeval open_time;
int share_mode;
uint32 desired_access;
Index: param/loadparm.c
===================================================================
RCS file: /cvsroot/samba/source/param/loadparm.c,v
retrieving revision 1.397.2.67
diff -u -r1.397.2.67 loadparm.c
--- param/loadparm.c 20 Jun 2003 01:42:13 -0000 1.397.2.67
+++ param/loadparm.c 21 Jun 2003 01:03:09 -0000
@@ -348,6 +348,7 @@
int iMaxPrintJobs;
int iMaxReportedPrintJobs;
int iWriteCacheSize;
+ int iReadCacheSize;
int iCreate_mask;
int iCreate_force_mode;
int iSecurity_mask;
@@ -468,6 +469,7 @@
1000, /* iMaxPrintJobs */
0, /* iMaxReportedPrintJobs */
0, /* iWriteCacheSize */
+ 0, /* iReadCacheSize */
0744, /* iCreate_mask */
0000, /* iCreate_force_mode */
0777, /* iSecurity_mask */
@@ -904,6 +906,7 @@
{"use sendfile", P_BOOL, P_LOCAL, &sDefault.bUseSendfile, NULL, NULL, FLAG_SHARE},
{"hostname lookups", P_BOOL, P_GLOBAL, &Globals.bHostnameLookups, NULL, NULL, FLAG_ADVANCED | FLAG_DEVELOPER},
{"write cache size", P_INTEGER, P_LOCAL, &sDefault.iWriteCacheSize, NULL, NULL, FLAG_SHARE},
+ {"read cache size", P_INTEGER, P_LOCAL, &sDefault.iReadCacheSize, NULL, NULL, FLAG_SHARE},
{"name cache timeout", P_INTEGER, P_GLOBAL, &Globals.name_cache_timeout, NULL, NULL, FLAG_ADVANCED | FLAG_DEVELOPER},
@@ -1851,6 +1854,7 @@
FN_LOCAL_INTEGER(lp_oplock_contention_limit, iOplockContentionLimit)
FN_LOCAL_INTEGER(lp_csc_policy, iCSCPolicy)
FN_LOCAL_INTEGER(lp_write_cache_size, iWriteCacheSize)
+FN_LOCAL_INTEGER(lp_read_cache_size, iReadCacheSize)
FN_LOCAL_INTEGER(lp_block_size, iBlock_size)
FN_LOCAL_CHAR(lp_magicchar, magic_char)
FN_GLOBAL_INTEGER(lp_winbind_cache_time, &Globals.winbind_cache_time)
Index: smbd/close.c
===================================================================
RCS file: /cvsroot/samba/source/smbd/close.c,v
retrieving revision 1.42.2.6
diff -u -r1.42.2.6 close.c
--- smbd/close.c 14 May 2003 10:58:58 -0000 1.42.2.6
+++ smbd/close.c 21 Jun 2003 01:03:10 -0000
@@ -96,6 +96,7 @@
ret = -1;
delete_write_cache(fsp);
+ delete_read_cache(fsp);
}
conn->num_files_open--;
Index: smbd/fileio.c
===================================================================
RCS file: /cvsroot/samba/source/smbd/fileio.c,v
retrieving revision 1.40.2.9
diff -u -r1.40.2.9 fileio.c
--- smbd/fileio.c 14 May 2003 10:58:58 -0000 1.40.2.9
+++ smbd/fileio.c 21 Jun 2003 01:03:11 -0000
@@ -23,6 +23,12 @@
#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 invalidate_read_cache(write_cache *);
+static void delete_cache(write_cache *cp);
+
/****************************************************************************
Seek a file. Try to avoid the seek if possible.
@@ -71,6 +77,119 @@
return True;
}
+/*
+ * Read from the read cache, too. This variant invalidates the cache if
+ * a non-sequential read comes in, on the grounds that random I/O
+ * should do it's own buffering, if any buffering is done.
+ */
+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 (EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type) && !rcp) {
+ /* 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;
+ }
+ }
+ else if (rcp->offset != pos) {
+ /* This perhaps could become a seek and reread. */
+ DEBUG(0,("invalidating read cache.\n"));
+ seek_file(fsp,pos); /* Correct read position. */
+ invalidate_read_cache(rcp);
+ safe_free(rcp);
+ fsp->rcp = NULL;
+ return 0;
+ }
+
+ 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,11 +202,20 @@
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.
*/
-
- if(read_from_write_cache(fsp, data, pos, n))
+ if (read_from_write_cache(fsp, data, pos, n))
return n;
flush_write_cache(fsp, READ_FLUSH);
@@ -96,7 +224,24 @@
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 +773,41 @@
}
/****************************************************************************
- 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 (fsp) {
+ delete_cache(fsp->wcp);
+ DEBUG(10,("delete_write_cache: File %s deleted write cache\n",fsp->fsp_name ));
- if(!(wcp = fsp->wcp))
- return;
-
- 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.
****************************************************************************/
@@ -667,7 +823,14 @@
if(alloc_size == 0 || fsp->wcp)
return False;
- if((wcp = (write_cache *)malloc(sizeof(write_cache))) == NULL) {
+ if (fsp->rcp != NULL) {
+ /* There is a read cache: invalidate it and grab its space. */
+ invalidate_read_cache(fsp->rcp);
+ wcp = fsp->rcp;
+ fsp->rcp = NULL;
+ safe_free(wcp->data);
+ }
+ else if ((wcp = (write_cache *)malloc(sizeof(write_cache))) == NULL) {
DEBUG(0,("setup_write_cache: malloc fail.\n"));
return False;
}
@@ -694,6 +857,64 @@
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;
+ }
+
+/****************************************************************************
+Invalidate a read cache and remove its buffer. Used if writeb caching is used
+or if cache is out of sync with a read. If the latter is common, and large
+reads are still a good idea, we may just do a seek instead.
+****************************************************************************/
+ static void
+invalidate_read_cache(write_cache *rcp) {
+ rcp->file_size = 0;
+ rcp->offset = 0;
+ rcp->alloc_size = 0;
+ rcp->data_size = 0;
+ safe_free(rcp->data);
+}
+
/****************************************************************************
Cope with a size change.
More information about the samba-technical
mailing list