windows-dirty-buffer-optimization-20070808
authorJeffrey Altman <jaltman@secure-endpoints.com>
Thu, 9 Aug 2007 06:33:17 +0000 (06:33 +0000)
committerJeffrey Altman <jaltman@secure-endpoints.com>
Thu, 9 Aug 2007 06:33:17 +0000 (06:33 +0000)
when storing dirty buffers only store the bytes that are dirty

increase the default chunksize from 128KB to 1MB

remove OVERLAPPED field from cm_buf_t.  It was unused.

add a dummy pointer in order to ensure data structure compatibility
between the checked and release builds.

src/WINNT/afsd/cm_buf.c
src/WINNT/afsd/cm_buf.h
src/WINNT/afsd/cm_config.h
src/WINNT/afsd/cm_dcache.c
src/WINNT/afsd/cm_scache.c
src/WINNT/afsd/rawops.c
src/WINNT/afsd/smb.c

index 1f7361d..5f36354 100644 (file)
@@ -547,6 +547,7 @@ long buf_CleanAsyncLocked(cm_buf_t *bp, cm_req_t *reqp)
     long code = 0;
     long isdirty = 0;
     cm_scache_t * scp = NULL;
+    osi_hyper_t offset;
 
     osi_assert(bp->magic == CM_BUF_MAGIC);
 
@@ -557,9 +558,10 @@ long buf_CleanAsyncLocked(cm_buf_t *bp, cm_req_t *reqp)
        scp = cm_FindSCache(&bp->fid);
        if (scp) {
            osi_Log2(buf_logp, "buf_CleanAsyncLocked starts I/O on scp 0x%p buf 0x%p", scp, bp);
-           code = (*cm_buf_opsp->Writep)(scp, &bp->offset,
-                                          cm_data.buf_blockSize, 0, bp->userp,
-                                          reqp);
+
+            offset = bp->offset;
+            LargeIntegerAdd(offset, ConvertLongToLargeInteger(bp->dirty_offset));
+           code = (*cm_buf_opsp->Writep)(scp, &offset, bp->dirty_length, 0, bp->userp, reqp);
            osi_Log3(buf_logp, "buf_CleanAsyncLocked I/O on scp 0x%p buf 0x%p, done=%d", scp, bp, code);
 
            cm_ReleaseSCache(scp);
@@ -577,6 +579,8 @@ long buf_CleanAsyncLocked(cm_buf_t *bp, cm_req_t *reqp)
        if (code == CM_ERROR_NOSUCHFILE){
            bp->flags &= ~CM_BUF_DIRTY;
            bp->flags |= CM_BUF_ERROR;
+            bp->dirty_offset = 0;
+            bp->dirty_length = 0;
            bp->error = CM_ERROR_NOSUCHFILE;
            bp->dataVersion = -1; /* bad */
            bp->dirtyCounter++;
@@ -988,10 +992,6 @@ long buf_Get(struct cm_scache *scp, osi_hyper_t *offsetp, cm_buf_t **bufpp)
         /* load the page; freshly created pages should be idle */
         osi_assert(!(bp->flags & (CM_BUF_READING | CM_BUF_WRITING)));
 
-        /* setup offset, event */
-        bp->over.Offset = bp->offset.LowPart;
-        bp->over.OffsetHigh = bp->offset.HighPart;
-
         /* start the I/O; may drop lock */
         bp->flags |= CM_BUF_READING;
         code = (*cm_buf_opsp->Readp)(bp, cm_data.buf_blockSize, &tcount, NULL);
@@ -1122,42 +1122,62 @@ void buf_CleanWait(cm_scache_t * scp, cm_buf_t *bp)
  *
  * The buffer must be locked before calling this routine.
  */
-void buf_SetDirty(cm_buf_t *bp)
+void buf_SetDirty(cm_buf_t *bp, afs_uint32 offset, afs_uint32 length)
 {
     osi_assert(bp->magic == CM_BUF_MAGIC);
     osi_assert(bp->refCount > 0);
-       
+
+    lock_ObtainWrite(&buf_globalLock);
     if (bp->flags & CM_BUF_DIRTY) {
+
        osi_Log1(buf_logp, "buf_SetDirty 0x%p already dirty", bp);
+
+        if (bp->dirty_offset <= offset) {
+            if (bp->dirty_offset + bp->dirty_length >= offset + length) {
+                /* dirty_length remains the same */
+            } else {
+                bp->dirty_length = offset + length - bp->dirty_offset;
+            }
+        } else /* bp->dirty_offset > offset */ {
+            if (bp->dirty_offset + bp->dirty_length >= offset + length) {
+                bp->dirty_length = bp->dirty_offset + bp->dirty_length - offset;
+            } else {
+                bp->dirty_length = length;
+            }
+            bp->dirty_offset = offset;
+        }
     } else {
        osi_Log1(buf_logp, "buf_SetDirty 0x%p", bp);
-    }
-    /* set dirty bit */
-    bp->flags |= CM_BUF_DIRTY;
 
-    /* and turn off EOF flag, since it has associated data now */
-    bp->flags &= ~CM_BUF_EOF;
+        /* set dirty bit */
+        bp->flags |= CM_BUF_DIRTY;
 
-    /* and add to the dirty list.  
-     * we obtain a hold on the buffer for as long as it remains 
-     * in the list.  buffers are only removed from the list by 
-     * the buf_IncrSyncer function regardless of when else the
-     * dirty flag might be cleared.
-     *
-     * This should never happen but just in case there is a bug
-     * elsewhere, never add to the dirty list if the buffer is 
-     * already there.
-     */
-    lock_ObtainWrite(&buf_globalLock);
-    if (bp->dirtyp == NULL && cm_data.buf_dirtyListEndp != bp) {
-       buf_HoldLocked(bp);
-       if (!cm_data.buf_dirtyListp) {
-           cm_data.buf_dirtyListp = cm_data.buf_dirtyListEndp = bp;
-       } else {
-           cm_data.buf_dirtyListEndp->dirtyp = bp;
-           cm_data.buf_dirtyListEndp = bp;
-       }
-       bp->dirtyp = NULL;
+        /* and turn off EOF flag, since it has associated data now */
+        bp->flags &= ~CM_BUF_EOF;
+
+        bp->dirty_offset = offset;
+        bp->dirty_length = length;
+
+        /* and add to the dirty list.  
+         * we obtain a hold on the buffer for as long as it remains 
+         * in the list.  buffers are only removed from the list by 
+         * the buf_IncrSyncer function regardless of when else the
+         * dirty flag might be cleared.
+         *
+         * This should never happen but just in case there is a bug
+         * elsewhere, never add to the dirty list if the buffer is 
+         * already there.
+         */
+        if (bp->dirtyp == NULL && cm_data.buf_dirtyListEndp != bp) {
+            buf_HoldLocked(bp);
+            if (!cm_data.buf_dirtyListp) {
+                cm_data.buf_dirtyListp = cm_data.buf_dirtyListEndp = bp;
+            } else {
+                cm_data.buf_dirtyListEndp->dirtyp = bp;
+                cm_data.buf_dirtyListEndp = bp;
+            }
+            bp->dirtyp = NULL;
+        }
     }
     lock_ReleaseWrite(&buf_globalLock);
 }
@@ -1340,6 +1360,8 @@ long buf_Truncate(cm_scache_t *scp, cm_user_t *userp, cm_req_t *reqp,
             if (LargeIntegerLessThanOrEqualTo(*sizep, bufp->offset)) {
                 /* truncating the entire page */
                 bufp->flags &= ~CM_BUF_DIRTY;
+                bufp->dirty_offset = 0;
+                bufp->dirty_length = 0;
                 bufp->dataVersion = -1;        /* known bad */
                 bufp->dirtyCounter++;
             }
@@ -1678,8 +1700,11 @@ long buf_DirtyBuffersExist(cm_fid_t *fidp)
 {
     cm_buf_t *bp;
     afs_uint32 bcount = 0;
+    afs_uint32 i;
 
-    for (bp = cm_data.buf_allp; bp; bp=bp->allp, bcount++) {
+    i = BUF_FILEHASH(fidp);
+
+    for (bp = cm_data.buf_fileHashTablepp[i]; bp; bp=bp->allp, bcount++) {
        if (!cm_FidCmp(fidp, &bp->fid) && (bp->flags & CM_BUF_DIRTY))
            return 1;
     }
@@ -1699,6 +1724,8 @@ long buf_CleanDirtyBuffers(cm_scache_t *scp)
            lock_ObtainMutex(&bp->mx);
            bp->cmFlags &= ~CM_BUF_CMSTORING;
            bp->flags &= ~CM_BUF_DIRTY;
+            bp->dirty_offset = 0;
+            bp->dirty_length = 0;
            bp->flags |= CM_BUF_ERROR;
            bp->error = VNOVNODE;
            bp->dataVersion = -1; /* bad */
index 53183f8..29e6445 100644 (file)
@@ -72,26 +72,31 @@ typedef struct cm_buf {
     long dirtyCounter;         /* bumped at each dirty->clean transition */
     osi_hyper_t offset;                /* offset */
     cm_fid_t fid;              /* file ID */
-#ifdef DEBUG
-    cm_scache_t *scp;          /* for debugging, the scache object belonging to */
-                                /* the fid at the time of fid assignment. */
-#endif
     long flags;                        /* flags we're using */
     char *datap;               /* data in this buffer */
     unsigned long error;       /* last error code, if CM_BUF_ERROR is set */
     cm_user_t *userp;          /* user who wrote to the buffer last */
-    OVERLAPPED over;           /* overlapped structure for I/O */
         
     /* fields added for the CM; locked by scp->mx */
     long dataVersion;          /* data version of this page */
     long cmFlags;              /* flags for cm */
+
+    /* syncop state */
+    afs_uint32 waitCount;       /* number of threads waiting */
+    afs_uint32 waitRequests;    /* num of thread wait requests */
+
+    afs_uint32 dirty_offset;    /* offset from beginning of buffer containing dirty bytes */
+    afs_uint32 dirty_length;      /* number of dirty bytes within the buffer */
+
 #ifdef DISKCACHE95
     cm_diskcache_t *dcp;        /* diskcache structure */
 #endif /* DISKCACHE95 */
-
-    /* syncop state */
-    afs_uint32 waitCount;           /* number of threads waiting */
-    afs_uint32 waitRequests;        /* num of thread wait requests */
+#ifdef DEBUG
+    cm_scache_t *scp;          /* for debugging, the scache object belonging to */
+                                /* the fid at the time of fid assignment. */
+#else
+    void * dummy;
+#endif
 } cm_buf_t;
 
 /* values for cmFlags */
@@ -161,7 +166,7 @@ extern long buf_CleanAsync(cm_buf_t *, cm_req_t *);
 
 extern void buf_CleanWait(cm_scache_t *, cm_buf_t *);
 
-extern void buf_SetDirty(cm_buf_t *);
+extern void buf_SetDirty(cm_buf_t *, afs_uint32 offset, afs_uint32 length);
 
 extern long buf_CleanAndReset(void);
 
index 2363054..9689d52 100644 (file)
@@ -13,7 +13,7 @@
 #define CM_CONFIGDEFAULT_CACHESIZE     98304
 #define CM_CONFIGDEFAULT_BLOCKSIZE     4096
 #define CM_CONFIGDEFAULT_STATS         10000
-#define CM_CONFIGDEFAULT_CHUNKSIZE     17
+#define CM_CONFIGDEFAULT_CHUNKSIZE     20
 #define CM_CONFIGDEFAULT_DAEMONS       2
 #define CM_CONFIGDEFAULT_SVTHREADS     25
 #define CM_CONFIGDEFAULT_TRACEBUFSIZE  5000
index a8ee555..ab37e48 100644 (file)
@@ -1252,8 +1252,10 @@ void cm_ReleaseBIOD(cm_bulkIO_t *biop, int isStore, int failed)
                }
                if (failed)
                    bufp->flags &= ~CM_BUF_WRITING;
-               else
+               else {
                    bufp->flags &= ~(CM_BUF_WRITING | CM_BUF_DIRTY);
+                    bufp->dirty_offset = bufp->dirty_length = 0;
+                }
            }
 
            lock_ReleaseMutex(&scp->mx);
index 437c999..20c6d8e 100644 (file)
@@ -105,6 +105,8 @@ long cm_RecycleSCache(cm_scache_t *scp, afs_int32 flags)
                lock_ObtainMutex(&bufp->mx);
                bufp->cmFlags &= ~CM_BUF_CMSTORING;
                bufp->flags &= ~CM_BUF_DIRTY;
+                bufp->dirty_offset = 0;
+                bufp->dirty_length = 0;
                bufp->flags |= CM_BUF_ERROR;
                bufp->error = VNOVNODE;
                bufp->dataVersion = -1; /* bad */
@@ -125,6 +127,8 @@ long cm_RecycleSCache(cm_scache_t *scp, afs_int32 flags)
                lock_ObtainMutex(&bufp->mx);
                bufp->cmFlags &= ~CM_BUF_CMFETCHING;
                bufp->flags &= ~CM_BUF_DIRTY;
+                bufp->dirty_offset = 0;
+                bufp->dirty_length = 0;
                bufp->flags |= CM_BUF_ERROR;
                bufp->error = VNOVNODE;
                bufp->dataVersion = -1; /* bad */
index cd0c521..0a6b07e 100644 (file)
@@ -155,11 +155,11 @@ long WriteData(cm_scache_t *scp, osi_hyper_t offset, long count, char *op,
     long written = 0;
     osi_hyper_t fileLength;    /* file's length at start of write */
     osi_hyper_t minLength;     /* don't read past this */
-    long nbytes;               /* # of bytes to transfer this iteration */
+    afs_uint32 nbytes;         /* # of bytes to transfer this iteration */
     cm_buf_t *bufferp;
     osi_hyper_t thyper;                /* hyper tmp variable */
     osi_hyper_t bufferOffset;
-    long bufIndex;                     /* index in buffer where our data is */
+    afs_uint32 bufIndex;       /* index in buffer where our data is */
     int doWriteBack;
     osi_hyper_t writeBackOffset;       /* offset of region to write back when
     * I/O is done */
@@ -328,7 +328,7 @@ long WriteData(cm_scache_t *scp, osi_hyper_t offset, long count, char *op,
 
         /* now copy the data */
        memcpy(bufferp->datap + bufIndex, op, nbytes);
-        buf_SetDirty(bufferp);
+        buf_SetDirty(bufferp, bufIndex, nbytes);
 
         /* and record the last writer */
         if (bufferp->userp != userp) {
index ccefda0..3b211c8 100644 (file)
@@ -6122,11 +6122,11 @@ long smb_WriteData(smb_fid_t *fidp, osi_hyper_t *offsetp, long count, char *op,
     cm_scache_t *scp;
     osi_hyper_t fileLength;    /* file's length at start of write */
     osi_hyper_t minLength;     /* don't read past this */
-    long nbytes;               /* # of bytes to transfer this iteration */
+    afs_uint32 nbytes;         /* # of bytes to transfer this iteration */
     cm_buf_t *bufferp;
     osi_hyper_t thyper;                /* hyper tmp variable */
     osi_hyper_t bufferOffset;
-    long bufIndex;             /* index in buffer where our data is */
+    afs_uint32 bufIndex;               /* index in buffer where our data is */
     int doWriteBack;
     osi_hyper_t writeBackOffset;/* offset of region to write back when
                                  * I/O is done */
@@ -6308,7 +6308,7 @@ long smb_WriteData(smb_fid_t *fidp, osi_hyper_t *offsetp, long count, char *op,
 
         /* now copy the data */
        memcpy(bufferp->datap + bufIndex, op, nbytes);
-        buf_SetDirty(bufferp);
+        buf_SetDirty(bufferp, bufIndex, nbytes);
 
         /* and record the last writer */
         if (bufferp->userp != userp) {