From 27bc0ef095e76ca65f2c67629b902a970786ee0d Mon Sep 17 00:00:00 2001 From: Zach Brown Date: Wed, 7 Oct 2020 15:38:12 -0700 Subject: [PATCH] scoutfs: fix item cache page trim The tests for the various page range intersections were out of order. The edge overlap case could trigger before the bisection case and we'd fail to remove the initial items in the page. That would leave items before the start key which would later be used as a midpoint for a split, causing all kinds of chaos. Rework the cases so that the overlap cases are last. The unique bisect case will be caught before we can mistake it for an edge overlap case. And minimize the number of comparisons we calculate by storing the handful that all the cases need. Signed-off-by: Zach Brown --- kmod/src/item.c | 87 +++++++++++++++++++++++++++++++++---------------- 1 file changed, 59 insertions(+), 28 deletions(-) diff --git a/kmod/src/item.c b/kmod/src/item.c index 120c07c1..15c7a1aa 100644 --- a/kmod/src/item.c +++ b/kmod/src/item.c @@ -740,48 +740,79 @@ static int trim_page_intersection(struct super_block *sb, struct scoutfs_key *start, struct scoutfs_key *end) { - if (scoutfs_key_compare(&pg->start, end) > 0 || - scoutfs_key_compare(&pg->end, start) < 0) { - /* page and range don't intersect */ + int ps_e = scoutfs_key_compare(&pg->start, end); + int pe_s = scoutfs_key_compare(&pg->end, start); + int ps_s; + int pe_e; + + /* + * page and range don't intersect + * + * ps |----------| pe + * s |----------| e + * (or) + * ps |----------| pe + * s |----------| e + */ + if (ps_e > 0 || pe_s < 0) return PGI_DISJOINT; - } - if (scoutfs_key_compare(&pg->start, start) >= 0 && - scoutfs_key_compare(&pg->end, end) <= 0) { - /* page entirely inside range */ + ps_s = scoutfs_key_compare(&pg->start, start); + pe_e = scoutfs_key_compare(&pg->end, end); + + /* + * page entirely inside range + * + * ps |----------| pe + * s |----------| e + */ + if (ps_s >= 0 && pe_e <= 0) return PGI_INSIDE; + + /* + * page surrounds range, and is bisected by it + * + * ps |----------| pe + * s |------| e + */ + if (ps_s < 0 && pe_e > 0) { + if (!right) + return PGI_BISECT_NEEDED; + + right->start = *end; + scoutfs_key_inc(&right->start); + right->end = pg->end; + pg->end = *start; + scoutfs_key_dec(&pg->end); + erase_page_items(pg, start, end); + move_page_items(sb, cinf, pg, right, &right->start, NULL); + return PGI_BISECT; } - if (scoutfs_key_compare(&pg->start, end) <= 0 && - scoutfs_key_compare(&pg->end, end) > 0) { - /* start of page intersects with range */ + /* + * start of page overlaps with range + * + * ps |----------| pe + * s |----------| e + */ + if (pe_e > 0) { + /* start of page overlaps range */ pg->start = *end; scoutfs_key_inc(&pg->start); erase_page_items(pg, start, end); return PGI_START_OLAP; } - if (scoutfs_key_compare(&pg->end, start) >= 0 && - scoutfs_key_compare(&pg->start, start) < 0) { - /* end of page intersects with range */ - pg->end = *start; - scoutfs_key_dec(&pg->end); - erase_page_items(pg, start, end); - return PGI_END_OLAP; - } - - /* page surrounds range, and is bisected by it */ - if (!right) - return PGI_BISECT_NEEDED; - - right->start = *end; - scoutfs_key_inc(&right->start); - right->end = pg->end; + /* + * end of page overlaps with range + * + * ps |----------| pe + * s |----------| e + */ pg->end = *start; scoutfs_key_dec(&pg->end); erase_page_items(pg, start, end); - move_page_items(sb, cinf, pg, right, &right->start, NULL); - return PGI_BISECT; + return PGI_END_OLAP; } /*