Experimental read cache patches, part 4 of 4

David Collier-Brown -- Customer Engineering David.Collier-Brown at Sun.COM
Thu May 29 20:44:29 GMT 2003


jra at dp.samba.org wrote:
> b). Send patches as *attachments*, not as inline code. This
> preserves all line boundaries etc.


	Oh RATS!  I was carefully pasting them in as message text
	to keep the list processor from removing them.

	Let's try that one again (;-)) Here they are again
	as diff files generated with the gnu diff, with
	-ugh options.  If I literally need to use CVS, I'll
	redo them at home.


--dave
-- 
David Collier-Brown,           | Always do right. This will gratify
Sun Microsystems DCMO          | some people and astonish the rest.
Toronto, Ontario               |
(905) 415-2849 or x52849       | davecb at canada.sun.com

-------------- next part --------------
--- close.old.c Tue May 27 20:05:13 2003
+++ close.c     Wed May 28 21:17:21 2003
@@ -96,6 +96,7 @@ static int close_filestruct(files_struct
                        ret = -1;
 
                delete_write_cache(fsp);
+               delete_read_cache(fsp);
        }
 
        conn->num_files_open--;

-------------- next part --------------
--- 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.

-------------- next part --------------
--- loadparm.old.c      Wed May 28 21:23:51 2003
+++ loadparm.c  Wed May 28 21:40:18 2003
@@ -347,6 +347,7 @@ typedef struct
        int iMaxPrintJobs;
        int iMaxReportedPrintJobs;
        int iWriteCacheSize;
+       int iReadCacheSize;
        int iCreate_mask;
        int iCreate_force_mode;
        int iSecurity_mask;
@@ -466,6 +467,7 @@ static service sDefault = {
        1000,                   /* iMaxPrintJobs */
        0,                      /* iMaxReportedPrintJobs */
        0,                      /* iWriteCacheSize */
+       0,                      /* iReadCacheSize */
        0744,                   /* iCreate_mask */
        0000,                   /* iCreate_force_mode */
        0777,                   /* iSecurity_mask */
@@ -902,6 +904,7 @@ static struct parm_struct parm_table[] =
        {"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_max_reported_jobs, i
 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)

-------------- next part --------------
--- smb.old.h   Tue May 27 20:04:23 2003
+++ smb.h       Wed May 28 21:13:48 2003
@@ -365,6 +365,7 @@ typedef struct write_cache
     size_t alloc_size;
     size_t data_size;
     char *data;
+    char *at; /* Used only in read buffers. */
 } write_cache;
 
 typedef struct
@@ -393,6 +394,7 @@ typedef struct files_struct
        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;



More information about the samba-technical mailing list