scoutfs: incremental srch compaction

Previously the srch compaction work would output the entire compacted
file and delete the input files in one atomic commit.  The server would
send the input files and an allocator to the client, and the client
would send back an output file and an allocator that included the
deletion of the input files.  The server would merge in the allocator
and replace the input file items with the output file item.

Doing it this way required giving an enormous allocation pool to the
client in a radix, which would deal with recursive operations
(allocating from and freeing to the radix that is being modified).  We
no longer have the radix allocator, and we use single block avail/free
lists instead of recursively modifying the btrees with free extent
items.  The compaction RPC needs to work with a finite amount of
allocator resources that can be stored in an alloc list block.

The compaction work now does a fixed amount of work and a compaction
operation spans multiple work iterations.

A single compaction struct is now sent between the client and server in
the get_compact and commit_compact messages.  The client records any
partial progress in the struct.  The server writes that position into
PENDING items.  It first searchs for pending items to give to clients
before searching for files to start a new compaction operation.

The compact struct has flags to indicate whether the output file is
being written or the input files are being deleted.  The server manages
the flags and sets the input file deletion flag only once the result of
the compaction has been reflected in the btree items which record srch
files.

We added the progress fields to the compaction struct, making it even
bigger than it already was, so we take the time to allocate them rather
than declaring them on the stack.

It's worth mentioning that each operation now takes a reasonably bounded
amount of time will make it feasible to decide that it has failed and
needs to be fenced.

Signed-off-by: Zach Brown <zab@versity.com>
This commit is contained in:
Zach Brown
2020-10-26 15:19:03 -07:00
committed by Zach Brown
parent d589881855
commit 7a3749d591
8 changed files with 555 additions and 289 deletions
+12 -12
View File
@@ -1121,15 +1121,15 @@ int scoutfs_alloc_foreach(struct super_block *sb,
struct scoutfs_btree_ref stale_refs[2] = {{0,}};
struct scoutfs_btree_ref refs[2] = {{0,}};
struct scoutfs_super_block *super = NULL;
struct scoutfs_srch_compact_input *scin;
struct scoutfs_srch_compact *sc;
struct scoutfs_log_trees_val ltv;
SCOUTFS_BTREE_ITEM_REF(iref);
struct scoutfs_key key;
int ret;
super = kmalloc(sizeof(struct scoutfs_super_block), GFP_NOFS);
scin = kmalloc(sizeof(struct scoutfs_srch_compact_input), GFP_NOFS);
if (!super || !scin) {
sc = kmalloc(sizeof(struct scoutfs_srch_compact), GFP_NOFS);
if (!super || !sc) {
ret = -ENOMEM;
goto out;
}
@@ -1200,17 +1200,17 @@ retry:
/* srch compaction allocators */
memset(&key, 0, sizeof(key));
key.sk_zone = SCOUTFS_SRCH_ZONE;
key.sk_type = SCOUTFS_SRCH_BUSY_TYPE;
key.sk_type = SCOUTFS_SRCH_PENDING_TYPE;
for (;;) {
/* _BUSY_ is last type, _next won't see other types */
/* _PENDING_ and _BUSY_ are last, _next won't see other types */
ret = scoutfs_btree_next(sb, &super->srch_root, &key, &iref);
if (ret == -ENOENT)
break;
if (ret == 0) {
if (iref.val_len == sizeof(scin)) {
if (iref.val_len == sizeof(*sc)) {
key = *iref.key;
memcpy(scin, iref.val, iref.val_len);
memcpy(sc, iref.val, iref.val_len);
} else {
ret = -EIO;
}
@@ -1220,11 +1220,11 @@ retry:
goto out;
ret = cb(sb, arg, SCOUTFS_ALLOC_OWNER_SRCH,
le64_to_cpu(scin->id), true, true,
le64_to_cpu(scin->meta_avail.total_nr)) ?:
le64_to_cpu(sc->id), true, true,
le64_to_cpu(sc->meta_avail.total_nr)) ?:
cb(sb, arg, SCOUTFS_ALLOC_OWNER_SRCH,
le64_to_cpu(scin->id), true, false,
le64_to_cpu(scin->meta_freed.total_nr));
le64_to_cpu(sc->id), true, false,
le64_to_cpu(sc->meta_freed.total_nr));
if (ret < 0)
goto out;
@@ -1244,6 +1244,6 @@ out:
}
kfree(super);
kfree(scin);
kfree(sc);
return ret;
}