From 7c5823ad12a24f77263bd738365fd83637f25e59 Mon Sep 17 00:00:00 2001 From: Zach Brown Date: Mon, 30 Nov 2020 11:04:19 -0800 Subject: [PATCH] scoutfs: drop duplicate compacted srch entries The k-way merge used by srch file compaction only dropped the second entry in a pair of duplicate entries. Duplicate entries are both supposed to be removed so that entries for removed xattrs don't take up space in the files. This both drops the second entry and removes the first encoded entry. As we encode entries we rememeber their starting offset and the previous entry that they were encoded from. When we hit a duplicate entry we undo the encoding of the previous entry. This only works wihin srch file blocks. We can still have duplicate entries that span blocks but that's unlikely and relatively harmless. Signed-off-by: Zach Brown --- kmod/src/srch.c | 32 +++++++++++++++++++++++++++++++- 1 file changed, 31 insertions(+), 1 deletion(-) diff --git a/kmod/src/srch.c b/kmod/src/srch.c index 66346ea6..aac56dc6 100644 --- a/kmod/src/srch.c +++ b/kmod/src/srch.c @@ -1528,15 +1528,18 @@ static int kway_merge(struct super_block *sb, { DECLARE_SRCH_INFO(sb, srinf); struct scoutfs_srch_block *srb = NULL; + struct scoutfs_srch_entry last_tail; struct scoutfs_block *bl = NULL; struct tourn_node *tnodes; struct tourn_node *leaves; struct tourn_node *root; struct tourn_node *tn; + int last_bytes = 0; int nr_parents; int nr_nodes; int empty = 0; int ret = 0; + int diff; u64 blk; int ind; int i; @@ -1594,7 +1597,9 @@ static int kway_merge(struct super_block *sb, scoutfs_inc_counter(sb, srch_compact_dirty_block); } - if (sre_cmp(&root->sre, &sfl->last) != 0) { + if (sre_cmp(&root->sre, &srb->last) != 0) { + last_bytes = le32_to_cpu(srb->entry_bytes); + last_tail = srb->last; ret = encode_entry(srb->entries + le32_to_cpu(srb->entry_bytes), &root->sre, &srb->tail); @@ -1627,6 +1632,31 @@ static int kway_merge(struct super_block *sb, scoutfs_inc_counter(sb, srch_compact_entry); } else { + /* + * Duplicate entries indicate deletion so we + * undo the previously encoded entry and ignore + * this entry. This only happens within each + * block. Deletions can span block boundaries + * and will be filtered out by search and + * hopefully removed in future compactions. + */ + diff = le32_to_cpu(srb->entry_bytes) - last_bytes; + if (diff) { + memset(srb->entries + last_bytes, 0, diff); + if (srb->entry_bytes == 0) { + /* last_tail will be 0 */ + if (blk == 0) + sfl->first = last_tail; + srb->first = last_tail; + } + le32_add_cpu(&srb->entry_nr, -1); + srb->entry_bytes = cpu_to_le32(last_bytes); + srb->last = last_tail; + srb->tail = last_tail; + sfl->last = last_tail; + le64_add_cpu(&sfl->entries, -1); + } + scoutfs_inc_counter(sb, srch_compact_removed_entry); }