diff --git a/kmod/src/scoutfs_trace.h b/kmod/src/scoutfs_trace.h index 96feeedd..838fe13f 100644 --- a/kmod/src/scoutfs_trace.h +++ b/kmod/src/scoutfs_trace.h @@ -2799,6 +2799,81 @@ TRACE_EVENT(scoutfs_omap_should_delete, SCSB_TRACE_ARGS, __entry->ino, __entry->nlink, __entry->ret) ); +#define SSCF_FMT "[bo %llu bs %llu es %llu]" +#define SSCF_FIELDS(pref) \ + __field(__u64, pref##_blkno) \ + __field(__u64, pref##_blocks) \ + __field(__u64, pref##_entries) +#define SSCF_ASSIGN(pref, sfl) \ + __entry->pref##_blkno = le64_to_cpu((sfl)->ref.blkno); \ + __entry->pref##_blocks = le64_to_cpu((sfl)->blocks); \ + __entry->pref##_entries = le64_to_cpu((sfl)->entries); +#define SSCF_ENTRY_ARGS(pref) \ + __entry->pref##_blkno, \ + __entry->pref##_blocks, \ + __entry->pref##_entries + +DECLARE_EVENT_CLASS(scoutfs_srch_compact_class, + TP_PROTO(struct super_block *sb, struct scoutfs_srch_compact *sc), + + TP_ARGS(sb, sc), + + TP_STRUCT__entry( + SCSB_TRACE_FIELDS + __field(__u64, id) + __field(__u8, nr) + __field(__u8, flags) + SSCF_FIELDS(out) + __field(__u64, in0_blk) + __field(__u64, in0_pos) + SSCF_FIELDS(in0) + __field(__u64, in1_blk) + __field(__u64, in1_pos) + SSCF_FIELDS(in1) + __field(__u64, in2_blk) + __field(__u64, in2_pos) + SSCF_FIELDS(in2) + __field(__u64, in3_blk) + __field(__u64, in3_pos) + SSCF_FIELDS(in3) + ), + + TP_fast_assign( + SCSB_TRACE_ASSIGN(sb); + __entry->id = le64_to_cpu(sc->id); + __entry->nr = sc->nr; + __entry->flags = sc->flags; + SSCF_ASSIGN(out, &sc->out) + __entry->in0_blk = le64_to_cpu(sc->in[0].blk); + __entry->in0_pos = le64_to_cpu(sc->in[0].pos); + SSCF_ASSIGN(in0, &sc->in[0].sfl) + __entry->in1_blk = le64_to_cpu(sc->in[0].blk); + __entry->in1_pos = le64_to_cpu(sc->in[0].pos); + SSCF_ASSIGN(in1, &sc->in[1].sfl) + __entry->in2_blk = le64_to_cpu(sc->in[0].blk); + __entry->in2_pos = le64_to_cpu(sc->in[0].pos); + SSCF_ASSIGN(in2, &sc->in[2].sfl) + __entry->in3_blk = le64_to_cpu(sc->in[0].blk); + __entry->in3_pos = le64_to_cpu(sc->in[0].pos); + SSCF_ASSIGN(in3, &sc->in[3].sfl) + ), + + TP_printk(SCSBF" id %llu nr %u flags 0x%x out "SSCF_FMT" in0 b %llu p %llu "SSCF_FMT" in1 b %llu p %llu "SSCF_FMT" in2 b %llu p %llu "SSCF_FMT" in3 b %llu p %llu "SSCF_FMT, + SCSB_TRACE_ARGS, __entry->id, __entry->nr, __entry->flags, SSCF_ENTRY_ARGS(out), + __entry->in0_blk, __entry->in0_pos, SSCF_ENTRY_ARGS(in0), + __entry->in1_blk, __entry->in1_pos, SSCF_ENTRY_ARGS(in1), + __entry->in2_blk, __entry->in2_pos, SSCF_ENTRY_ARGS(in2), + __entry->in3_blk, __entry->in3_pos, SSCF_ENTRY_ARGS(in3)) +); +DEFINE_EVENT(scoutfs_srch_compact_class, scoutfs_srch_compact_client_send, + TP_PROTO(struct super_block *sb, struct scoutfs_srch_compact *sc), + TP_ARGS(sb, sc) +); +DEFINE_EVENT(scoutfs_srch_compact_class, scoutfs_srch_compact_client_recv, + TP_PROTO(struct super_block *sb, struct scoutfs_srch_compact *sc), + TP_ARGS(sb, sc) +); + #endif /* _TRACE_SCOUTFS_H */ /* This part must be outside protection */ diff --git a/kmod/src/srch.c b/kmod/src/srch.c index 81bc2238..e05f707c 100644 --- a/kmod/src/srch.c +++ b/kmod/src/srch.c @@ -31,6 +31,8 @@ #include "counters.h" #include "scoutfs_trace.h" #include "triggers.h" +#include "sysfs.h" +#include "msg.h" /* * This srch subsystem gives us a way to find inodes that have a given @@ -69,10 +71,14 @@ struct srch_info { atomic_t shutdown; struct workqueue_struct *workq; struct delayed_work compact_dwork; + struct scoutfs_sysfs_attrs ssa; + atomic_t compact_delay_ms; }; #define DECLARE_SRCH_INFO(sb, name) \ struct srch_info *name = SCOUTFS_SB(sb)->srch_info +#define DECLARE_SRCH_INFO_KOBJ(kobj, name) \ + DECLARE_SRCH_INFO(SCOUTFS_SYSFS_ATTRS_SB(kobj), name) #define SRE_FMT "%016llx.%llu.%llu" #define SRE_ARG(sre) \ @@ -2208,8 +2214,15 @@ static int delete_files(struct super_block *sb, struct scoutfs_alloc *alloc, return ret; } -/* wait 10s between compact attempts on error, immediate after success */ -#define SRCH_COMPACT_DELAY_MS (10 * MSEC_PER_SEC) +static void queue_compact_work(struct srch_info *srinf, bool immediate) +{ + unsigned long delay; + + if (!atomic_read(&srinf->shutdown)) { + delay = immediate ? 0 : msecs_to_jiffies(atomic_read(&srinf->compact_delay_ms)); + queue_delayed_work(srinf->workq, &srinf->compact_dwork, delay); + } +} /* * Get a compaction operation from the server, sort the entries from the @@ -2237,7 +2250,6 @@ static void scoutfs_srch_compact_worker(struct work_struct *work) struct super_block *sb = srinf->sb; struct scoutfs_block_writer wri; struct scoutfs_alloc alloc; - unsigned long delay; int ret; int err; @@ -2250,6 +2262,8 @@ static void scoutfs_srch_compact_worker(struct work_struct *work) scoutfs_block_writer_init(sb, &wri); ret = scoutfs_client_srch_get_compact(sb, sc); + if (ret >= 0) + trace_scoutfs_srch_compact_client_recv(sb, sc); if (ret < 0 || sc->nr == 0) goto out; @@ -2278,6 +2292,7 @@ commit: sc->meta_freed = alloc.freed; sc->flags |= ret < 0 ? SCOUTFS_SRCH_COMPACT_FLAG_ERROR : 0; + trace_scoutfs_srch_compact_client_send(sb, sc); err = scoutfs_client_srch_commit_compact(sb, sc); if (err < 0 && ret == 0) ret = err; @@ -2288,14 +2303,56 @@ out: scoutfs_inc_counter(sb, srch_compact_error); scoutfs_block_writer_forget_all(sb, &wri); - if (!atomic_read(&srinf->shutdown)) { - delay = (sc->nr > 0 && ret == 0) ? 0 : msecs_to_jiffies(SRCH_COMPACT_DELAY_MS); - queue_delayed_work(srinf->workq, &srinf->compact_dwork, delay); - } + queue_compact_work(srinf, sc->nr > 0 && ret == 0); kfree(sc); } +static ssize_t compact_delay_ms_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf) +{ + DECLARE_SRCH_INFO_KOBJ(kobj, srinf); + + return snprintf(buf, PAGE_SIZE, "%u", atomic_read(&srinf->compact_delay_ms)); +} + +#define MIN_COMPACT_DELAY_MS MSEC_PER_SEC +#define DEF_COMPACT_DELAY_MS (10 * MSEC_PER_SEC) +#define MAX_COMPACT_DELAY_MS (60 * MSEC_PER_SEC) + +static ssize_t compact_delay_ms_store(struct kobject *kobj, struct kobj_attribute *attr, + const char *buf, size_t count) +{ + struct super_block *sb = SCOUTFS_SYSFS_ATTRS_SB(kobj); + DECLARE_SRCH_INFO(sb, srinf); + char nullterm[30]; /* more than enough for octal -U64_MAX */ + u64 val; + int len; + int ret; + + len = min(count, sizeof(nullterm) - 1); + memcpy(nullterm, buf, len); + nullterm[len] = '\0'; + + ret = kstrtoll(nullterm, 0, &val); + if (ret < 0 || val < MIN_COMPACT_DELAY_MS || val > MAX_COMPACT_DELAY_MS) { + scoutfs_err(sb, "invalid compact_delay_ms value, must be between %lu and %lu", + MIN_COMPACT_DELAY_MS, MAX_COMPACT_DELAY_MS); + return -EINVAL; + } + + atomic_set(&srinf->compact_delay_ms, val); + cancel_delayed_work(&srinf->compact_dwork); + queue_compact_work(srinf, false); + + return count; +} +SCOUTFS_ATTR_RW(compact_delay_ms); + +static struct attribute *srch_attrs[] = { + SCOUTFS_ATTR_PTR(compact_delay_ms), + NULL, +}; + void scoutfs_srch_destroy(struct super_block *sb) { struct scoutfs_sb_info *sbi = SCOUTFS_SB(sb); @@ -2312,6 +2369,8 @@ void scoutfs_srch_destroy(struct super_block *sb) destroy_workqueue(srinf->workq); } + scoutfs_sysfs_destroy_attrs(sb, &srinf->ssa); + kfree(srinf); sbi->srch_info = NULL; } @@ -2329,8 +2388,15 @@ int scoutfs_srch_setup(struct super_block *sb) srinf->sb = sb; atomic_set(&srinf->shutdown, 0); INIT_DELAYED_WORK(&srinf->compact_dwork, scoutfs_srch_compact_worker); + scoutfs_sysfs_init_attrs(sb, &srinf->ssa); + atomic_set(&srinf->compact_delay_ms, DEF_COMPACT_DELAY_MS); + sbi->srch_info = srinf; + ret = scoutfs_sysfs_create_attrs(sb, &srinf->ssa, srch_attrs, "srch"); + if (ret < 0) + goto out; + srinf->workq = alloc_workqueue("scoutfs_srch_compact", WQ_NON_REENTRANT | WQ_UNBOUND | WQ_HIGHPRI, 0); @@ -2339,8 +2405,7 @@ int scoutfs_srch_setup(struct super_block *sb) goto out; } - queue_delayed_work(srinf->workq, &srinf->compact_dwork, - msecs_to_jiffies(SRCH_COMPACT_DELAY_MS)); + queue_compact_work(srinf, false); ret = 0; out: diff --git a/tests/golden/srch-safe-merge-pos b/tests/golden/srch-safe-merge-pos index 369d4e04..e801d558 100644 --- a/tests/golden/srch-safe-merge-pos +++ b/tests/golden/srch-safe-merge-pos @@ -1,4 +1,4 @@ -== snapshot errors +== initialize per-mount values == arm compaction triggers trigger srch_compact_logs_pad_safe armed: 1 trigger srch_merge_stop_safe armed: 1 @@ -10,72 +10,28 @@ trigger srch_compact_logs_pad_safe armed: 1 trigger srch_merge_stop_safe armed: 1 trigger srch_compact_logs_pad_safe armed: 1 trigger srch_merge_stop_safe armed: 1 -== force lots of small rotated log files for compaction +== compact more often +== create padded sorted inputs by forcing log rotation trigger srch_force_log_rotate armed: 1 trigger srch_force_log_rotate armed: 1 trigger srch_force_log_rotate armed: 1 trigger srch_force_log_rotate armed: 1 +trigger srch_compact_logs_pad_safe armed: 1 trigger srch_force_log_rotate armed: 1 trigger srch_force_log_rotate armed: 1 trigger srch_force_log_rotate armed: 1 trigger srch_force_log_rotate armed: 1 +trigger srch_compact_logs_pad_safe armed: 1 trigger srch_force_log_rotate armed: 1 trigger srch_force_log_rotate armed: 1 trigger srch_force_log_rotate armed: 1 trigger srch_force_log_rotate armed: 1 +trigger srch_compact_logs_pad_safe armed: 1 trigger srch_force_log_rotate armed: 1 trigger srch_force_log_rotate armed: 1 trigger srch_force_log_rotate armed: 1 trigger srch_force_log_rotate armed: 1 -trigger srch_force_log_rotate armed: 1 -trigger srch_force_log_rotate armed: 1 -trigger srch_force_log_rotate armed: 1 -trigger srch_force_log_rotate armed: 1 -trigger srch_force_log_rotate armed: 1 -trigger srch_force_log_rotate armed: 1 -trigger srch_force_log_rotate armed: 1 -trigger srch_force_log_rotate armed: 1 -trigger srch_force_log_rotate armed: 1 -trigger srch_force_log_rotate armed: 1 -trigger srch_force_log_rotate armed: 1 -trigger srch_force_log_rotate armed: 1 -trigger srch_force_log_rotate armed: 1 -trigger srch_force_log_rotate armed: 1 -trigger srch_force_log_rotate armed: 1 -trigger srch_force_log_rotate armed: 1 -trigger srch_force_log_rotate armed: 1 -trigger srch_force_log_rotate armed: 1 -trigger srch_force_log_rotate armed: 1 -trigger srch_force_log_rotate armed: 1 -trigger srch_force_log_rotate armed: 1 -trigger srch_force_log_rotate armed: 1 -trigger srch_force_log_rotate armed: 1 -trigger srch_force_log_rotate armed: 1 -trigger srch_force_log_rotate armed: 1 -trigger srch_force_log_rotate armed: 1 -trigger srch_force_log_rotate armed: 1 -trigger srch_force_log_rotate armed: 1 -trigger srch_force_log_rotate armed: 1 -trigger srch_force_log_rotate armed: 1 -trigger srch_force_log_rotate armed: 1 -trigger srch_force_log_rotate armed: 1 -trigger srch_force_log_rotate armed: 1 -trigger srch_force_log_rotate armed: 1 -trigger srch_force_log_rotate armed: 1 -trigger srch_force_log_rotate armed: 1 -trigger srch_force_log_rotate armed: 1 -trigger srch_force_log_rotate armed: 1 -trigger srch_force_log_rotate armed: 1 -trigger srch_force_log_rotate armed: 1 -trigger srch_force_log_rotate armed: 1 -trigger srch_force_log_rotate armed: 1 -trigger srch_force_log_rotate armed: 1 -trigger srch_force_log_rotate armed: 1 -trigger srch_force_log_rotate armed: 1 -trigger srch_force_log_rotate armed: 1 -trigger srch_force_log_rotate armed: 1 -trigger srch_force_log_rotate armed: 1 -== wait for compaction -== test and disarm compaction triggers -== verify triggers and errors +trigger srch_compact_logs_pad_safe armed: 1 +== compaction of padded should stop at safe +== verify no compaction errors == cleanup diff --git a/tests/src/bulk_create_paths.c b/tests/src/bulk_create_paths.c index e9886443..9e5a3db8 100644 --- a/tests/src/bulk_create_paths.c +++ b/tests/src/bulk_create_paths.c @@ -1,6 +1,7 @@ #include #include #include +#include #include #include #include @@ -35,10 +36,10 @@ struct opts { unsigned int dry_run:1, ls_output:1, quiet:1, - user_xattr:1, - same_srch_xattr:1, - group_srch_xattr:1, - unique_srch_xattr:1; + xattr_set:1, + xattr_file:1, + xattr_group:1; + char *xattr_name; }; struct stats { @@ -149,12 +150,31 @@ static void free_dir(struct dir *dir) free(dir); } +static size_t snprintf_off(void *buf, size_t sz, size_t off, char *fmt, ...) +{ + va_list ap; + int ret; + + if (off >= sz) + return sz; + + va_start(ap, fmt); + ret = vsnprintf(buf + off, sz - off, fmt, ap); + va_end(ap); + + if (ret <= 0) + return sz; + + return off + ret; +} + static void create_dir(struct dir *dir, struct opts *opts, struct stats *stats) { struct str_list *s; - char name[100]; + char name[256]; /* max len and null term */ char val = 'v'; + size_t off; int rc; int i; @@ -175,29 +195,21 @@ static void create_dir(struct dir *dir, struct opts *opts, rc = mknod(s->str, S_IFREG | 0644, 0); error_exit(rc, "mknod %s failed"ERRF, s->str, ERRA); - rc = 0; - if (rc == 0 && opts->user_xattr) { - strcpy(name, "user.scoutfs_bcp"); - rc = setxattr(s->str, name, &val, 1, 0); - } - if (rc == 0 && opts->same_srch_xattr) { - strcpy(name, "scoutfs.srch.scoutfs_bcp"); - rc = setxattr(s->str, name, &val, 1, 0); - } - if (rc == 0 && opts->group_srch_xattr) { - snprintf(name, sizeof(name), - "scoutfs.srch.scoutfs_bcp.group.%lu", - stats->files / 10000); - rc = setxattr(s->str, name, &val, 1, 0); - } - if (rc == 0 && opts->unique_srch_xattr) { - snprintf(name, sizeof(name), - "scoutfs.srch.scoutfs_bcp.unique.%lu", - stats->files); + if (opts->xattr_set) { + off = snprintf_off(name, sizeof(name), 0, "%s", opts->xattr_name); + if (opts->xattr_file) + off = snprintf_off(name, sizeof(name), off, + "-f-%lu", stats->files); + if (opts->xattr_group) + off = snprintf_off(name, sizeof(name), off, + "-g-%lu", stats->files / 10000); + + error_exit(off >= sizeof(name), "xattr name longer than 255 bytes"); + rc = setxattr(s->str, name, &val, 1, 0); + error_exit(rc, "setxattr %s %s failed"ERRF, s->str, name, ERRA); } - error_exit(rc, "setxattr %s %s failed"ERRF, s->str, name, ERRA); stats->files++; rate_banner(opts, stats); @@ -365,11 +377,10 @@ static void usage(void) " -d DIR | create all files in DIR top level directory\n" " -n | dry run, only parse, don't create any files\n" " -q | quiet, don't regularly print rates\n" + " -F | append \"-f-NR\" file nr to xattr name, requires -X\n" + " -G | append \"-g-NR\" file nr/10000 to xattr name, requires -X\n" " -L | parse ls output; only reg, skip meta, paths at ./\n" - " -X | set the same user. xattr name in all files\n" - " -S | set the same .srch. xattr name in all files\n" - " -G | set a .srch. xattr name shared by groups of files\n" - " -U | set a unique .srch. xattr name in all files\n"); + " -X NAM | set named xattr in all files\n"); } int main(int argc, char **argv) @@ -386,7 +397,7 @@ int main(int argc, char **argv) memset(&opts, 0, sizeof(opts)); - while ((c = getopt(argc, argv, "d:nqLXSGU")) != -1) { + while ((c = getopt(argc, argv, "d:nqFGLX:")) != -1) { switch(c) { case 'd': top_dir = strdup(optarg); @@ -397,20 +408,19 @@ int main(int argc, char **argv) case 'q': opts.quiet = 1; break; + case 'F': + opts.xattr_file = 1; + break; + case 'G': + opts.xattr_group = 1; + break; case 'L': opts.ls_output = 1; break; case 'X': - opts.user_xattr = 1; - break; - case 'S': - opts.same_srch_xattr = 1; - break; - case 'G': - opts.group_srch_xattr = 1; - break; - case 'U': - opts.unique_srch_xattr = 1; + opts.xattr_set = 1; + opts.xattr_name = strdup(optarg); + error_exit(!opts.xattr_name, "error allocating xattr name"); break; case '?': printf("Unknown option '%c'\n", optopt); @@ -419,6 +429,11 @@ int main(int argc, char **argv) } } + error_exit(opts.xattr_file && !opts.xattr_set, + "must specify xattr -X when appending file nr with -F"); + error_exit(opts.xattr_group && !opts.xattr_set, + "must specify xattr -X when appending file nr with -G"); + if (!opts.dry_run) { error_exit(!top_dir, "must specify top level directory with -d"); diff --git a/tests/tests/srch-basic-functionality.sh b/tests/tests/srch-basic-functionality.sh index 1b982489..83d69e94 100644 --- a/tests/tests/srch-basic-functionality.sh +++ b/tests/tests/srch-basic-functionality.sh @@ -9,6 +9,7 @@ LOG=340000 LIM=1000000 SEQF="%.20g" +SXA="scoutfs.srch.test-srch-basic-functionality" t_require_commands touch rm setfattr scoutfs find_xattrs @@ -27,20 +28,20 @@ diff_srch_find() echo "== create new xattrs" touch "$T_D0/"{create,update} -setfattr -n scoutfs.srch.test -v 1 "$T_D0/"{create,update} 2>&1 | t_filter_fs -diff_srch_find scoutfs.srch.test +setfattr -n $SXA -v 1 "$T_D0/"{create,update} 2>&1 | t_filter_fs +diff_srch_find $SXA echo "== update existing xattr" -setfattr -n scoutfs.srch.test -v 2 "$T_D0/update" 2>&1 | t_filter_fs -diff_srch_find scoutfs.srch.test +setfattr -n $SXA -v 2 "$T_D0/update" 2>&1 | t_filter_fs +diff_srch_find $SXA echo "== remove an xattr" -setfattr -x scoutfs.srch.test "$T_D0/create" 2>&1 | t_filter_fs -diff_srch_find scoutfs.srch.test +setfattr -x $SXA "$T_D0/create" 2>&1 | t_filter_fs +diff_srch_find $SXA echo "== remove xattr with files" rm -f "$T_D0/"{create,update} -diff_srch_find scoutfs.srch.test +diff_srch_find $SXA echo "== trigger small log merges by rotating single block with unmount" sv=$(t_server_nr) @@ -56,7 +57,7 @@ while [ "$i" -lt "8" ]; do eval path="\$T_D${nr}/single-block-$i" touch "$path" - setfattr -n scoutfs.srch.single-block-logs -v $i "$path" + setfattr -n $SXA -v $i "$path" t_umount $nr t_mount $nr @@ -65,51 +66,51 @@ while [ "$i" -lt "8" ]; do done # wait for srch compaction worker delay sleep 10 -rm -rf "$T_D0/single-block-*" +find "$T_D0" -type f -name 'single-block-*' -delete echo "== create entries in current log" DIR="$T_D0/dir" NR=$((LOG / 4)) mkdir -p "$DIR" -seq -f "f-$SEQF" 1 $NR | src/bulk_create_paths -S -d "$DIR" > /dev/null -diff_srch_find scoutfs.srch.scoutfs_bcp +seq -f "f-$SEQF" 1 $NR | src/bulk_create_paths -X $SXA -d "$DIR" > /dev/null +diff_srch_find $SXA echo "== delete small fraction" -seq -f "$DIR/f-$SEQF" 1 7 $NR | xargs setfattr -x scoutfs.srch.scoutfs_bcp -diff_srch_find scoutfs.srch.scoutfs_bcp +seq -f "$DIR/f-$SEQF" 1 7 $NR | xargs setfattr -x $SXA +diff_srch_find $SXA echo "== remove files" rm -rf "$DIR" -diff_srch_find scoutfs.srch.scoutfs_bcp +diff_srch_find $SXA echo "== create entries that exceed one log" NR=$((LOG * 3 / 2)) mkdir -p "$DIR" -seq -f "f-$SEQF" 1 $NR | src/bulk_create_paths -S -d "$DIR" > /dev/null -diff_srch_find scoutfs.srch.scoutfs_bcp +seq -f "f-$SEQF" 1 $NR | src/bulk_create_paths -X $SXA -d "$DIR" > /dev/null +diff_srch_find $SXA echo "== delete fractions in phases" for i in $(seq 1 3); do - seq -f "$DIR/f-$SEQF" $i 3 $NR | xargs setfattr -x scoutfs.srch.scoutfs_bcp - diff_srch_find scoutfs.srch.scoutfs_bcp + seq -f "$DIR/f-$SEQF" $i 3 $NR | xargs setfattr -x $SXA + diff_srch_find $SXA done echo "== remove files" rm -rf "$DIR" -diff_srch_find scoutfs.srch.scoutfs_bcp +diff_srch_find $SXA echo "== create entries for exceed search entry limit" NR=$((LIM * 3 / 2)) mkdir -p "$DIR" -seq -f "f-$SEQF" 1 $NR | src/bulk_create_paths -S -d "$DIR" > /dev/null -diff_srch_find scoutfs.srch.scoutfs_bcp +seq -f "f-$SEQF" 1 $NR | src/bulk_create_paths -X $SXA -d "$DIR" > /dev/null +diff_srch_find $SXA echo "== delete half" -seq -f "$DIR/f-$SEQF" 1 2 $NR | xargs setfattr -x scoutfs.srch.scoutfs_bcp -diff_srch_find scoutfs.srch.scoutfs_bcp +seq -f "$DIR/f-$SEQF" 1 2 $NR | xargs setfattr -x $SXA +diff_srch_find $SXA echo "== entirely remove third batch" rm -rf "$DIR" -diff_srch_find scoutfs.srch.scoutfs_bcp +diff_srch_find $SXA t_pass diff --git a/tests/tests/srch-safe-merge-pos.sh b/tests/tests/srch-safe-merge-pos.sh index b575d84e..bd388a18 100644 --- a/tests/tests/srch-safe-merge-pos.sh +++ b/tests/tests/srch-safe-merge-pos.sh @@ -4,10 +4,9 @@ # block. Resuming from that position would return an error and # compaction would stop making forward progress. # -# We use triggers to make sure that we create the circumstance where a -# sorted srch block ends at the _SAFE_BYTES offsset and that a merge -# request stops with a partial block at that specific offset. We then -# watch error counters to make sure compaction doesn't get stuck. +# We use triggers to pad the output of log compaction to end on the safe +# offset and then cause compaction of those padded inputs to stop at the +# safe offset. Continuation will either succeed or return errors. # # forcing rotation, so just a few @@ -15,11 +14,20 @@ NR=10 SEQF="%.20g" COMPACT_NR=4 -echo "== snapshot errors" +echo "== initialize per-mount values" declare -a err +declare -a compact_delay for nr in $(t_fs_nrs); do err[$nr]=$(t_counter srch_compact_error $nr) + compact_delay[$nr]=$(cat $(t_sysfs_path $nr)/srch/compact_delay_ms) done +restore_compact_delay() +{ + for nr in $(t_fs_nrs); do + echo ${compact_delay[$nr]} > $(t_sysfs_path $nr)/srch/compact_delay_ms + done +} +trap restore_compact_delay EXIT echo "== arm compaction triggers" for nr in $(t_fs_nrs); do @@ -27,37 +35,50 @@ for nr in $(t_fs_nrs); do t_trigger_arm srch_merge_stop_safe $nr done -echo "== force lots of small rotated log files for compaction" -sv=$(t_server_nr) -iter=1 -while [ $iter -le $((COMPACT_NR * COMPACT_NR * COMPACT_NR)) ]; do - t_trigger_arm srch_force_log_rotate $sv - - seq -f "f-$iter-$SEQF" 1 10 | src/bulk_create_paths -S -d "$T_D0" > /dev/null - sync - - test "$(t_trigger_get srch_force_log_rotate $sv)" == "0" || \ - t_fail "srch_force_log_rotate didn't trigger" - - ((iter++)) -done - -echo "== wait for compaction" -sleep 15 - -echo "== test and disarm compaction triggers" -pad=0 -merge_stop=0 +echo "== compact more often" for nr in $(t_fs_nrs); do - test "$(t_trigger_get srch_compact_logs_pad_safe $nr)" == "0" && pad=1 - t_trigger_set srch_compact_logs_pad_safe $nr 0 - test "$(t_trigger_get srch_merge_stop_safe $nr)" == "0" && merge_stop=1 - t_trigger_set srch_merge_stop_safe $nr 0 + echo 1000 > $(t_sysfs_path $nr)/srch/compact_delay_ms done -echo "== verify triggers and errors" -test $pad == 1 || t_fail "srch_compact_logs_pad_safe didn't trigger" -test $merge_stop == 1 || t_fail "srch_merge_stop_safe didn't trigger" +echo "== create padded sorted inputs by forcing log rotation" +sv=$(t_server_nr) +for i in $(seq 1 $COMPACT_NR); do + for j in $(seq 1 $COMPACT_NR); do + t_trigger_arm srch_force_log_rotate $sv + + seq -f "f-$i-$j-$SEQF" 1 10 | \ + bulk_create_paths -X "scoutfs.srch.t-srch-safe-merge-pos" -d "$T_D0" > \ + /dev/null + sync + + test "$(t_trigger_get srch_force_log_rotate $sv)" == "0" || \ + t_fail "srch_force_log_rotate didn't trigger" + done + + padded=0 + while test $padded == 0 && sleep .5; do + for nr in $(t_fs_nrs); do + if [ "$(t_trigger_get srch_compact_logs_pad_safe $nr)" == "0" ]; then + t_trigger_arm srch_compact_logs_pad_safe $nr + padded=1 + break + fi + test "$(t_counter srch_compact_error $nr)" == "${err[$nr]}" || \ + t_fail "srch_compact_error counter increased on mount $nr" + done + done +done + +echo "== compaction of padded should stop at safe" +sleep 2 +for nr in $(t_fs_nrs); do + if [ "$(t_trigger_get srch_merge_stop_safe $nr)" == "0" ]; then + break + fi +done + +echo "== verify no compaction errors" +sleep 2 for nr in $(t_fs_nrs); do test "$(t_counter srch_compact_error $nr)" == "${err[$nr]}" || \ t_fail "srch_compact_error counter increased on mount $nr"