diff options
-rw-r--r-- | xlators/features/bit-rot/src/bitd/bit-rot-scrub.c | 191 | ||||
-rw-r--r-- | xlators/features/bit-rot/src/bitd/bit-rot.c | 1 | ||||
-rw-r--r-- | xlators/features/bit-rot/src/bitd/bit-rot.h | 5 |
3 files changed, 192 insertions, 5 deletions
diff --git a/xlators/features/bit-rot/src/bitd/bit-rot-scrub.c b/xlators/features/bit-rot/src/bitd/bit-rot-scrub.c index e96d82d6282..390148fdb06 100644 --- a/xlators/features/bit-rot/src/bitd/bit-rot-scrub.c +++ b/xlators/features/bit-rot/src/bitd/bit-rot-scrub.c @@ -508,13 +508,121 @@ br_fsscanner_handle_entry (xlator_t *subvol, return -1; } +/*scrubber frequency tunable value in second (day * hour * minut * second)*/ +#define DAILY (1*24*60*60) +#define WEEKLY (7*24*60*60) +#define BIWEEKLY (14*24*60*60) +#define MONTHLY (30*24*60*60) + +struct timeval +br_scrubber_calc_freq (xlator_t *this) +{ + br_private_t *priv = NULL; + struct timeval scrub_sec = {0,}; + + priv = this->private; + + /*By default scrubber frequency will be biweekly*/ + if (!strncmp (priv->scrub_freq, "daily", strlen("daily"))) { + scrub_sec.tv_sec = DAILY; + } else if (!strncmp (priv->scrub_freq, "weekly", strlen("weekly"))) { + scrub_sec.tv_sec = WEEKLY; + } else if (!strncmp (priv->scrub_freq, "monthly", strlen("monthly"))) { + scrub_sec.tv_sec = MONTHLY; + } else if (!strncmp (priv->scrub_freq, "biweekly", + strlen("biweekly"))) { + scrub_sec.tv_sec = BIWEEKLY; + } else { + gf_log (this->name, GF_LOG_ERROR, "Invalid scrub-frequency %s" + "value.", priv->scrub_freq); + scrub_sec.tv_sec = -1; + } + + return scrub_sec; +} + +#define SCRUBBER_SLEEP(freq_diff, elapse_time) do { \ + \ + if (freq_diff < 0) { \ + return 0; \ + } else if (freq_diff <= DAILY) { \ + gf_log (this->name, GF_LOG_INFO, \ + "Scrubber is sleeping for %ld " \ + "sec", freq_diff); \ + sleep (freq_diff); \ + return 0; \ + } else { \ + gf_log (this->name, GF_LOG_INFO, \ + "Scrubber is sleeping for %ld " \ + "sec", freq_diff); \ + sleep (DAILY); \ + elapse_time += DAILY; \ + } \ + } while (0) + +static int +br_scrubber_sleep_check (struct timeval *begin, struct timeval *end, + xlator_t *this) +{ + br_private_t *priv = NULL; + struct timeval elapse_time = {0,}; + struct timeval freq_diff = {0,}; + struct timeval scrub_sec = {0,}; + struct timeval temp = {0,}; + + priv = this->private; + + scrub_sec = br_scrubber_calc_freq (this); + if (scrub_sec.tv_sec == -1) { + gf_log (this->name, GF_LOG_ERROR, "Unable to calculate scrub " + "frequency %s value", priv->scrub_freq); + return -1; + } + + if ((end->tv_sec - begin->tv_sec) < scrub_sec.tv_sec) { + /* Sleep, if scrubber have completed its job before schedule + * scrub frequency based on current scrub frequency value */ + do { + scrub_sec = br_scrubber_calc_freq (this); + freq_diff.tv_sec = scrub_sec.tv_sec - (end->tv_sec - + begin->tv_sec) - + elapse_time.tv_sec; + SCRUBBER_SLEEP(freq_diff.tv_sec, elapse_time.tv_sec); + } while (1); + + + } else { + /* Sleep, if scrubber have completed its job after schedule + * scrub frequency based on current scrub frequency value */ + temp.tv_sec = (end->tv_sec - begin->tv_sec) % scrub_sec.tv_sec; + if (temp.tv_sec != 0) { + do { + scrub_sec = br_scrubber_calc_freq (this); + freq_diff.tv_sec = scrub_sec.tv_sec + - temp.tv_sec + - elapse_time.tv_sec; + SCRUBBER_SLEEP(freq_diff.tv_sec, + elapse_time.tv_sec); + } while (1); + } + } + + return 0; +} + void * br_fsscanner (void *arg) { - loc_t loc = {0,}; - xlator_t *this = NULL; - br_child_t *child = NULL; - struct br_scanfs *fsscan = NULL; + int32_t ret = -1; + loc_t loc = {0,}; + char timestr[1024] = {0,}; + xlator_t *this = NULL; + br_child_t *child = NULL; + struct br_scanfs *fsscan = NULL; + br_private_t *priv = NULL; + struct timeval elapse_time = {0,}; + struct timeval scrub_sec = {0,}; + struct timeval freq_diff = {0,}; child = arg; this = child->this; @@ -522,13 +630,73 @@ br_fsscanner (void *arg) THIS = this; + priv = this->private; + loc.inode = child->table->root; + + /* Scrubber should start scrubbing the filesystem *after* the + * schedueled scrub-frequency has expired.*/ + do { + /*Calculate current scrub frequency value in second*/ + scrub_sec = br_scrubber_calc_freq (this); + if (scrub_sec.tv_sec == -1) { + gf_log (this->name, GF_LOG_ERROR, "Unable to calculate " + "scrub frequency %s value", priv->scrub_freq); + return NULL; + } + + freq_diff.tv_sec = scrub_sec.tv_sec - elapse_time.tv_sec; + + if (freq_diff.tv_sec < 0) { + break; + } else if (freq_diff.tv_sec == DAILY) { + sleep (DAILY); + break; + } else { + sleep (DAILY); + elapse_time.tv_sec += DAILY; + } + + } while (1); + while (1) { + /* log scrub start time */ + gettimeofday (&priv->tv_before_scrub, NULL); + gf_time_fmt (timestr, sizeof timestr, + priv->tv_before_scrub.tv_sec, gf_timefmt_FT); + gf_log (this->name, GF_LOG_INFO, + "Scrubbing \"%s\" started at %s", + child->brick_path, timestr); + + /* scrub */ (void) syncop_ftw (child->xl, &loc, GF_CLIENT_PID_SCRUB, child, br_fsscanner_handle_entry); if (!list_empty (&fsscan->queued)) wait_for_scrubbing (this, fsscan); + + gettimeofday (&priv->tv_after_scrub, NULL); + /* log scrub finish time */ + gf_time_fmt (timestr, sizeof timestr, + priv->tv_after_scrub.tv_sec, gf_timefmt_FT); + gf_log (this->name, GF_LOG_INFO, + "Scrubbing \"%s\" finished at %s", + child->brick_path, timestr); + + /* Scrubber should sleep if it have completed scrubbing + * of filesystem before the scheduled scrub-frequency*/ + ret = br_scrubber_sleep_check (&priv->tv_before_scrub, + &priv->tv_after_scrub, + this); + if (!ret) { + gf_log (this->name, GF_LOG_DEBUG, "scrubber is crawling" + " file system with scrubber frequency %s", + priv->scrub_freq); + } else { + gf_log (this->name, GF_LOG_ERROR, "Unable to perform " + "scrubber sleep check for scrubber frequency"); + return NULL; + } } return NULL; @@ -920,7 +1088,16 @@ br_scrubber_handle_stall (xlator_t *this, br_private_t *priv, return -1; } -/* TODO: frequency */ +static int32_t +br_scrubber_handle_freq (xlator_t *this, br_private_t *priv, dict_t *options) +{ + int32_t ret = -1; + + ret = br_scrubber_fetch_option (this, "scrub-freq", options, + &priv->scrub_freq); + return ret; +} + int32_t br_scrubber_handle_options (xlator_t *this, br_private_t *priv, dict_t *options) { @@ -935,6 +1112,10 @@ br_scrubber_handle_options (xlator_t *this, br_private_t *priv, dict_t *options) if (ret) goto error_return; + ret = br_scrubber_handle_freq (this, priv, options); + if (ret) + goto error_return; + return 0; error_return: diff --git a/xlators/features/bit-rot/src/bitd/bit-rot.c b/xlators/features/bit-rot/src/bitd/bit-rot.c index 61d461f897b..b9adbd6647c 100644 --- a/xlators/features/bit-rot/src/bitd/bit-rot.c +++ b/xlators/features/bit-rot/src/bitd/bit-rot.c @@ -1728,6 +1728,7 @@ struct volume_options options[] = { }, { .key = {"scrub-freq"}, .type = GF_OPTION_TYPE_STR, + .default_value = "biweekly", .description = "Scrub frequency for volume <VOLNAME>", }, { .key = {"scrub-state"}, diff --git a/xlators/features/bit-rot/src/bitd/bit-rot.h b/xlators/features/bit-rot/src/bitd/bit-rot.h index bbaf86fa65f..1705f715f0c 100644 --- a/xlators/features/bit-rot/src/bitd/bit-rot.h +++ b/xlators/features/bit-rot/src/bitd/bit-rot.h @@ -139,6 +139,11 @@ struct br_private { gf_boolean_t iamscrubber; /* function as a fs scrubber */ struct br_scrubber fsscrub; /* scrubbers for this subvolume */ + + char *scrub_freq; /* Scrubber frequency*/ + + struct timeval tv_before_scrub; /* time before starting scrubbing*/ + struct timeval tv_after_scrub; /* time after scrubbing completion*/ }; typedef struct br_private br_private_t; |