int split = b_node->b_end / 2; // Assume equal split.
unsigned char slot_cnt = mt_slots[b_node->type];
- if (mab_middle_node(b_node, b_node->b_end, split, slot_cnt)) {
+ if (ma_is_leaf(b_node->type) &&
+ mab_middle_node(b_node, b_node->b_end, split, slot_cnt)) {
split = b_node->b_end / 3;
*mid_split = split * 2;
} else {
b_node->b_end = j;
}
-static inline int mab_mas_cp(struct maple_big_node *b_node,
- unsigned char mab_start, unsigned char mab_end,
- struct ma_state *mas, unsigned char mas_start)
+static inline void mab_mas_cp(struct maple_big_node *b_node,
+ unsigned char mab_start, unsigned char mab_end,
+ struct ma_state *mas, unsigned char mas_start)
{
int i, j;
if (!mte_is_leaf(mas->node) && mt_is_alloc(mas->tree))
mte_set_gap(mas->node, j, b_node->gap[i]);
}
-
- return i;
}
static inline void mas_descend_adopt(struct ma_state *mas)
mas_descend(mas);
return true;
}
-/* mast_consume() - Add the portions of the tree which will be replaced by the
+/* mast_topiary() - Add the portions of the tree which will be replaced by the
* operation to the removal list; either to be @free or @discard (destroy walk).
*/
-static inline void mast_consume(struct maple_subtree_state *mast)
+static inline void mast_topiary(struct maple_subtree_state *mast)
{
unsigned char l_slot, r_slot, slot, end;
- unsigned long l_min, range_min, range_max;
+ unsigned long l_index, range_min, range_max;
// The left node is consumed, so add to the free list.
- l_min = mast->orig_l->index;
+ l_index = mast->orig_l->index;
mast->orig_l->index = mast->orig_l->last;
mas_node_walk(mast->orig_l, mte_node_type(mast->orig_l->node),
&range_min, &range_max);
- mast->orig_l->index = l_min;
+ mast->orig_l->index = l_index;
l_slot = mas_get_slot(mast->orig_l);
r_slot = mas_get_slot(mast->orig_r);
if (mast->orig_l->node == mast->orig_r->node) {
- /* If the contents up to l_slot and from r_slot to end are
- * still valid and it's the same node, then the rest may need to
- * be mast->destroyed. The exception is if a there is data taken
- * from the parent in the previous iteration which is still in
- * use.
- */
for (slot = l_slot + 1; slot < r_slot; slot++)
mat_add(mast->destroy,
mas_get_rcu_slot(mast->orig_l, slot));
if (mte_is_leaf(mast->orig_r->node))
return;
- /* Now free l_slot + 1 -> end and 0 -> r_slot - 1 */
+ /* Now destroy l_slot + 1 -> end and 0 -> r_slot - 1 */
end = mas_data_end(mast->orig_l);
for (slot = l_slot + 1; slot <= end; slot++)
mat_add(mast->destroy, mas_get_rcu_slot(mast->orig_l, slot));
} else {
do {
mast_ascend_free(mast);
- mast_consume(mast);
+ mast_topiary(mast);
} while (!mte_is_root(mast->orig_l->node));
}
return false;
}
+
+static inline void mast_setup_bnode_for_split(struct maple_subtree_state *mast)
+{
+ mast->bn->b_end--;
+ mast->bn->min = mast->orig_l->min;
+ mast->bn->type = mte_node_type(mast->orig_l->node);
+}
+
/* Private
*
* mas_combine_separate() - Follow the tree upwards from @l_mas and @r_mas for
* Returns the number of elements in b_node during the last loop.
*/
static inline int mas_combine_separate(struct ma_state *mas,
- struct maple_subtree_state *mast, unsigned char count)
+ struct maple_subtree_state *mast,
+ unsigned char count)
{
unsigned char split, mid_split;
unsigned char slot = 0;
/* MA_START doesn't work here */
l_mas.node = r_mas.node = m_mas.node = NULL;
- mast_consume(mast);
+ mast_topiary(mast);
while(count--) {
- mast->bn->b_end--;
- mast->bn->min = mast->orig_l->min;
- mast->bn->type = mte_node_type(mast->orig_l->node);
+ 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, right, split);
/* Copy data from next level in the tree to mast->bn from next iteration */
memset(mast->bn, 0, sizeof(struct maple_big_node));
+ mast->bn->b_end = 0;
mast->orig_l->depth++;
if (mast_new_root(mast, mas))
goto new_root;
mast_ascend_free(mast);
-
- mast->bn->b_end = 0;
mast_combine_cp_left(mast);
-
mas_set_slot(&l_mas, mast->bn->b_end);
mab_set_b_end(mast->bn, &l_mas, left);
mab_set_b_end(mast->bn, &m_mas, middle);
// Copy anything necessary out of the right node.
mast_combine_cp_right(mast);
- mast_consume(mast);
+ mast_topiary(mast);
mast->orig_l->last = mast->orig_l->max;
if(mast_sufficient(mast))
return mas_combine_separate(mas, &mast, empty_cnt);
}
+static inline bool mas_split_final_node(struct maple_subtree_state *mast,
+ struct ma_state *mas, int height)
+{
+ struct maple_enode *ancestor;
+
+ if (height <= mas->full_cnt)
+ return false;
+
+ if (mte_is_root(mas->node)) {
+ if (mt_is_alloc(mas->tree))
+ mast->bn->type = maple_arange_64;
+ else
+ mast->bn->type = maple_range_64;
+ mas->depth = height;
+ }
+ /* Only a single node is used here, could be root.
+ * Big_node should just fit in a single node.
+ */
+ ancestor = mas_new_ma_node(mas, mast->bn);
+ mte_set_parent(mast->l->node, ancestor, mas_get_slot(mast->l));
+ mte_set_parent(mast->r->node, ancestor, mas_get_slot(mast->r));
+ mte_to_node(ancestor)->parent = mas_mn(mas)->parent;
+ // New root requires a new height.
+ if (mas->full_cnt >= mas->tree->ma_height)
+ mas->tree->ma_height++;
+
+ mast->l->node = ancestor;
+ mab_mas_cp(mast->bn, 0, mt_slots[mast->bn->type] - 1, mast->l, 0);
+ return true;
+}
+
+static inline void mast_split_fill_bnode(struct maple_subtree_state *mast,
+ struct ma_state *mas)
+{
+ bool cp = true;
+ struct maple_enode *old = mas->node;
+ unsigned char split;
+
+ memset(mast->bn, 0, sizeof(struct maple_big_node));
+ if (mte_is_root(mas->node)) {
+ cp = false;
+ } else {
+ mas_ascend(mas);
+ mat_add(mast->free, old);
+ mas_set_slot(mas, mte_parent_slot(mas->node));
+ }
+
+ mast->bn->min = mas->min;
+ if (cp && mas_get_slot(mast->l))
+ mas_mab_cp(mas, 0, mas_get_slot(mast->l) - 1, mast->bn, 0);
+
+ split = mast->bn->b_end;
+ mab_set_b_end(mast->bn, mast->l, mast->l->node);
+ mas_set_slot(mast->r, mast->bn->b_end);
+ mab_set_b_end(mast->bn, mast->r, mast->r->node);
+ if (cp)
+ mas_mab_cp(mas, split + 1, mt_slot_count(mas->node) - 1,
+ mast->bn, mast->bn->b_end);
+ mast->bn->b_end--;
+ mast->bn->type = mte_node_type(mas->node);
+}
+
static inline int mas_split(struct ma_state *mas,
struct maple_big_node *b_node)
{
- struct maple_enode *ancestor = MAS_NONE;
- unsigned char split = 0;
- int j, height = 0;
+ struct maple_subtree_state mast;
+ unsigned char p_slot, split = 0;
+ int height = 0;
+ unsigned char mid_split;
MA_STATE(l_mas, mas->tree, mas->index, mas->last);
MA_STATE(r_mas, mas->tree, mas->index, mas->last);
- MA_STATE(orig_l_mas, mas->tree, mas->index, mas->last);
- MA_STATE(orig_r_mas, mas->tree, mas->index, mas->last);
-
+ MA_STATE(prev_l_mas, mas->tree, mas->index, mas->last);
+ MA_STATE(prev_r_mas, mas->tree, mas->index, mas->last);
MA_TOPIARY(mat, mas->tree);
// Allocation failures will happen early.
if (mas_is_err(mas))
return 0;
+ mast.l = &l_mas;
+ mast.r = &r_mas;
+ mast.free = &mat;
+ mast.bn = b_node;
+
while (height++ <= mas->full_cnt) {
- unsigned char mid_split;
- unsigned char slot_cnt = mt_slot_count(mas->node);
- bool cp = true;
-
- b_node->type = mte_node_type(mas->node);
- if (height > mas->full_cnt) {
- // The last node to be created.
- if (mte_is_root(mas->node)) {
- if (mt_is_alloc(mas->tree))
- b_node->type = maple_arange_64;
- else
- b_node->type = maple_range_64;
- mas->depth = height;
- }
- /* Only a single node is used here, could be root.
- * Big_node should just fit in a single node.
- */
- ancestor = mas_new_ma_node(mas, b_node);
- mte_set_parent(l_mas.node, ancestor,
- mas_get_slot(&l_mas));
- mte_set_parent(r_mas.node, ancestor,
- mas_get_slot(&r_mas));
- mte_to_node(ancestor)->parent = mas_mn(mas)->parent;
- // New root requires a new height.
- if (mas->full_cnt >= mas->tree->ma_height)
- mas->tree->ma_height++;
- l_mas.node = ancestor;
- mab_mas_cp(b_node, 0, mt_slots[b_node->type] - 1,
- &l_mas, 0);
+ if (mas_split_final_node(&mast, mas, height))
break;
- }
- b_node->min = mas->min;
mas_dup_state(&l_mas, mas);
mas_dup_state(&r_mas, mas);
l_mas.node = mas_new_ma_node(mas, b_node);
r_mas.node = mas_new_ma_node(mas, b_node);
- if (mte_is_leaf(mas->node)) {
- split = mab_calc_split(b_node, &mid_split);
- if (split < slot_cnt)
- j = mab_mas_cp(b_node, 0, split, &l_mas, 0);
- else
- j = mab_mas_cp(b_node, 0, slot_cnt, &l_mas, 0);
-
- mte_set_pivot(r_mas.node, 0, r_mas.max);
- mab_mas_cp(b_node, j, b_node->b_end, &r_mas, 0);
- mas_set_slot(&l_mas, mte_parent_slot(mas->node));
- r_mas.min = l_mas.max + 1;
- // In the case of empty.
- mas_set_slot(&r_mas, mas_get_slot(&l_mas) + 1);
- } else {
- unsigned char p_slot;
- /* Note, look into shifting data left or right */
- /* internal node split - cut in half for now. */
- split = slot_cnt / 2;
- j = mab_mas_cp(b_node, 0, split, &l_mas, 0);
- l_mas.max = b_node->pivot[j - 1];
- r_mas.min = l_mas.max + 1;
- mab_mas_cp(b_node, j, slot_cnt, &r_mas, 0);
- p_slot = mas_get_slot(&orig_l_mas);
- mas_set_split_parent(&orig_l_mas, l_mas.node,
- r_mas.node, &p_slot, split);
- mas_set_split_parent(&orig_r_mas, l_mas.node,
- r_mas.node, &p_slot, split);
- }
-
- b_node->b_end = 0;
- memset(b_node, 0, sizeof(struct maple_big_node));
- if (mte_is_root(mas->node)) {
- cp = false;
- } else {
- struct maple_enode *old = mas->node;
-
- mas_ascend(mas);
- mat_add(&mat, old);
- mas_set_slot(mas, mte_parent_slot(mas->node));
+ split = mab_calc_split(b_node, &mid_split);
+ mab_mas_cp(b_node, 0, split, &l_mas, 0);
+ mte_set_pivot(r_mas.node, 0, r_mas.max);
+ mab_mas_cp(b_node, split + 1, b_node->b_end, &r_mas, 0);
+ mas_set_slot(&l_mas, mte_parent_slot(mas->node));
+ l_mas.max = b_node->pivot[split];
+ r_mas.min = l_mas.max + 1;
+ if (!mte_is_leaf(mas->node)) {
+ p_slot = mas_get_slot(&prev_l_mas);
+ mas_set_split_parent(&prev_l_mas, l_mas.node,
+ r_mas.node, &p_slot, split);
+ mas_set_split_parent(&prev_r_mas, l_mas.node,
+ r_mas.node, &p_slot, split);
}
-
- if (cp && mas_get_slot(&l_mas))
- mas_mab_cp(mas, 0, mas_get_slot(&l_mas) - 1, b_node, 0);
-
- split = b_node->b_end;
- mab_set_b_end(b_node, &l_mas, l_mas.node);
- mas_set_slot(&r_mas, b_node->b_end);
- mab_set_b_end(b_node, &r_mas, r_mas.node);
- mas_dup_state(&orig_l_mas, &l_mas);
- mas_dup_state(&orig_r_mas, &r_mas);
- if (cp)
- mas_mab_cp(mas, split + 1, mt_slot_count(mas->node) - 1,
- b_node, b_node->b_end);
+ mast_split_fill_bnode(&mast, mas);
+ mas_dup_state(&prev_l_mas, mast.l);
+ mas_dup_state(&prev_r_mas, mast.r);
}
// Set the original node as dead
- mat_add(&mat, mas->node);
- mas->node = ancestor;
- mas_wmb_replace(mas, &mat, NULL);
+ mat_add(mast.free, mas->node);
+ mas->node = l_mas.node;
+ mas_wmb_replace(mas, mast.free, NULL);
return 1;
}
memset(&b_node, 0, sizeof(struct maple_big_node));
mas_set_slot(mas, slot);
b_node.b_end = mas_store_b_node(mas, &b_node, entry);
+ b_node.min = mas->min;
// Check if this is an append operation.
end = mas_data_end(mas);
else if (b_node.b_end < mt_min_slot_cnt(mas->node))
mas_cnt_empty(mas);
+ b_node.type = mte_node_type(mas->node);
mas_commit_b_node(mas, &b_node);
if (mas_is_err(mas))
ret = 3;