dafs-kill-xcpu-dump-vlru-stats-20080318
authorTom Keiser <tkeiser@sinenomine.net>
Tue, 18 Mar 2008 16:05:09 +0000 (16:05 +0000)
committerDerrick Brashear <shadow@dementia.org>
Tue, 18 Mar 2008 16:05:09 +0000 (16:05 +0000)
LICENSE BSD

this will dump the current dafs vlru state on kill -XCPU (just as we dump other fileserver state)

that state is
VLRU is a garbage collection facility which automatically offlines
volumes in the background. The purpose of this facility is to
proactively offline infrequently used volumes to improve shutdown and
salvage times. The process of offlining a volume from the "attached"
state to the "pre-attached" state is called soft detachment.

VLRU works in a manner similar to a generational garbage collector.
There are five queues on which volumes can reside: new, intermediate,
old, held, and candidate:

held:

queue for volumes which are administratively barred from VLRU activity

candidate:

queue for volumes which have not been accessed recently, and are thus
candidates for soft detachment

new, intermediate, old:

generational queues for active volumes; state transitions controlled by
inactivity timers.

State transition timeouts are as follows:

candidate->new activity present
new->candidate (1*vlruthresh) minutes since last transition; no activity
new->mid (2*vlruthresh) minutes since last transition; activity
present
mid->old (4*vlruthresh) minutes since last transition; activity
present
old->mid (2*vlruthresh) minutes since last transition; no activity
mid->new (1*vlruthresh) minutes since last transition; no activity

src/vol/volume.c

index 33c7ddd..a35bc52 100644 (file)
@@ -6996,10 +6996,110 @@ DoubleToPrintable(double x, char * buf, int len)
     return buf;
 }
 
+struct VLRUExtStatsEntry {
+    VolumeId volid;
+};
+
+struct VLRUExtStats {
+    afs_uint32 len;
+    afs_uint32 used;
+    struct {
+       afs_uint32 start;
+       afs_uint32 len;
+    } queue_info[VLRU_QUEUE_INVALID];
+    struct VLRUExtStatsEntry * vec;
+};
+
+/** 
+ * add a 256-entry fudge factor onto the vector in case state changes
+ * out from under us.
+ */
+#define VLRU_EXT_STATS_VEC_LEN_FUDGE   256
+
+/**
+ * collect extended statistics for the VLRU subsystem.
+ *
+ * @param[out] stats  pointer to stats structure to be populated
+ * @param[in] nvols   number of volumes currently known to exist
+ *
+ * @pre VOL_LOCK held
+ *
+ * @post stats->vec allocated and populated
+ *
+ * @return operation status
+ *    @retval 0 success
+ *    @retval 1 failure
+ */
+static int
+VVLRUExtStats_r(struct VLRUExtStats * stats, afs_uint32 nvols)
+{
+    afs_uint32 cur, idx, len;
+    struct rx_queue * qp, * nqp;
+    Volume * vp;
+    struct VLRUExtStatsEntry * vec;
+
+    len = nvols + VLRU_EXT_STATS_VEC_LEN_FUDGE;
+    vec = stats->vec = calloc(len,
+                             sizeof(struct VLRUExtStatsEntry));
+    if (vec == NULL) {
+       return 1;
+    }
+
+    cur = 0;
+    for (idx = VLRU_QUEUE_NEW; idx < VLRU_QUEUE_INVALID; idx++) {
+       VLRU_Wait_r(&volume_LRU.q[idx]);
+       VLRU_BeginExclusive_r(&volume_LRU.q[idx]);
+       VOL_UNLOCK;
+
+       stats->queue_info[idx].start = cur;
+
+       for (queue_Scan(&volume_LRU.q[idx], qp, nqp, rx_queue)) {
+           if (cur == len) {
+               /* out of space in vec */
+               break;
+           }
+           vp = (Volume *)((char *)qp - offsetof(Volume, vlru));
+           vec[cur].volid = vp->hashid;
+           cur++;
+       }
+
+       stats->queue_info[idx].len = cur - stats->queue_info[idx].start;
+
+       VOL_LOCK;
+       VLRU_EndExclusive_r(&volume_LRU.q[idx]);
+    }
+
+    stats->len = len;
+    stats->used = cur;
+    return 0;
+}
+
+#define ENUMTOSTRING(en)  #en
+#define ENUMCASE(en) \
+    case en: \
+        return ENUMTOSTRING(en); \
+        break
+
+static char *
+vlru_idx_to_string(int idx)
+{
+    switch (idx) {
+       ENUMCASE(VLRU_QUEUE_NEW);
+       ENUMCASE(VLRU_QUEUE_MID);
+       ENUMCASE(VLRU_QUEUE_OLD);
+       ENUMCASE(VLRU_QUEUE_CANDIDATE);
+       ENUMCASE(VLRU_QUEUE_HELD);
+       ENUMCASE(VLRU_QUEUE_INVALID);
+    default:
+       return "**UNKNOWN**";
+    }
+}
+
 void
 VPrintExtendedCacheStats_r(int flags)
 {
     int i, j;
+    afs_uint32 vol_sum = 0;
     struct stats {
        double min;
        double max;
@@ -7011,6 +7111,7 @@ VPrintExtendedCacheStats_r(int flags)
     char pr_buf[4][32];
     VolumeHashChainHead *head;
     Volume *vp, *np;
+    struct VLRUExtStats vlru_stats;
 
     /* zero out stats */
     memset(&looks, 0, sizeof(struct stats));
@@ -7038,6 +7139,7 @@ VPrintExtendedCacheStats_r(int flags)
            gets.sum     += ch_gets.sum;
            reorders.sum += ch_reorders.sum;
            len.sum      += (double)head->len;
+           vol_sum      += head->len;
            
            if (i == 0) {
                len.min      = (double) head->len;
@@ -7201,6 +7303,8 @@ VPrintExtendedCacheStats_r(int flags)
        VOL_UNLOCK;
        for (i = 0; i <= VOLMAXPARTS; i++) {
            if (part_exists[i]) {
+               /* XXX while this is currently safe, it is a violation
+                *     of the VGetPartitionById_r interface contract. */
                diskP = VGetPartitionById_r(i, 0);
                if (diskP) {
                    Log("Partition %s has %d online volumes\n", 
@@ -7211,6 +7315,43 @@ VPrintExtendedCacheStats_r(int flags)
        VOL_LOCK;
     }
 
+    /* print extended VLRU statistics */
+    if (VVLRUExtStats_r(&vlru_stats, vol_sum) == 0) {
+       afs_uint32 idx, cur, lpos;
+       VOL_UNLOCK;
+       VolumeId line[5];
+
+       Log("VLRU State Dump:\n\n");
+
+       for (idx = VLRU_QUEUE_NEW; idx < VLRU_QUEUE_INVALID; idx++) {
+           Log("\t%s:\n", vlru_idx_to_string(idx));
+
+           lpos = 0;
+           for (cur = vlru_stats.queue_info[idx].start;
+                cur < vlru_stats.queue_info[idx].len;
+                cur++) {
+               line[lpos++] = vlru_stats.vec[cur].volid;
+               if (lpos==5) {
+                   Log("\t\t%u, %u, %u, %u, %u,\n",
+                       line[0], line[1], line[2], line[3], line[4]);
+                   lpos = 0;
+               }
+           }
+
+           if (lpos) {
+               while (lpos < 5) {
+                   line[lpos++] = 0;
+               }
+               Log("\t\t%u, %u, %u, %u, %u\n",
+                   line[0], line[1], line[2], line[3], line[4]);
+           }
+           Log("\n");
+       }
+
+       free(vlru_stats.vec);
+
+       VOL_LOCK;
+    }
 }
 
 void