return ((unsigned long)entry >> 3) & 15;
}
+
+static inline bool ma_is_dense(const enum maple_type type)
+{
+ return type < maple_sparse_6;
+}
+
static inline bool ma_is_leaf(const enum maple_type type)
{
return type < maple_range_16;
{
unsigned char slot, coalesce;
+ if (mte_is_root(mas->node))
+ goto no_entry;
+
// Walk up.
while (1) {
slot = mte_parent_slot(mas->node);
return ma_hard_data(end, coalesce);
}
-static inline void mas_coalesce_empty(struct ma_state *mas,
- struct maple_enode *eparent, unsigned char p_slot)
+static inline void mas_coalesce_pivots(struct ma_state *mas, int slot,
+ enum maple_type type, bool skip)
{
- mte_set_rcu_slot(eparent, p_slot, XA_DELETED_ENTRY);
+ unsigned long piv_val = _mas_get_safe_pivot(mas, slot, type);
+ unsigned char pivot_cnt = mt_pivots[type];
+ int last_null = slot;
+
+ while ((slot < pivot_cnt - 1)) {
+ unsigned long this_pivot = mte_get_pivot(mas->node, slot + 1);
+
+ if (!this_pivot) // end of node.
+ break;
+
+ // There is data for this pivot.
+ if (!mt_is_empty(mte_get_rcu_slot(mas->node, slot + 1)))
+ break;
+
+ // empty slot above the erase.
+ piv_val = this_pivot;
+ slot++;
+ }
+
+
+ /* Walk down and set all the previous pivots with NULLs to piv_val */
+ while (--slot >= 0) {
+ void *entry = mte_get_rcu_slot(mas->node, slot);
+
+ if (!mt_is_empty(entry)) {
+ last_null = slot + 1;
+ break;
+ }
+ if (!slot)
+ last_null = slot;
+
+ if (skip)
+ mte_set_rcu_slot(mas->node, slot, XA_SKIP_ENTRY);
+
+ mte_set_pivot(mas->node, slot, piv_val);
+ }
+ if (skip)
+ mte_set_rcu_slot(mas->node, last_null, NULL);
+
+}
+static inline void mas_coalesce_empty(struct ma_state *mas,
+ struct maple_enode *eparent, unsigned char p_slot,
+ enum maple_type p_type)
+{
+ mte_set_rcu_slot(eparent, p_slot, NULL);
mas_set_slot(mas, p_slot);
+ mas_coalesce_pivots(mas, p_slot, p_type, true);
}
/** Private
if (coalesce)
coalesce--;
+
l_slot_cnt = ma_hard_data(end, coalesce);
if (mte_is_root(this_enode))
return mas_coalesce_node(mas, end, coalesce, true);
-
+
this_p_slot = mte_parent_slot(this_enode);
mas_encoded_parent(mas);
mas_set_slot(mas, this_p_slot + 1);
if (!mas_next_nentry(mas, ULONG_MAX, &r_piv)) {
- // this_enode is the right-most node.
- BUG_ON(!l_slot_cnt);
+ // this_enode is the right-most node of the parent.
mas->node = this_enode;
mas->max = this_max;
mas->min = this_min;
- mas_set_slot(mas, this_p_slot);
+ //mas_set_slot(mas, this_p_slot);
mas_encoded_parent(mas);
mas_set_slot(mas, this_p_slot);
- // If there is a single entry, rebalance the parent.
if (mas_prev_nentry(mas, 0, &r_piv)) {
+ // If there is a node to the left, rebalance the left
mas->node =
mte_get_rcu_slot(mas->node, mas_get_slot(mas));
end = mas_data_end(mas, mte_node_type(mas->node),
&l_piv, &coalesce);
return mas_rebalance(mas, end, coalesce);
}
+ // No left or right, rebalance the parent.
+ // But first, remove this entry if it's empty.
mas->node = this_enode;
mas->max = this_max;
mas->min = this_min;
mas_set_slot(mas, this_p_slot);
+ if (l_slot_cnt <= 1) {
+ enum maple_type p_type =
+ mas_parent_enum(mas, this_enode);
+ struct maple_enode *eparent =
+ mt_mk_node(mte_parent(this_enode), p_type);
+ mas_coalesce_empty(mas, eparent, this_p_slot, p_type);
+ }
mas_encoded_parent(mas);
mas_coalesce(mas);
+ if (mas_is_err(mas))
+ return 0;
+ return 1;
}
// If we reached here, then the node to the right exists.
this_type = mte_node_type(this_enode);
end = mas_data_end(mas, this_type, &piv, &coalesce);
hard_data = ma_hard_data(end, coalesce);
+ if (end == 1 && coalesce == 1) {
+ mas_first_node(mas, ULONG_MAX);
+ if (mas_is_none(mas)) {
+ // Allocation failures
+
+ mas->tree->ma_root = NULL;
+ mte_free(this_enode);
+ return;
+ }
+ mas->node = this_enode;
+ }
+
if ((end <= coalesce)) {
if(!mte_is_leaf(this_enode)) {
// Remove level in tree.
mas_set_slot(mas, 0);
mas_first_node(mas, ULONG_MAX);
+
mte_to_node(mas->node)->parent =
mte_to_node(this_enode)->parent;
mas->node = mte_mk_root(mas->node);
*
*
* Attempt to move things left with a rebalance. Upon failure, check if there
- * is a contigeous gap from the end of this node to the start of the next.
+ * is a contiguous gap from the end of this node to the start of the next.
*
* Notes:
* - Entries move Left, appending data at the end of the leaf
* - Holes move Right.
* - Either way, parent pivots need to be changed.
+ * - empty nodes will be replaced by skip entries on allocation failure.
*
*
*/
{
unsigned char end, p_slot, coalesce;
struct maple_enode *this_enode, *eparent;
- enum maple_type this_type;
- unsigned long piv;
- void *entry;
+ enum maple_type this_type, p_type;
bool check_parent = false;
+ unsigned long piv, this_piv;
+ int h_data;
+ void *entry;
+start:
if (mte_is_root(mas->node))
return mas_coalesce_root(mas);
-start:
this_enode = mas->node;
this_type = mte_node_type(this_enode);
- end = mas_data_end(mas, this_type, &piv, &coalesce);
+ end = mas_data_end(mas, this_type, &this_piv, &coalesce);
+ p_type = mas_parent_enum(mas, this_enode);
+ p_slot = mte_parent_slot(this_enode);
+ eparent = mt_mk_node(mte_parent(this_enode), p_type);
/* If there is any space to save, try to reallocate */
- if (ma_hard_data(end, coalesce) < mt_min_slots[this_type] - 1) {
+ h_data = ma_hard_data(end, coalesce);
+ if (h_data < mt_min_slots[this_type] - 1) {
if (mas_rebalance(mas, end, coalesce))
goto done;
- if (mas_is_err(mas))
- return;
+ if (mas_is_err(mas)) {
+ if (h_data >= 1)
+ return;
+ // Single entry and allocation failed, free this_enode
+ mas->node = this_enode;
+ mas_encoded_parent(mas);
+ mas_coalesce_empty(mas, eparent, p_slot, p_type);
+ check_parent = true;
+ mas->node = this_enode;
+ goto done;
+ }
}
/* Group the gaps together. Acquire any data from the next node, if
* necessary
*/
- p_slot = mte_parent_slot(this_enode);
- eparent = mt_mk_node(mte_parent(this_enode),
- mas_parent_enum(mas, this_enode));
entry = mte_get_rcu_slot(this_enode, end);
if (!mt_is_empty(entry))
goto check_start;
if (!end || end + 1 <= coalesce) {
- mas_coalesce_empty(mas, eparent, p_slot);
+ mas_coalesce_empty(mas, eparent, p_slot, p_type);
check_parent = true;
}
}
mas->node = eparent;
- mas_update_limits(mas, p_slot, mte_node_type(mas->node));
+ mas_update_limits(mas, p_slot, p_type);
mas->node = this_enode;
if (!slot) {
// Empty node...
- mas_coalesce_empty(mas, eparent, p_slot);
+ mas_coalesce_empty(mas, eparent, p_slot, p_type);
check_parent = true;
piv = mas->min;
} else {
unsigned char prev_end;
// Check the previous node.
mas_prev_slot(mas, 0);
- if (mas->node == MAS_NONE)
+ if (mas_is_none(mas))
goto done;
if (!mt_is_empty(mas->node)) {
if (!mt_is_empty(mte_get_rcu_slot(mas->node, prev_end)))
goto done;
} else {
- piv = mas->min;
+ piv = mte_get_pivot(this_enode, 0);
}
if (p_slot)
mte_set_pivot(eparent, p_slot - 1, piv);
// Walk up and set all the pivots to piv
-
}
done:
mas->node = this_enode;
static inline void *mas_erase(struct ma_state *mas)
{
enum maple_type type;
- unsigned char pivot_cnt;
- unsigned long piv_val;
- int slot, ret = 1;
+ int slot;
void *entry = NULL;
_mas_walk(mas);
return NULL;
type = mte_node_type(mas->node);
- pivot_cnt = mt_pivots[type];
entry = mte_get_rcu_slot(mas->node, slot);
mte_update_rcu_slot(mas->node, slot, XA_DELETED_ENTRY);
// dense nodes only need to set a single value.
- if (!pivot_cnt)
- goto done;
+ if (!ma_is_dense(type))
+ mas_coalesce_pivots(mas, slot, type, false);
- piv_val = _mas_get_safe_pivot(mas, slot, type);
- while ((slot < pivot_cnt - 1)) {
- unsigned long this_pivot = mte_get_pivot(mas->node, slot + 1);
-
- if (!this_pivot) // end of node.
- break;
-
- // There is data for this pivot.
- if (!mt_is_empty(mte_get_rcu_slot(mas->node, slot + 1)))
- break;
-
- // empty slot above the erase.
- piv_val = this_pivot;
- slot++;
- }
-
- /* Walk down and set all the previous pivots with NULLs to piv_val */
- while (--slot >= 0) {
- void *entry = mte_get_rcu_slot(mas->node, slot);
-
- if (!mt_is_empty(entry))
- break;
-
- mte_set_pivot(mas->node, slot, piv_val);
- ret++;
- }
-
-done:
mas_coalesce(mas);
return entry;
}