]> git.michaelhowe.org Git - packages/o/openafs.git/commitdiff
Windows: Negative Caching for Volume Lookups
authorJeffrey Altman <jaltman@your-file-system.com>
Thu, 16 Sep 2010 12:23:41 +0000 (14:23 +0200)
committerDerrick Brashear <shadow@dementia.org>
Mon, 25 Oct 2010 21:34:32 +0000 (14:34 -0700)
If a volume lookup returns VL_NOENT or VL_BADNAME, cache the negative
response for five minutes.  This prevents volume lookup storms caused
by the same volume lookup being performed repeated during a short
time period.  This can happen if mount points to volumes that do not
exist are present in a directory that is being evaluated by Windows
Explorer or Common Control File Dialogs.

This functionality is implemented by storing the most recent update
time for the volume group as part of the cm_volume_t.  A non-existing
volume group is identified with a new CM_VOLUMEFLAG_NOEXIST flag.
The presence of the lastUpdateTime value also permits volume location
information to expire at lastUpdateTime + lifetime instead of expiring
all volume information simultaneously each lifetime period.

LICENSE MIT

Reviewed-on: http://gerrit.openafs.org/2771
Reviewed-by: Derrick Brashear <shadow@dementia.org>
Tested-by: BuildBot <buildbot@rampaginggeek.com>
Reviewed-by: Jeffrey Altman <jaltman@openafs.org>
Tested-by: Jeffrey Altman <jaltman@openafs.org>
(cherry picked from commit a00da7d2c9a66f1e5984ec2b3bd3efe10793e1c9)
Change-Id: I3603e746a6df1834612647931cc09228428842db
Reviewed-on: http://gerrit.openafs.org/3132
Tested-by: Derrick Brashear <shadow@dementia.org>
src/WINNT/afsd/cm_daemon.c
src/WINNT/afsd/cm_ioctl.c
src/WINNT/afsd/cm_memmap.c
src/WINNT/afsd/cm_scache.h
src/WINNT/afsd/cm_volume.c
src/WINNT/afsd/cm_volume.h

index fac1be3682fd8b1b17dd89f28211e0074cf89182..72ec25096295ccedcb6186531d1e9fd4dcfad34e 100644 (file)
@@ -507,11 +507,15 @@ void cm_Daemon(long parm)
             cm_VolStatus_Network_Addr_Change();
         }
 
-        if (now > lastVolCheck + cm_daemonCheckVolInterval &&
+        /*
+         * Once every five minutes inspect the volume list and enforce
+         * the volume location expiration time.
+         */
+        if (now > lastVolCheck + 300 &&
             daemon_ShutdownFlag == 0 &&
             powerStateSuspended == 0) {
             lastVolCheck = now;
-            cm_RefreshVolumes();
+            cm_RefreshVolumes(cm_daemonCheckVolInterval);
             if (daemon_ShutdownFlag == 1)
                 break;
            now = osi_Time();
index b25cc0cfa9c4fca37577d05dd8c27f0b6c75ef93..a9bcf15bd5570ecc62c8800edc545f9a3c9d9b62 100644 (file)
@@ -1285,7 +1285,7 @@ cm_IoctlCheckServers(struct cm_ioctl *ioctlp, struct cm_user *userp)
 afs_int32 
 cm_IoctlCheckVolumes(cm_ioctl_t *ioctlp, cm_user_t *userp)
 {
-    cm_RefreshVolumes();
+    cm_RefreshVolumes(0);
     return 0;
 }       
 
index 3b946129167034a58b28395c3ff94bd12fdee4ab..6fb91ed220dbb68decb7aeca0af7e90817c678cf 100644 (file)
@@ -874,7 +874,7 @@ cm_InitMappedMemory(DWORD virtualCache, char * cachePath, DWORD stats, DWORD max
         cm_data.buf_blockSize = blockSize;
         cm_data.buf_hashSize = osi_PrimeLessThan((afs_uint32)(cacheBlocks/7 + 1));
 
-        cm_data.mountRootGen = time(NULL);
+        cm_data.mountRootGen = 0;
 
         baseAddress += ComputeSizeOfConfigData();
         cm_data.volumeBaseAddress = (cm_volume_t *) baseAddress;
index 5bfc6fa1b92f664957e42d992d958c9e5b883555..a04f3140274787ccc0ce12896639c1560e73d5fb 100644 (file)
@@ -145,7 +145,7 @@ typedef struct cm_scache {
                                         * the link contents here.
                                          */
     cm_fid_t  mountRootFid;            /* mounted on root */
-    time_t    mountRootGen;            /* time to update mountRootFidp? */
+    time_t    mountRootGen;            /* time to update mountRootFid? */
     cm_fid_t  dotdotFid;               /* parent of volume root */
 
     /* callback info */
index 9976fe53b3afc53ec88179fa80fdf5427676b0d2..ffdfa43fa7046c1799e057abd27545b7868f8a29 100644 (file)
@@ -190,6 +190,17 @@ long cm_UpdateVolumeLocation(struct cm_cell *cellp, cm_user_t *userp, cm_req_t *
 
     lock_AssertWrite(&volp->rw);
 
+    /*
+     * If the last volume update was in the last five
+     * minutes and it did not exist, then avoid the RPC
+     * and return No Such Volume immediately.
+     */
+    if ((volp->flags & CM_VOLUMEFLAG_NOEXIST) &&
+        volp->lastUpdateTime + 600 < time(0))
+    {
+        return CM_ERROR_NOSUCHVOLUME;
+    }
+
 #ifdef AFS_FREELANCE_CLIENT
     if ( cellp->cellID == AFS_FAKE_ROOT_CELL_ID && volp->vol[RWVOL].ID == AFS_FAKE_ROOT_VOL_ID ) 
     {
@@ -614,28 +625,13 @@ long cm_UpdateVolumeLocation(struct cm_cell *cellp, cm_user_t *userp, cm_req_t *
             cm_RandomizeServer(&volp->vol[ROVOL].serversp);
         }
 
-
         rwNewstate = rwServers_alldown ? vl_alldown : vl_online;
         roNewstate = roServers_alldown ? vl_alldown : vl_online;
         bkNewstate = bkServers_alldown ? vl_alldown : vl_online;
-    } else if (code == CM_ERROR_NOSUCHVOLUME || code == VL_NOENT || code == VL_BADNAME) {
-        /* this volume does not exist - we should discard it */
-        if (volp->flags & CM_VOLUMEFLAG_IN_HASH)
-            cm_RemoveVolumeFromNameHashTable(volp);
-        for ( volType = RWVOL; volType < NUM_VOL_TYPES; volType++) {
-            if (volp->vol[volType].flags & CM_VOLUMEFLAG_IN_HASH)
-                cm_RemoveVolumeFromIDHashTable(volp, volType);
-            if (volp->vol[volType].ID) {
-                cm_VolumeStatusNotification(volp, volp->vol[volType].ID, volp->vol[volType].state, vl_alldown);
-                volp->vol[volType].ID = 0;
-            }
-            cm_SetFid(&volp->vol[volType].dotdotFid, 0, 0, 0, 0);
-        }
-
-        /* Move to the end so it will be recycled first */
-        cm_MoveVolumeToLRULast(volp);
 
-        volp->namep[0] ='\0';
+        volp->flags &= ~CM_VOLUMEFLAG_NOEXIST;
+    } else if (code == CM_ERROR_NOSUCHVOLUME || code == VL_NOENT || code == VL_BADNAME) {
+        volp->flags |= CM_VOLUMEFLAG_NOEXIST;
     } else {
         rwNewstate = roNewstate = bkNewstate = vl_alldown;
     }
@@ -656,6 +652,8 @@ long cm_UpdateVolumeLocation(struct cm_cell *cellp, cm_user_t *userp, cm_req_t *
         volp->vol[BACKVOL].state = bkNewstate;
     }
 
+    volp->lastUpdateTime = time(0);
+
     if (code == 0)
         volp->flags &= ~CM_VOLUMEFLAG_RESET;
 
@@ -1144,48 +1142,40 @@ long cm_GetROVolumeID(cm_volume_t *volp)
     return id;
 }
 
-void cm_RefreshVolumes(void)
+void cm_RefreshVolumes(int lifetime)
 {
     cm_volume_t *volp;
     cm_scache_t *scp;
     afs_int32 refCount;
+    time_t now;
 
-    cm_data.mountRootGen = time(NULL);
+    now = time(NULL);
+
+    /* force mount point target updates */
+    if (cm_data.mountRootGen + lifetime <= now)
+        cm_data.mountRootGen = now;
 
-    /* force a re-loading of volume data from the vldb */
+    /*
+     * force a re-loading of volume data from the vldb
+     * if the lifetime for the cached data has expired
+     */
     lock_ObtainRead(&cm_volumeLock);
     for (volp = cm_data.allVolumesp; volp; volp=volp->allNextp) {
        InterlockedIncrement(&volp->refCount);
        lock_ReleaseRead(&cm_volumeLock);
 
-       lock_ObtainWrite(&volp->rw);
-       volp->flags |= CM_VOLUMEFLAG_RESET;
-       lock_ReleaseWrite(&volp->rw);
-       
+        if (!(volp->flags & CM_VOLUMEFLAG_RESET)) {
+            lock_ObtainWrite(&volp->rw);
+            if (volp->lastUpdateTime + lifetime <= now)
+                volp->flags |= CM_VOLUMEFLAG_RESET;
+            lock_ReleaseWrite(&volp->rw);
+        }
+
         lock_ObtainRead(&cm_volumeLock);
         refCount = InterlockedDecrement(&volp->refCount);
        osi_assertx(refCount >= 0, "cm_volume_t refCount underflow");
     }
     lock_ReleaseRead(&cm_volumeLock);
-
-    /* force mount points to be re-evaluated so that 
-     * if the volume location has changed we will pick 
-     * that up
-     */
-    for ( scp = cm_data.scacheLRUFirstp; 
-          scp;
-          scp = (cm_scache_t *) osi_QNext(&scp->q)) {
-        if ( scp->fileType == CM_SCACHETYPE_MOUNTPOINT 
-#ifdef AFS_FREELANCE_CLIENT
-             && !(scp->fid.cell == AFS_FAKE_ROOT_CELL_ID && scp->fid.volume == AFS_FAKE_ROOT_VOL_ID)
-#endif
-             ) {
-            lock_ObtainWrite(&scp->rw);
-            scp->mountPointStringp[0] = '\0';
-            lock_ReleaseWrite(&scp->rw);
-        }
-    }
-
 }
 
 void
index 7ec1a8c7a7f28eab5ad91fffcd7b645ec1e93f32..44f92c6eec1a8b3c7206c4c9974c3db52bcf96dc 100644 (file)
@@ -45,6 +45,7 @@ typedef struct cm_volume {
     struct cm_server *cbServerpRO;      /* server granting RO callback; by cm_scacheLock */
     time_t cbExpiresRO;                 /* latest RO expiration time; by cm_scacheLock */
     time_t creationDateRO;              /* latest volume creation date; 0 if unknown; by cm_scacheLock */
+    time_t lastUpdateTime;              /* most recent volume location update cm_volumeLock */
 } cm_volume_t;
 
 #define CM_VOLUMEFLAG_RESET       1    /* reload this info on next use */
@@ -52,6 +53,7 @@ typedef struct cm_volume {
 #define CM_VOLUMEFLAG_IN_LRU_QUEUE 4
 #define CM_VOLUMEFLAG_UPDATING_VL  8
 #define CM_VOLUMEFLAG_DFS_VOLUME  16
+#define CM_VOLUMEFLAG_NOEXIST     32
 
 typedef struct cm_volumeRef {
     struct cm_volumeRef * next;
@@ -100,7 +102,7 @@ extern cm_serverRef_t **cm_GetVolServers(cm_volume_t *volp, afs_uint32 volume,
 
 extern void cm_ChangeRankVolume(cm_server_t *tsp);
 
-extern void cm_RefreshVolumes(void);
+extern void cm_RefreshVolumes(int lifetime);
 
 extern long cm_ValidateVolume(void);