struct maple_subtree_state {
struct ma_state *orig_l; /* Original left side of subtree */
- struct ma_state *orig_r; /* Original rigth side of subtree */
+ struct ma_state *orig_r; /* Original right side of subtree */
struct ma_state *l; /* New left side of subtree */
struct ma_state *m; /* New middle of subtree (rare) */
struct ma_state *r; /* New right side of subtree */
for (offset = l_off + 1; offset < r_off; offset++)
mat_add(mast->destroy, mas_slot_locked(mast->orig_l,
slots, offset));
+
return;
}
/* mast->orig_r is different and consumed. */
child = mas_slot_locked(mast->orig_l, slots, offset++);
if (!child)
break;
+
mat_add(mast->destroy, child);
}
* @old_r: The encoded maple node to the right (next node).
*/
static inline void mast_rebalance_next(struct maple_subtree_state *mast,
- struct maple_enode *old_r)
+ struct maple_enode *old_r, bool free)
{
unsigned char b_end = mast->bn->b_end;
mas_mab_cp(mast->orig_r, 0, mt_slot_count(mast->orig_r->node),
mast->bn, b_end);
- mat_add(mast->free, old_r);
+ if (free)
+ mat_add(mast->free, old_r);
+
mast->orig_r->last = mast->orig_r->max;
if (old_r == mast->orig_l->node)
mast->orig_l->node = mast->orig_r->node;
* Check the right side, then the left. Data is copied into the @mast->bn.
* @mast: The maple_subtree_state.
*/
-static inline bool mast_sibling_rebalance_right(struct maple_subtree_state *mast)
+static inline
+bool mast_sibling_rebalance_right(struct maple_subtree_state *mast, bool free)
{
struct maple_enode *old_r;
struct maple_enode *old_l;
old_r = mast->orig_r->node;
if (mas_next_sibling(mast->orig_r)) {
- mast_rebalance_next(mast, old_r);
+ mast_rebalance_next(mast, old_r, free);
return true;
}
* Check the right side, then the left. Data is copied into the @mast->bn.
* @mast: The maple_subtree_state.
*/
-static inline bool mast_cousin_rebalance_right(struct maple_subtree_state *mast)
+static inline
+bool mast_cousin_rebalance_right(struct maple_subtree_state *mast, bool free)
{
struct maple_enode *old_l = mast->orig_l->node;
struct maple_enode *old_r = mast->orig_r->node;
mas_dup_state(&tmp, mast->orig_r);
mas_next_node(mast->orig_r, ULONG_MAX);
if (!mas_is_none(mast->orig_r)) {
- mast_rebalance_next(mast, old_r);
+ mast_rebalance_next(mast, old_r, free);
return true;
}
* @b_node: the maple_big_node with the type encoding.
*
* Use the node type from the maple_big_node to allocate a new node from the
- * maple_state. This function exists mainly for code readability.
+ * ma_state. This function exists mainly for code readability.
*
* Return: A new maple encoded node
*/
* @mid_split: The location to split between middle and right.
*/
static inline void mast_cp_to_nodes(struct maple_subtree_state *mast,
- struct maple_enode *left,
- struct maple_enode *middle,
- struct maple_enode *right,
- unsigned char split,
- unsigned char mid_split)
+ struct maple_enode *left, struct maple_enode *middle,
+ struct maple_enode *right, unsigned char split, unsigned char mid_split,
+ struct ma_state *save)
{
mast->l->node = mte_node_or_none(left);
mast->m->node = mte_node_or_none(middle);
mab_mas_cp(mast->bn, 1 + split, mid_split, mast->m);
mast->m->min = mast->bn->pivot[split] + 1;
mast->m->max = mast->bn->pivot[mid_split];
+ if (!save->node &&
+ (save->offset > split) && (save->offset < mid_split)) {
+ save->offset -= (split + 1);
+ save->node= mast->m->node;
+ save->min = mast->m->min;
+ save->max = mast->m->max;
+ }
split = mid_split;
}
mab_mas_cp(mast->bn, 1 + split, mast->bn->b_end, mast->r);
mast->r->min = mast->bn->pivot[split] + 1;
mast->r->max = mast->bn->pivot[mast->bn->b_end];
+ if (!save->node && (save->offset > split)) {
+ save->offset -= (split + 1);
+ save->node= mast->r->node;
+ save->min = mast->r->min;
+ save->max = mast->r->max;
+ }
+ }
+ if (!save->node) {
+ save->node= mast->l->node;
+ save->min = mast->l->min;
+ save->max = mast->l->max;
}
}
* Return: the number of elements in b_node during the last loop.
*/
static int mas_spanning_rebalance(struct ma_state *mas,
- struct maple_subtree_state *mast,
- unsigned char count)
+ struct maple_subtree_state *mast, unsigned char count)
{
+ struct ma_state restore;
unsigned char split, mid_split;
unsigned char slot = 0;
struct maple_enode *left = NULL, *middle = NULL, *right = NULL;
mast->free = &free;
mast->destroy = &destroy;
l_mas.node = r_mas.node = m_mas.node = MAS_NONE;
-
+ if (!mas_is_root_limits(mas) &&
+ unlikely(mast->bn->b_end <= mt_min_slots[mast->bn->type])) {
+ // Do not free the current node as it may be freed in a bulk
+ // free.
+ if (!mast_sibling_rebalance_right(mast, false))
+ mast_cousin_rebalance_right(mast, false);
+ }
+ restore.node = NULL;
+ restore.offset = mas->offset;
mast->orig_l->depth = 0;
- mast_topiary(mast);
+
while (count--) {
mast_setup_bnode_for_split(mast);
split = mas_mab_to_node(mas, mast->bn, &left, &right, &middle,
&mid_split);
mast_set_split_parents(mast, left, middle, right, split,
mid_split);
- mast_cp_to_nodes(mast, left, middle, right, split, mid_split);
+ mast_cp_to_nodes(mast, left, middle, right, split, mid_split,
+ &restore);
/* Copy data from next level in the tree to mast->bn from next iteration */
memset(mast->bn, 0, sizeof(struct maple_big_node));
// Try to get enough data for the next iteration.
- if (!mast_sibling_rebalance_right(mast))
- if (!mast_cousin_rebalance_right(mast))
+ if (!mast_sibling_rebalance_right(mast, true))
+ if (!mast_cousin_rebalance_right(mast, true))
break;
// rebalancing from other nodes may require another loop.
// Set up mas for insertion.
mas_dup_state(mas, mast->orig_l);
mas_wmb_replace(mas, &free, &destroy);
+ mas->offset = restore.offset;
+ mas->min = restore.min;
+ mas->max = restore.max;
+ mas->node = restore.node;
return mast->bn->b_end;
}
*
* Return: the number of elements in b_node during the last loop.
*/
-static inline int mas_rebalance(struct ma_state *mas, struct maple_big_node *b_node)
+static inline int mas_rebalance(struct ma_state *mas,
+ struct maple_big_node *b_node)
{
char empty_count = mas_mt_height(mas);
struct maple_subtree_state mast;
mas_prev_sibling(&l_mas);
shift = mas_data_end(&l_mas) + 1;
mab_shift_right(b_node, shift);
+ mas->offset += shift;
mas_mab_cp(&l_mas, 0, shift - 1, b_node, 0);
b_node->b_end = shift + b_end;
l_mas.index = l_mas.last = l_mas.min;
* @split: The location to split the big node
*/
static inline void mast_split_data(struct maple_subtree_state *mast,
- struct ma_state *mas,
- unsigned char split)
+ struct ma_state *mas, unsigned char split, struct ma_state *save)
{
unsigned char p_slot;
mast->r->node, &p_slot, split);
mas_set_split_parent(mast->orig_r, mast->l->node,
mast->r->node, &p_slot, split);
+ } else {
+ if (save->offset > split) {
+ save->node = mast->r->node;
+ save->min = mast->r->min;
+ save->max = mast->r->max;
+ save->offset -= (split + 1);
+ } else {
+ save->node = mast->l->node;
+ save->min = mast->l->min;
+ save->max = mast->l->max;
+ }
}
}
* Return: True if pushed, false otherwise.
*/
static inline bool mas_push_data(struct ma_state *mas, int height,
- struct maple_subtree_state *mast, bool left)
+ struct maple_subtree_state *mast, bool left,
+ struct ma_state *save)
{
unsigned char slot_total = mast->bn->b_end;
unsigned char end, space, split;
mab_shift_right(mast->bn, end + 1);
mas_mab_cp(&tmp_mas, 0, end, mast->bn, 0);
mast->bn->b_end = slot_total + 1;
+ if (!save->node)
+ save->offset = mas->offset + end + 1;
} else {
mas_mab_cp(&tmp_mas, 0, end, mast->bn, mast->bn->b_end);
}
if (left)
mast->orig_l->offset += end + 1;
- mast_split_data(mast, mas, split);
+ mast_split_data(mast, mas, split, save);
mast_fill_bnode(mast, mas, 2);
_mas_split_final_node(mast, mas, height + 1);
return true;
struct maple_subtree_state mast;
int height = 0;
unsigned char mid_split, split = 0;
+ struct ma_state restore;
MA_STATE(l_mas, mas->tree, mas->index, mas->last);
MA_STATE(r_mas, mas->tree, mas->index, mas->last);
mast.orig_r = &prev_r_mas;
mast.free = &mat;
mast.bn = b_node;
+ restore.node = NULL;
+ restore.offset = mas->offset;
while (height++ <= mas->depth) {
if (mas_split_final_node(&mast, mas, height))
l_mas.node = mas_new_ma_node(mas, b_node);
r_mas.node = mas_new_ma_node(mas, b_node);
// Try to push left.
- if (mas_push_data(mas, height, &mast, true))
+ if (mas_push_data(mas, height, &mast, true, &restore))
break;
// Try to push right.
- if (mas_push_data(mas, height, &mast, false))
+ if (mas_push_data(mas, height, &mast, false, &restore))
break;
split = mab_calc_split(mas, b_node, &mid_split);
- mast_split_data(&mast, mas, split);
+ mast_split_data(&mast, mas, split, &restore);
// Usually correct, mab_mas_cp in the above call overwrites r->max.
mast.r->max = mas->max;
mast_fill_bnode(&mast, mas, 1);
mat_add(mast.free, mas->node);
mas->node = l_mas.node;
mas_wmb_replace(mas, mast.free, NULL);
+ mas->offset = restore.offset;
+ mas->min = restore.min;
+ mas->max = restore.max;
+ mas->node = restore.node;
return 1;
}
return mas_split(mas, b_node);
if (mas_reuse_node(mas, b_node, end))
- goto reused_node;
+ goto reuse_node;
mas_node_count(mas, 1);
if (mas_is_err(mas))
new_node = mt_mk_node(mas_pop_node(mas), mte_node_type(mas->node));
mte_to_node(new_node)->parent = mas_mn(mas)->parent;
mas->node = new_node;
-
mab_mas_cp(b_node, 0, b_end, mas);
mas_replace(mas, false);
-reused_node:
+reuse_node:
mas_update_gap(mas);
- return 2;
+ return 1;
}
/*
*
* Return: 0 on success, 1 otherwise.
*/
-static inline int mas_root_ptr(struct ma_state *mas, void *entry, bool overwrite)
+static inline int mas_root_ptr(struct ma_state *mas, void *entry,
+ bool overwrite)
{
int ret = 1;
ret = mas_root_expand(mas, entry);
else if (((unsigned long) (entry) & 3) == 2)
ret = mas_root_expand(mas, entry);
- else
+ else {
rcu_assign_pointer(mas->tree->ma_root, entry);
+ mas->node = MAS_START;
+ }
return ret;
exists:
if (unlikely(mas_is_err(mas)))
return existing;
- if (unlikely(!mte_is_leaf(mas->node))) // spanning store occurred
- mas_walk(mas);
-
return existing;
}
if (unlikely(mas_is_err(mas)))
return xa_err(mas->node);
- if (unlikely(!mte_is_leaf(mas->node))) // spanning store occurred
- mas_walk(mas);
-
return 0;
-
}
/*