From 6c81286368e17bdde543d4d6e5d19512cab62ba3 Mon Sep 17 00:00:00 2001 From: Tom Keiser Date: Tue, 18 Mar 2008 16:05:09 +0000 Subject: [PATCH] dafs-kill-xcpu-dump-vlru-stats-20080318 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 | 141 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 141 insertions(+) diff --git a/src/vol/volume.c b/src/vol/volume.c index 33c7ddd..a35bc52 100644 --- a/src/vol/volume.c +++ b/src/vol/volume.c @@ -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 -- 1.9.4