If the minimum checkpoint number of valid checkpoints is large to some
extent, "lscp -r" command takes very long time:
$ lscp -r
CNO DATE TIME MODE FLG BLKCNT ICNT
6541269 2015-02-11 18:38:30 cp - 435 2
6541268 2015-02-11 18:38:25 cp - 484 51
<the command looks to enter a busy loop>
This is because it tries to find younger checkpoints tracking back the
checkpoint list in a constant step size.
This fixes the issue by lengthening or shortening the step size
depending on whether the backward search found a younger checkpoint or
not.
This patch also inserts a dummy nilfs_get_cpinfo() call before
starting the backward search to make successive nilfs_get_cpinfo()
calls much faster.
Signed-off-by: Ryusuke Konishi <[email protected]>
---
bin/lscp.c | 96 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++------
1 file changed, 87 insertions(+), 9 deletions(-)
diff --git a/bin/lscp.c b/bin/lscp.c
index c855def..023be5c 100644
--- a/bin/lscp.c
+++ b/bin/lscp.c
@@ -84,6 +84,12 @@ static const struct option long_option[] = {
#define LSCP_NCPINFO 512
#define LSCP_MINDELTA 64 /* Minimum delta for reverse direction */
+enum lscp_state {
+ LSCP_INIT_ST, /* Initial state */
+ LSCP_NORMAL_ST, /* Normal state */
+ LSCP_ACCEL_ST, /* Accelerate state */
+ LSCP_DECEL_ST, /* Decelerate state */
+};
static __u64 param_index;
static __u64 param_lines;
@@ -176,35 +182,107 @@ static int lscp_backward_cpinfo(struct nilfs *nilfs,
struct nilfs_cpinfo *cpi;
nilfs_cno_t sidx; /* start index (inclusive) */
nilfs_cno_t eidx; /* end index (exclusive) */
- __u64 rest, delta;
+ nilfs_cno_t prev_head = 0;
+ __u64 rest, delta, v;
+ int state = LSCP_INIT_ST;
ssize_t n;
rest = param_lines && param_lines < cpstat->cs_ncps ? param_lines :
cpstat->cs_ncps;
+ if (!rest)
+ goto out;
eidx = param_index && param_index < cpstat->cs_cno ? param_index + 1 :
cpstat->cs_cno;
- for ( ; rest > 0 && eidx > NILFS_CNO_MIN; eidx = sidx) {
- delta = min_t(__u64, LSCP_NCPINFO,
- max_t(__u64, rest, LSCP_MINDELTA));
- sidx = (eidx >= NILFS_CNO_MIN + delta) ? eidx - delta :
- NILFS_CNO_MIN;
+recalc_delta:
+ delta = min_t(__u64, LSCP_NCPINFO, max_t(__u64, rest, LSCP_MINDELTA));
+ v = delta;
- n = lscp_get_cpinfo(nilfs, sidx, NILFS_CHECKPOINT, eidx - sidx);
+ while (eidx > NILFS_CNO_MIN) {
+ if (eidx < NILFS_CNO_MIN + v || state == LSCP_INIT_ST)
+ sidx = NILFS_CNO_MIN;
+ else
+ sidx = eidx - v;
+
+ n = lscp_get_cpinfo(nilfs, sidx, NILFS_CHECKPOINT,
+ state == LSCP_NORMAL_ST ? eidx - sidx : 1);
if (n < 0)
return n;
if (!n)
break;
- for (cpi = cpinfos + n - 1; cpi >= cpinfos && rest > 0; cpi--) {
+ if (state == LSCP_INIT_ST) {
+ /*
+ * This state makes succesive
+ * nilfs_get_cpinfo() calls much faster by
+ * setting minimum checkpoint number in nilfs
+ * struct.
+ */
+ if (cpinfos[0].ci_cno >= eidx)
+ goto out; /* out of range */
+ state = LSCP_NORMAL_ST;
+ continue;
+ } else if (cpinfos[0].ci_cno == prev_head) {
+ /* No younger checkpoint was found */
+
+ if (sidx == NILFS_CNO_MIN)
+ break;
+
+ /* go further back */
+ switch (state) {
+ case LSCP_NORMAL_ST:
+ state = LSCP_ACCEL_ST;
+ /* fall through */
+ case LSCP_ACCEL_ST:
+ if ((v << 1) > v)
+ v <<= 1;
+ break;
+ case LSCP_DECEL_ST:
+ state = LSCP_NORMAL_ST;
+ v = delta;
+ break;
+ }
+ eidx = sidx;
+ continue;
+ } else {
+ switch (state) {
+ case LSCP_ACCEL_ST:
+ case LSCP_DECEL_ST:
+ if (cpinfos[n - 1].ci_cno + 1 < prev_head) {
+ /* search again more slowly */
+ v >>= 1;
+ if (v <= delta) {
+ state = LSCP_NORMAL_ST;
+ v = delta;
+ } else {
+ state = LSCP_DECEL_ST;
+ }
+ continue;
+ }
+ break;
+ default:
+ break;
+ }
+ }
+
+ state = LSCP_NORMAL_ST;
+ cpi = &cpinfos[n - 1];
+ do {
if (cpi->ci_cno < eidx &&
(show_all || nilfs_cpinfo_snapshot(cpi) ||
!nilfs_cpinfo_minor(cpi))) {
lscp_print_cpinfo(cpi);
rest--;
+ if (rest == 0)
+ goto out;
}
- }
+ } while (--cpi >= cpinfos);
+
+ prev_head = cpinfos[0].ci_cno;
+ eidx = sidx;
+ goto recalc_delta;
}
+out:
return 0;
}
--
1.8.3.1
--
To unsubscribe from this list: send the line "unsubscribe linux-nilfs" in
the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html