]> git.michaelhowe.org Git - packages/o/openafs.git/commitdiff
DEVEL15-windows-afsd-btree-20090228
authorJeffrey Altman <jaltman@secure-endpoints.com>
Sat, 28 Feb 2009 15:41:44 +0000 (15:41 +0000)
committerJeffrey Altman <jaltman@secure-endpoints.com>
Sat, 28 Feb 2009 15:41:44 +0000 (15:41 +0000)
LICENSE MIT

Change how BPlusDir enumerations behave with regards to bulk stat
operations.  If the number of entries in the enumeration is larger
than the number of cm_scache objects, then using the previous model
of cm_BPlusDirEnumBulkStat being called for the entire enumeration
list results in the early objects being recycled and the status
info discarded before the caller of cm_BPlusDirNextEnumEntry()
receives the name.

The revised model triggers bulk stat operations from within
NextEnumEntry() as objects requiring status fetching are about
to be returned to the caller.  This reduces the thrashing of the
stat cache.

We should consider adding a flag field to cm_BPlusDirEnumerate()
or cm_BPlusDirNextEnumEntry() to permit enumeration without
status fetching.

(cherry picked from commit a32971251670acc7944dcd4b1eade1ab161e587f)

src/WINNT/afsd/cm_btree.c
src/WINNT/afsd/cm_btree.h

index 7e2492611e94c91ba1ca2cc74fb5264b5174c2e6..8eddc02097ebf4e96f5e5abecd9651f665e89e6a 100644 (file)
@@ -1613,7 +1613,7 @@ cm_BPlusDirLookupOriginalName(cm_dirOp_t * op, clientchar_t *centry,
          */
         slot = getSlot(op->scp->dirBplus, leafNode);
         if (slot <= BTERROR) {
-            op->scp->dirDataVersion = 0;
+            op->scp->dirDataVersion = CM_SCACHE_VERSION_BAD;
             rc = (slot == BTERROR ? EINVAL : ENOENT);
             goto done;
         }
@@ -2170,8 +2170,8 @@ cm_BPlusEnumAlloc(afs_uint32 entries)
 }
 
 long 
-cm_BPlusDirEnumerate(cm_scache_t *scp, afs_uint32 locked
-                     clientchar_t * maskp, cm_direnum_t **enumpp)
+cm_BPlusDirEnumerate(cm_scache_t *scp, cm_user_t *userp, cm_req_t *reqp
+                     afs_uint32 locked, clientchar_t * maskp, cm_direnum_t **enumpp)
 {
     afs_uint32 count = 0, slot, numentries;
     Nptr leafNode = NONODE, nextLeafNode;
@@ -2191,6 +2191,7 @@ cm_BPlusDirEnumerate(cm_scache_t *scp, afs_uint32 locked,
      * recycled while the enumeration is active. 
      */
     cm_HoldSCache(scp);
+    cm_HoldUser(userp);
 
     if (scp->dirBplus == NULL) {
        osi_Log0(afsd_logp, "cm_BPlusDirEnumerate No BPlus Tree");
@@ -2292,6 +2293,8 @@ cm_BPlusDirEnumerate(cm_scache_t *scp, afs_uint32 locked,
     }   
 
     enump->dscp = scp;
+    enump->userp = userp;
+    enump->reqFlags = reqp->flags;
 
   done:
     if (!locked)
@@ -2303,6 +2306,7 @@ cm_BPlusDirEnumerate(cm_scache_t *scp, afs_uint32 locked,
        
         /* release the directory because we failed to generate an enumeration object */
         cm_ReleaseSCache(scp);
+        cm_ReleaseUser(userp);
         if (enump) {
            for ( count = 0; count < enump->count && enump->entry[count].name; count++ ) {
                free(enump->entry[count].name);
@@ -2318,12 +2322,17 @@ cm_BPlusDirEnumerate(cm_scache_t *scp, afs_uint32 locked,
 }
 
 long 
-cm_BPlusDirEnumBulkStat(cm_direnum_t *enump, cm_user_t *userp, cm_req_t *reqp)
+cm_BPlusDirEnumBulkStat(cm_direnum_t *enump)
 {
     cm_scache_t *dscp = enump->dscp;
+    cm_user_t   *userp = enump->userp;
     cm_bulkStat_t *bsp;
     afs_uint32 count;
-    afs_uint32 code;
+    afs_uint32 code = 0;
+    cm_req_t req;
+
+    cm_InitReq(&req);
+    req.flags = enump->reqFlags;
 
     if ( dscp->fid.cell == AFS_FAKE_ROOT_CELL_ID )
         return 0;
@@ -2345,6 +2354,7 @@ cm_BPlusDirEnumBulkStat(cm_direnum_t *enump, cm_user_t *userp, cm_req_t *reqp)
                      */
                     lock_ReleaseWrite(&tscp->rw);
                     cm_ReleaseSCache(tscp);
+                    enump->entry[count].flags |= CM_DIRENUM_FLAG_GOT_STATUS;
                     continue;
                 }
                 lock_ReleaseWrite(&tscp->rw);
@@ -2356,21 +2366,82 @@ cm_BPlusDirEnumBulkStat(cm_direnum_t *enump, cm_user_t *userp, cm_req_t *reqp)
         bsp->fids[i].Volume = enump->entry[count].fid.volume;
         bsp->fids[i].Vnode = enump->entry[count].fid.vnode;
         bsp->fids[i].Unique = enump->entry[count].fid.unique;
+        enump->entry[count].flags |= CM_DIRENUM_FLAG_GOT_STATUS;
 
         if (bsp->counter == AFSCBMAX) {
-            code = cm_TryBulkStatRPC(dscp, bsp, userp, reqp);
+            code = cm_TryBulkStatRPC(dscp, bsp, userp, &req);
             memset(bsp, 0, sizeof(cm_bulkStat_t));
         }
     }
 
     if (bsp->counter > 0)
-        code = cm_TryBulkStatRPC(dscp, bsp, userp, reqp);
+        code = cm_TryBulkStatRPC(dscp, bsp, userp, &req);
 
     free(bsp);
-    return 0;
+    return code;
 }
 
-long 
+static long 
+cm_BPlusDirEnumBulkStatNext(cm_direnum_t *enump)
+{
+    cm_scache_t *dscp = enump->dscp;
+    cm_user_t   *userp = enump->userp;
+    cm_bulkStat_t *bsp;
+    afs_uint32 count;
+    afs_uint32 code = 0;
+    cm_req_t req;
+
+    cm_InitReq(&req);
+    req.flags = enump->reqFlags;
+
+    if ( dscp->fid.cell == AFS_FAKE_ROOT_CELL_ID )
+        return 0;
+
+    bsp = malloc(sizeof(cm_bulkStat_t));
+    memset(bsp, 0, sizeof(cm_bulkStat_t));
+
+    for ( count = enump->next; count < enump->count; count++ ) {
+        cm_scache_t   *tscp = cm_FindSCache(&enump->entry[count].fid);
+        int i;
+
+        if (tscp) {
+            if (lock_TryWrite(&tscp->rw)) {
+                /* we have an entry that we can look at */
+                if (!(tscp->flags & CM_SCACHEFLAG_EACCESS) && cm_HaveCallback(tscp)) {
+                    /* we have a callback on it.  Don't bother
+                     * fetching this stat entry, since we're happy
+                     * with the info we have.
+                     */
+                    lock_ReleaseWrite(&tscp->rw);
+                    cm_ReleaseSCache(tscp);
+                    enump->entry[count].flags |= CM_DIRENUM_FLAG_GOT_STATUS;
+                    continue;
+                }
+                lock_ReleaseWrite(&tscp->rw);
+            }  /* got lock */
+            cm_ReleaseSCache(tscp);
+        }      /* found entry */
+
+        i = bsp->counter++;
+        bsp->fids[i].Volume = enump->entry[count].fid.volume;
+        bsp->fids[i].Vnode = enump->entry[count].fid.vnode;
+        bsp->fids[i].Unique = enump->entry[count].fid.unique;
+        enump->entry[count].flags |= CM_DIRENUM_FLAG_GOT_STATUS;
+
+        if (bsp->counter == AFSCBMAX) {
+            code = cm_TryBulkStatRPC(dscp, bsp, userp, &req);
+            break;
+        }
+    }
+
+    if (bsp->counter > 0 && bsp->counter < AFSCBMAX)
+        code = cm_TryBulkStatRPC(dscp, bsp, userp, &req);
+
+    free(bsp);
+    return code;
+}
+
+long
 cm_BPlusDirNextEnumEntry(cm_direnum_t *enump, cm_direnum_entry_t **entrypp)
 {      
     if (enump == NULL || entrypp == NULL || enump->next >= enump->count) {
@@ -2380,6 +2451,9 @@ cm_BPlusDirNextEnumEntry(cm_direnum_t *enump, cm_direnum_entry_t **entrypp)
        return CM_ERROR_INVAL;
     }
 
+    if (!(enump->entry[enump->next].flags & CM_DIRENUM_FLAG_GOT_STATUS)) 
+        cm_BPlusDirEnumBulkStatNext(enump);
+
     *entrypp = &enump->entry[enump->next++];
     if ( enump->next == enump->count ) {
        osi_Log0(afsd_logp, "cm_BPlusDirNextEnumEntry STOPNOW");
@@ -2401,6 +2475,7 @@ cm_BPlusDirFreeEnumeration(cm_direnum_t *enump)
     if (enump) {
         /* Release the directory object */
         cm_ReleaseSCache(enump->dscp);
+        cm_ReleaseUser(enump->userp);
 
        for ( count = 0; count < enump->count && enump->entry[count].name; count++ ) {
            free(enump->entry[count].name);
@@ -2411,15 +2486,16 @@ cm_BPlusDirFreeEnumeration(cm_direnum_t *enump)
 }
 
 long
-cm_BPlusDirEnumTest(cm_scache_t * dscp, afs_uint32 locked)
+cm_BPlusDirEnumTest(cm_scache_t * dscp, cm_user_t *userp, cm_req_t *reqp, afs_uint32 locked)
 {
     cm_direnum_t *      enump = NULL;
     cm_direnum_entry_t * entryp;
     long                code;
 
+
     osi_Log0(afsd_logp, "cm_BPlusDirEnumTest start");
 
-    for (code = cm_BPlusDirEnumerate(dscp, locked, NULL, &enump); code == 0; ) {
+    for (code = cm_BPlusDirEnumerate(dscp, userp, reqp, locked, NULL, &enump); code == 0; ) {
        code = cm_BPlusDirNextEnumEntry(enump, &entryp);
        if (code == 0 || code == CM_ERROR_STOPNOW) {
            char buffer[1024];
index 5989dfd81e84b552a9d1a56ad5af4f0377b5178b..f5c897dd864dc1c6785397dea25645f30f4517b5 100644 (file)
@@ -156,20 +156,26 @@ typedef struct cm_direnum_entry {
     clientchar_t *name;
     cm_fid_t    fid;
     normchar_t   shortName[13];
+    afs_uint32   flags;
 } cm_direnum_entry_t;
 
+#define CM_DIRENUM_FLAG_GOT_STATUS     1
+
 typedef struct cm_direnum {
     cm_scache_t        *dscp;
+    cm_user_t          *userp;
+    afs_uint32          reqFlags;
     afs_uint32         count;
     afs_uint32         next;
     cm_direnum_entry_t         entry[1];
 } cm_direnum_t;
 
-long cm_BPlusDirEnumerate(cm_scache_t *dscp, afs_uint32 locked, clientchar_t *maskp, cm_direnum_t **enumpp);
+long cm_BPlusDirEnumerate(cm_scache_t *dscp, cm_user_t *userp, cm_req_t *reqp, 
+                          afs_uint32 locked, clientchar_t *maskp, cm_direnum_t **enumpp);
 long cm_BPlusDirNextEnumEntry(cm_direnum_t *enump, cm_direnum_entry_t **entrypp);
 long cm_BPlusDirFreeEnumeration(cm_direnum_t *enump);
-long cm_BPlusDirEnumTest(cm_scache_t * dscp, afs_uint32 locked);
-long cm_BPlusDirEnumBulkStat(cm_direnum_t *enump, cm_user_t *userp, cm_req_t *reqp);
+long cm_BPlusDirEnumTest(cm_scache_t * dscp, cm_user_t *userp, cm_req_t *reqp, afs_uint32 locked);
+long cm_BPlusDirEnumBulkStat(cm_direnum_t *enump);
 
 long cm_InitBPlusDir(void);