storage: block_set: Remove reentrant write support

Keep track of pending allocations in allocator instead to reduce memory
usage.

Change-Id: Ie6dd10f9887376fdc7c9e3aff79af2083634958e
diff --git a/block_set.c b/block_set.c
index eee15d5..c0892f7 100644
--- a/block_set.c
+++ b/block_set.c
@@ -109,6 +109,26 @@
 }
 
 /**
+ * block_set_print_ranges - Print block-set range
+ * @tr:         Transaction object.
+ * @range:      Range to print.
+ */
+static void block_set_print_range(struct block_range range, int *split_line)
+{
+    if (*split_line >= 8) {
+        *split_line = 0;
+        printf("\n");
+    }
+    (*split_line)++;
+    if (range.start == range.end - 1) {
+        printf("    %3lld      ",range.start);
+    } else {
+        printf("    %3lld - %3lld",range.start, range.end - 1);
+    }
+    (*split_line)++;
+}
+
+/**
  * block_set_print_ranges - Print block-set ranges
  * @tr:         Transaction object.
  * @set:        Block-set object.
@@ -119,70 +139,22 @@
     struct block_tree_path path;
     struct block_range range;
     int split_line = 0;
-    uint i;
 
     printf("set:\n");
 
     block_tree_walk(tr, &set->block_tree, 0, true, &path);
     block_range_init_from_path(&range, &path);
     while (!block_range_empty(range)) {
-        if (split_line >= 8) {
-            split_line = 0;
-            printf("\n");
-        }
-        split_line++;
-        if (range.start == range.end - 1) {
-            printf("    %3lld      ",range.start);
-        } else {
-            printf("    %3lld - %3lld",range.start, range.end - 1);
-        }
-        split_line++;
+        block_set_print_range(range, &split_line);
         block_tree_path_next(&path);
         block_range_init_from_path(&range, &path);
     }
     printf("\n");
 
-    if (!block_range_empty(set->inserting_range[0])) {
-        printf("inserting_range: ");
+    if (!block_range_empty(set->initial_range)) {
+        printf("initial_range: ");
         split_line = 0;
-        for (i = 0; i < countof(set->inserting_range); i++) {
-            range = set->inserting_range[i];
-            if (!block_range_empty(range)) {
-                if (split_line >= 8) {
-                    split_line = 0;
-                    printf("\n");
-                }
-                split_line++;
-                if (range.start == range.end - 1) {
-                    printf("    %3lld      ",range.start);
-                } else {
-                    printf("    %3lld - %3lld",range.start, range.end - 1);
-                }
-                split_line++;
-            }
-        }
-        printf("\n");
-    }
-
-    if (!block_range_empty(set->removing_range[0])) {
-        printf("removing_range: ");
-        split_line = 0;
-        for (i = 0; i < countof(set->removing_range); i++) {
-            range = set->removing_range[i];
-            if (!block_range_empty(range)) {
-                if (split_line >= 8) {
-                    split_line = 0;
-                    printf("\n");
-                }
-                split_line++;
-                if (range.start == range.end - 1) {
-                    printf("    %3lld      ",range.start);
-                } else {
-                    printf("    %3lld - %3lld",range.start, range.end - 1);
-                }
-                split_line++;
-            }
-        }
+        block_set_print_range(set->initial_range, &split_line);
         printf("\n");
     }
 }
@@ -265,77 +237,6 @@
 }
 
 /**
- * block_set_lookup_inserted_range
- * @set:        Block-set object.
- * @min_block:  Block number.
- * @range:      Range to store result in.
- *
- * Find a inserting range in containing @min_block or, if this range does not
- * exist, the first range to start above @min_block.
- */
-static void block_set_lookup_inserted_range(struct block_set *set,
-                                            data_block_t min_block,
-                                            struct block_range *range)
-{
-    uint i;
-    int best_i = -1;
-
-    for (i = 0; i < countof(set->inserting_range); i++) {
-        if (block_range_empty(set->inserting_range[i])) {
-            break;
-        }
-        if (block_in_range(set->inserting_range[i], min_block)) {
-            best_i = i;
-            break;
-        }
-        if (set->inserting_range[i].start > min_block
-            && (best_i < 0 ||
-                set->inserting_range[i].start < set->inserting_range[best_i].start)) {
-            best_i = i;
-        }
-    }
-    if (best_i >= 0) {
-        *range = set->inserting_range[best_i];
-    } else {
-        block_range_clear(range);
-    }
-    if (!block_range_empty(*range)) {
-        pr_read("%lld return [%lld-%lld]\n",
-                min_block, range->start, range->end - 1);
-    }
-}
-
-/**
- * block_set_remove_inserted_range - remove range from inserting_range
- * @set:        Block-set object.
- * @range:      Range to remove.
- *
- * Check if @set->inserting_range contains an excact match for @range and
- * if so remove it.
- *
- * Return: %true if @range was in @set->inserting_range, %false otherwise.
- */
-static bool block_set_remove_inserted_range(struct block_set *set,
-                                            struct block_range range)
-{
-    uint i;
-
-    for (i = 0; i < countof(set->inserting_range); i++) {
-        if (block_range_empty(set->inserting_range[i])) {
-            return false;
-        }
-        if (block_range_eq(set->inserting_range[i], range)) {
-            break;
-        }
-    }
-    if (i == countof(set->inserting_range)) {
-        return false;
-    }
-    array_shift_down(set->inserting_range, i, i + 1);
-    return true;
-}
-
-/**
  * block_set_find_next_block - find a block in or not in set
  * @tr:         Transaction object.
  * @set:        Block-set object.
@@ -353,43 +254,27 @@
 {
     struct block_tree_path path;
     struct block_range range;
-    struct block_range range_inserting; /* inserted but not yet in on disk tree */
-    data_block_t next_start;
 
-retry:
     block_tree_walk(tr, &set->block_tree, min_block, true, &path);
     block_range_init_from_path(&range, &path);
     if (!block_range_empty(range) && range.end <= min_block) {
         block_tree_path_next(&path);
         block_range_init_from_path(&range, &path);
     }
-    next_start = range.start;
-    block_set_lookup_inserted_range(set, min_block, &range_inserting);
+    if (block_range_empty(range)) {
+        range = set->initial_range;
+        if (range.end <= min_block) {
+            block_range_clear(&range);
+        }
+    }
 
-    pr_read("set at %lld, %lld in_set %d, disk [%lld-%lld], mem [%lld-%lld]\n",
+    pr_read("set at %lld, %lld in_set %d, [%lld-%lld]\n",
             block_mac_to_block(tr, &set->block_tree.root),
-            min_block, in_set, range.start, range.end - 1,
-            range_inserting.start, range_inserting.end -1);
+            min_block, in_set, range.start, range.end - 1);
 
     /* The block tree walk should not find an empty range that is not 0, 0 */
     assert(!block_range_empty(range) || !range.start);
 
-    if (!block_range_empty(range_inserting)
-        && (range_inserting.start < range.start || block_range_empty(range))) {
-        if (range_inserting.end < range.start || block_range_empty(range)) {
-            next_start = range.start;
-            range = range_inserting;
-        } else {
-            assert(range_inserting.end == range.start);
-            range.start = range_inserting.start;
-        }
-        block_set_lookup_inserted_range(set, range.end, &range_inserting);
-        if (!block_range_empty(range_inserting)
-            && range_inserting.start < next_start) {
-            next_start = range_inserting.start;
-        }
-    }
-
     if (block_in_range(range, min_block) == in_set) {
         pr_read("%lld in_set %d, return min_block, %lld\n",
                 min_block, in_set, min_block);
@@ -397,26 +282,13 @@
     } else {
         if (!in_set) {
             assert(!block_range_empty(range));
-            if (next_start == range.end) {
-                min_block = next_start;
-                pr_warn("%lld in_set %d, range.end == next_start, %lld, retry\n",
-                        min_block, in_set, range.end);
-                goto retry;
-            }
-            assert(next_start != range.end);
             pr_read("%lld in_set %d, return range.end, %lld\n",
                     min_block, in_set, range.end);
             return range.end;
         } else {
-            if (!block_range_empty(range)) {
-                pr_read("%lld in_set %d, return range.start, %lld\n",
-                        min_block, in_set, range.start);
-                return range.start;
-            } else {
-                pr_read("%lld in_set %d, return next_start, %lld\n",
-                        min_block, in_set, next_start);
-                return next_start;
-            }
+            pr_read("%lld in_set %d, return range.start, %lld\n",
+                    min_block, in_set, range.start);
+            return range.start;
         }
     }
 }
@@ -536,70 +408,7 @@
 }
 
 /**
- * block_set_add_inserting_range - Add a range to block set in memory
- * @set:        Block-set object.
- * @range:      Block range to add.
- *
- * Either adds @range to inserting_range or removes @range from removing_range.
- * Removing a subset of a range in removing_range is not supported.
- */
-static void block_set_add_inserting_range(struct block_set *set,
-                                          struct block_range range)
-{
-    uint i;
-    struct block_range removing_range;
-
-    assert(!block_range_empty(range));
-
-    for (i = 0; i < countof(set->removing_range); i++) {
-        removing_range = set->removing_range[i];
-        if (block_range_empty(removing_range)) {
-            break;
-        }
-        if (block_range_eq(range, removing_range)) {
-            pr_write("range [%lld-%lld], remove remove_range instead\n",
-                     range.start, range.end - 1);
-            array_shift_down(set->removing_range, i, i + 1);
-            return;
-        }
-        assert(!block_range_overlap(removing_range, range));
-    }
-
-    assert(block_range_empty(set->inserting_range[countof(set->inserting_range) - 1]));
-    array_insert(set->inserting_range, 0, range); /* TODO: shuffle less data around */
-}
-
-/**
- * block_set_add_inserting_range - Remove a range from block set in memory
- * @set:        Block-set object.
- * @range:      Block range to remove.
- *
- * Either adds @range to removing_range or removes @range from inserting_range.
- * Removing a subset of a range in inserting_range is not supported.
- */
-static void block_set_add_removing_range(struct block_set *set,
-                                         struct block_range range)
-{
-    bool removed;
-    struct block_range inserting_range;
-
-    assert(!block_range_empty(range));
-
-    block_set_lookup_inserted_range(set, range.start, &inserting_range);
-    if (block_range_eq(range, inserting_range)) {
-        pr_write("range [%lld-%lld], remove inserting_range instead\n",
-                 range.start, range.end - 1);
-        removed = block_set_remove_inserted_range(set, range);
-        assert(removed);
-        return;
-    }
-    assert(!block_range_overlap(inserting_range, range));
-    assert(block_range_empty(set->removing_range[countof(set->removing_range) - 1]));
-    array_insert(set->removing_range, 0, range); /* TODO: shuffle less data around */
-}
-
-/**
- * block_set_tree_insert_range - Add a range to block set tree
+ * block_set_add_range - Add a range to block set
  * @tr:         Transaction object.
  * @set:        Block-set object.
  * @range:      Block range to add.
@@ -608,9 +417,9 @@
  * tree, or by adding a new range to the tree. If an existing tree entry is
  * extended check if the next entry can be merged.
  */
-static void block_set_tree_insert_range(struct transaction *tr,
-                                        struct block_set *set,
-                                        struct block_range range)
+void block_set_add_range(struct transaction *tr,
+                         struct block_set *set,
+                         struct block_range range)
 {
     struct block_range tree_range;
     struct block_range new_tree_range;
@@ -619,8 +428,23 @@
     bool extend_left = false;
     bool merge;
 
-    assert(set->updating);
     assert(!block_range_empty(range));
+    assert(block_range_empty(set->initial_range));
+
+    if (tr->failed) {
+        pr_warn("transaction failed, ignore\n");
+        return;
+    }
+
+    pr_write("set %lld, add %lld-%lld, updating %d\n",
+             block_mac_to_block(tr, &set->block_tree.root),
+             range.start, range.end - 1, set->updating);
+
+    assert (!set->updating);
+    set->updating = true;
+
+    full_assert(block_set_check(tr, set));
+    assert(block_set_range_not_in_set(tr, set, range));
 
     block_tree_walk(tr, &set->block_tree, range.start - 1, true, &path);
     block_range_init_from_path(&tree_range, &path);
@@ -672,10 +496,23 @@
                               block_tree_path_get_data(&path));
         }
     }
+
+    if (tr->failed) {
+        pr_warn("transaction failed, abort\n");
+        return;
+    }
+
+    assert(set->updating);
+    set->updating = false;
+
+    full_assert(block_set_check(tr, set));
+    pr_write("set %lld, add %lld-%lld done\n",
+             block_mac_to_block(tr, &set->block_tree.root),
+             range.start, range.end - 1);
 }
 
 /**
- * block_set_tree_remove_range - Remove a range from block set tree
+ * block_set_remove_range - Remove a range from block set
  * @tr:         Transaction object.
  * @set:        Block-set object.
  * @range:      Block range to remove.
@@ -683,17 +520,32 @@
  * Remove @range from block set b+tree either by shrinking an existing range
  * in the tree, or by splitting an existing range in the tree.
  */
-static void block_set_tree_remove_range(struct transaction *tr,
-                                        struct block_set *set,
-                                        struct block_range range)
+void block_set_remove_range(struct transaction *tr,
+                            struct block_set *set,
+                            struct block_range range)
 {
     struct block_tree_path path;
     struct block_range tree_range;
     struct block_range new_tree_range;
     bool shrunk;
 
-    assert(set->updating);
     assert(!block_range_empty(range));
+    assert(block_range_empty(set->initial_range));
+
+    if (tr->failed) {
+        pr_warn("transaction failed, ignore\n");
+        return;
+    }
+
+    pr_write("set %lld, remove %lld-%lld, updating %d\n",
+             block_mac_to_block(tr, &set->block_tree.root),
+             range.start, range.end - 1, set->updating);
+
+    assert(block_set_range_in_set(tr, set, range) || tr->failed);
+
+    assert (!set->updating);
+    set->updating = true;
+
     full_assert(block_set_check(tr, set));
 
     block_tree_walk(tr, &set->block_tree, range.start, true, &path);
@@ -724,196 +576,20 @@
                           tree_range.start, tree_range.end,
                           new_tree_range.start, new_tree_range.end); /* TODO: use path? */
     }
-}
-
-/**
- * block_set_add_updating_ranges - Write in-memory block set updates to tree
- * @tr:                     Transaction object.
- * @set:                    Block-set object.
- * @skip_last_inserting:    If %true skip the last entry in inserting_range.
- */
-static void block_set_add_updating_ranges(struct transaction *tr,
-                                          struct block_set *set,
-                                          bool skip_last_inserting)
-{
-    bool removed;
-    struct block_range range;
-    int loop_limit = BLOCK_SET_MAX_DEPTH * BLOCK_SET_MAX_DEPTH * BLOCK_SET_MAX_DEPTH + tr->fs->dev->block_count;
-    const int print_loop_limit = loop_limit - BLOCK_SET_MAX_DEPTH * BLOCK_SET_MAX_DEPTH * BLOCK_SET_MAX_DEPTH;
-
-    while (true) {
-        assert(loop_limit-- > 0);
-        if (loop_limit == print_loop_limit) {
-            printf("%s: near loop limit: updating set:\n", __func__);
-            block_set_print(tr, set);
-            printf("%s: free set:\n", __func__);
-            block_set_print(tr, &tr->fs->free);
-        }
-        range = set->removing_range[0];
-        if (!block_range_empty(range)) {
-            array_shift_down(set->removing_range, 0, 1);
-            if (loop_limit <= print_loop_limit) {
-                pr_write("remove updating range [%lld-%lld]\n",
-                         range.start, range.end - 1);
-            }
-            block_set_tree_remove_range(tr, set, range);
-        } else {
-            range = set->inserting_range[0];
-            if (block_range_empty(range)) {
-                return;
-            }
-
-            if (!skip_last_inserting || !block_range_empty(set->inserting_range[1])) {
-                if (loop_limit <= print_loop_limit) {
-                    pr_write("add updating range [%lld-%lld]\n",
-                             range.start, range.end - 1);
-                }
-                block_set_tree_insert_range(tr, set, range);
-            }
-
-            removed = block_set_remove_inserted_range(set, range);
-            if (!removed) {
-                if (loop_limit <= print_loop_limit) {
-                    pr_write("added updating range [%lld-%lld] gone, remove\n",
-                             range.start, range.end - 1);
-                }
-                block_set_tree_remove_range(tr, set, range);
-            }
-        }
-        if (tr->failed) {
-            pr_warn("transaction failed, abort\n");
-            return;
-        }
-    }
-}
-
-/**
- * block_set_add_range - Add a range to block set
- * @tr:         Transaction object.
- * @set:        Block-set object.
- * @range:      Block range to add.
- *
- * Add @range to @set. If @set is already updating, add @range to in-memory
- * updates and return, if not add @range to in-memory updates then update tree.
- */
-void block_set_add_range(struct transaction *tr,
-                         struct block_set *set,
-                         struct block_range range)
-{
-    assert(!block_range_empty(range));
 
     if (tr->failed) {
-        pr_warn("transaction failed, ignore\n");
+        pr_warn("transaction failed, abort\n");
         return;
     }
 
-    full_assert(block_tree_check(tr, &set->block_tree));
+    assert(set->updating);
+    set->updating = false;
 
-    pr_write("set %lld, add %lld-%lld, updating %d\n",
+    full_assert(block_set_check(tr, set));
+
+    pr_write("set %lld, remove %lld-%lld done\n",
              block_mac_to_block(tr, &set->block_tree.root),
-             range.start, range.end - 1, set->updating);
-
-    if (set->updating) {
-        block_set_add_inserting_range(set, range);
-        pr_write("set %lld, add %lld-%lld tmp insert done\n",
-                 block_mac_to_block(tr, &set->block_tree.root),
-                 range.start, range.end - 1);
-    } else {
-        set->updating = true;
-
-        full_assert(block_set_check(tr, set));
-        assert(block_set_range_not_in_set(tr, set, range));
-
-        block_set_add_inserting_range(set, range); /* TODO: move up to common path? */
-        block_set_tree_insert_range(tr, set, range); /* TODO: remove and use block_set_add_updating_ranges? */
-        pr_write("set %lld, add %lld-%lld insert done\n",
-                 block_mac_to_block(tr, &set->block_tree.root),
-                 range.start, range.end - 1);
-
-        if (tr->failed) {
-            pr_warn("transaction failed, abort\n");
-            return;
-        }
-
-        full_assert(block_set_check(tr, set));
-        block_set_add_updating_ranges(tr, set, true);
-
-        if (tr->failed) {
-            pr_warn("transaction failed, abort\n");
-            return;
-        }
-
-        assert(set->updating);
-        set->updating = false;
-
-        full_assert(block_set_check(tr, set));
-        pr_write("set %lld, add %lld-%lld done\n",
-                 block_mac_to_block(tr, &set->block_tree.root),
-                 range.start, range.end - 1);
-    }
-}
-
-/**
- * block_set_remove_range - Remove a range from block set
- * @tr:         Transaction object.
- * @set:        Block-set object.
- * @range:      Block range to add.
- *
- * Remove @range from @set. If @set is already updating, add @range to in-memory
- * updates and return, if not remove @range from tree then apply other updates
- * to tree if needed.
- */
-void block_set_remove_range(struct transaction *tr,
-                            struct block_set *set,
-                            struct block_range range)
-{
-    assert(!block_range_empty(range));
-
-    if (tr->failed) {
-        pr_warn("transaction failed, ignore\n");
-        return;
-    }
-
-    full_assert(block_tree_check(tr, &set->block_tree));
-
-    pr_write("set %lld, remove %lld-%lld, updating %d\n",
-             block_mac_to_block(tr, &set->block_tree.root),
-             range.start, range.end - 1, set->updating);
-
-    assert(block_set_range_in_set(tr, set, range) || tr->failed);
-
-    if (set->updating) {
-        block_set_add_removing_range(set, range);
-        pr_write("set %lld, add %lld-%lld tmp remove done\n",
-                 block_mac_to_block(tr, &set->block_tree.root),
-                 range.start, range.end - 1);
-    } else {
-        set->updating = true;
-        full_assert(block_set_check(tr, set));
-        block_set_tree_remove_range(tr, set, range);
-
-        if (tr->failed) {
-            pr_warn("transaction failed, abort\n");
-            return;
-        }
-
-        full_assert(block_set_check(tr, set));
-        block_set_add_updating_ranges(tr, set, false);
-
-        if (tr->failed) {
-            pr_warn("transaction failed, abort\n");
-            return;
-        }
-
-        assert(set->updating);
-        set->updating = false;
-
-        full_assert(block_set_check(tr, set));
-
-        pr_write("set %lld, remove %lld-%lld done\n",
-                 block_mac_to_block(tr, &set->block_tree.root),
-                 range.start, range.end - 1);
-    }
+             range.start, range.end - 1);
 }
 
 /**
@@ -978,8 +654,8 @@
 void block_set_add_initial_range(struct block_set *set,
                                  struct block_range range)
 {
-    assert(block_range_empty(set->inserting_range[0]));
-    block_set_add_inserting_range(set, range);
+    assert(block_range_empty(set->initial_range));
+    set->initial_range = range;
 }
 
 /**
@@ -1001,14 +677,9 @@
     dest->block_tree.root = src->block_tree.root;
     if (!block_mac_valid(tr, &dest->block_tree.root)) {
         /* special case for newly created empty fs */
-        assert(!block_range_empty(src->inserting_range[0]));
-        assert(block_range_empty(src->inserting_range[1]));
-        dest->inserting_range[0] = src->inserting_range[0];
-        dest->updating = true;
-        block_set_add_updating_ranges(tr, dest, false);
-        assert(dest->updating);
-        dest->updating = false;
+        assert(!block_range_empty(src->initial_range));
+        block_set_add_range(tr, dest, src->initial_range);
     } else {
-        assert(block_range_empty(src->inserting_range[0]));
+        assert(block_range_empty(src->initial_range));
     }
 }
diff --git a/block_set.h b/block_set.h
index 7a7500a..2b30979 100644
--- a/block_set.h
+++ b/block_set.h
@@ -35,9 +35,7 @@
  * struct block_set - In-memory state of B+ tree backed block set
  * @node:               List node used to link transaction allocated sets in fs.
  * @block_tree:         Block tree state.
- * @inserting_range:    Block ranges added to set but not yet in @block_tree.
- * @removing_range:     Block ranges removed from set but not yet removed from
- *                      @block_tree.
+ * @inserting_range:    Block range added to set but not yet in @block_tree.
  * @updating:           %true while updating the set, %false otherwise. If a
  *                      set insert or remove operation is re-entered while
  *                      @updating is %true, the update is only applied to
@@ -54,16 +52,14 @@
 struct block_set {
     struct list_node node;
     struct block_tree block_tree;
-    struct block_range inserting_range[BLOCK_SET_MAX_DEPTH * BLOCK_SET_MAX_DEPTH]; // TODO: calculate smaller max
-    struct block_range removing_range[BLOCK_SET_MAX_DEPTH * BLOCK_SET_MAX_DEPTH];
+    struct block_range initial_range;
     bool updating;
 };
 
 #define BLOCK_SET_INITIAL_VALUE(block_set) { \
     .node = LIST_INITIAL_CLEARED_VALUE, \
     .block_tree = BLOCK_TREE_INITIAL_VALUE(block_set.block_tree), \
-    .inserting_range = {{0}}, \
-    .removing_range = {{0}}, \
+    .initial_range = {0}, \
     .updating = 0, \
 }
 
diff --git a/transaction.c b/transaction.c
index aa7901c..fb11d2d 100644
--- a/transaction.c
+++ b/transaction.c
@@ -295,7 +295,7 @@
         goto err_transaction_failed;
     }
 
-    assert(block_range_empty(new_free_set.inserting_range[0]));
+    assert(block_range_empty(new_free_set.initial_range));
     check_free_tree(tr, &new_free_set);
 
     super_block_updated = update_super_block(tr, &new_free_set.block_tree.root,
@@ -314,7 +314,7 @@
     assert(!tr->failed);
 
     tr->fs->free.block_tree.root = new_free_set.block_tree.root;
-    block_range_clear(&tr->fs->free.inserting_range[0]); /* clear for initial file-system state */
+    block_range_clear(&tr->fs->free.initial_range); /* clear for initial file-system state */
     tr->fs->files.root = new_files;
     tr->fs->super_block_version = tr->fs->written_super_block_version;