return true;
}
-static inline void mas_encoded_parent(struct ma_state *mas)
+static inline void mas_ascend(struct ma_state *mas)
{
- struct maple_enode *p_enode, *gp_enode;
- enum maple_type ptype, gptype;
- unsigned char slot;
+ struct maple_enode *p_enode;
+ struct maple_node *p_node;
+ unsigned char p_slot;
+ enum maple_type p_type;
- ptype = mas_parent_enum(mas, mas->node);
- p_enode = mt_mk_node(mte_parent(mas->node), ptype);
- if (_ma_is_root(mte_parent(mas->node))) {
- mas->node = p_enode;
- mas_set_slot(mas, 0); // No slot.
+ p_type = mas_parent_enum(mas, mas->node);
+ p_node = mte_parent(mas->node);
+ p_slot = mte_parent_slot(mas->node);
+ p_enode = mt_mk_node(p_node, p_type);
+ if (_ma_is_root(p_node)) {
mas->min = 0;
- mas->max = mt_max[ptype];
- return;
+ mas->max = mt_max[p_type];
+ } else if (!p_slot || p_slot >= mt_pivots[p_type]) {
+ mas->node = p_enode;
+ mas_ascend(mas);
+ mas_set_slot(mas, p_slot);
+ mas_descend(mas);
+ } else {
+ struct maple_enode *gp_enode = mt_mk_node(mte_parent(p_enode),
+ mas_parent_enum(mas, p_enode));
+ unsigned char gp_slot = mte_parent_slot(p_enode);
+ mas->node = gp_enode;
+ mas_set_slot(mas, gp_slot);
+ mas_update_limits(mas, gp_slot, mas_parent_enum(mas, p_enode));
}
-
- gptype = mas_parent_enum(mas, p_enode);
- gp_enode = mt_mk_node(mte_parent(p_enode), gptype);
- slot = mte_parent_slot(p_enode);
- mas->node = gp_enode;
- mas_set_slot(mas, slot);
- mas_update_limits(mas, slot, gptype);
mas->node = p_enode;
}
+
/* mas_get_prev_pivot() - Return the previous pivot.
*
* Mainly for extracting the previous pivot in the case of slot = 0.
while (prev_piv.min == mas->min) {
p_slot = mte_parent_slot(prev_piv.node);
- mas_encoded_parent(&prev_piv);
+ mas_ascend(&prev_piv);
if (p_slot)
break;
}
void *entry;
piv = _mas_get_safe_pivot(mas, slot, type);
+ printk("%p[%u] piv %lu\n", mas_mn(mas), slot, piv);
if (!piv && slot) { // Past the end of data.
slot--;
piv = prev_piv;
counted_null = 0;
}
- if (piv == mas->max)
+ if (piv == mas->max) {
+ printk("max hit %lu\n", mas->max);
break;
+ }
prev_piv = piv;
}
+ printk("last piv %lu slot %u coalesce %u\n", piv, slot, *coalesce);
*last_piv = piv;
return slot;
}
enum maple_type type, unsigned char slot,
unsigned long piv, void *entry, bool flush)
{
- printk("set %p[%u] -> %p\n", mn, slot, entry);
+ //printk("set %p[%u] -> %p\n", mn, slot, entry);
ma_set_rcu_slot(mn, slot, type, entry);
if (flush)
wmb(); // data needs to exist before pivot for readers
if (right) {
split = mas_cp_calc_split(mas, mas_type, append);
- printk("Using split of %d\n", split);
+ // printk("Using split of %d\n", split);
}
if (left) {
p_slot = mte_parent_slot(left->node);
parent = mte_parent(left->node);
mas_type = mas_parent_enum(mas, left->node);
- printk("parent is %p\n", parent);
+ // printk("parent is %p\n", parent);
}
if (!entry_cnt)
piv[2] = mas->max;
if (append) { // start at a given slot, so append there.
- printk("append\n");
+ // printk("append\n");
//mt_dump(mas->tree);
mas_dup_state(&cp, mas);
src_slot = entry_cnt;
if (!written_piv) // empty node.
written_piv = mas->min;
- printk("src_slot %u written %lu\n", src_slot, written_piv);
+ // printk("src_slot %u written %lu\n", src_slot, written_piv);
slot = entry_cnt;
if (existing) {
slot++;
src_slot++;
- printk("there is an existing\n");
+ // printk("there is an existing\n");
}
entry_cnt = 0;
do {
int i = 2; // Default to just writing the pivot.
int j = 3; // Loop limit.
- printk("src slot %u entry_cnt %d slot %u\n", src_slot, entry_cnt, slot);
+ // printk("src slot %u entry_cnt %d slot %u\n", src_slot, entry_cnt, slot);
if (entry_cnt < 0) {
- printk("Setting to appending mode\n");
+ // printk("Setting to appending mode\n");
appending = true;
existing = NULL;
piv[2] = mas->max;
if (!piv[2] && src_slot)
piv[2] = mas->max;
existing = mte_get_rcu_slot(mas->node, src_slot);
- printk("getting %u (%lu->%p)\n", src_slot, piv[2],
- existing);
+ // printk("getting %u (%lu->%p)\n", src_slot, piv[2],
+ // existing);
}
if (!appending) {
if (mt_will_coalesce(existing)) {
- printk("coalesce\n");
+ // printk("coalesce\n");
goto skip_src_slot;
}
if (append || (attempt_insert && (cp.index <= piv[2]))) {
i = 0;
- printk("Written piv %lu\n", written_piv);
+ // printk("Written piv %lu\n", written_piv);
if (written_piv == cp.index - 1)
i = 1; // previous pivot matches exactly.
else if (!src_slot && written_piv == cp.index)
i = 1; // mas->min matches exactly.
- printk("piv2 %lu <= last %lu\n", piv[2], cp.last);
+ // printk("piv2 %lu <= last %lu\n", piv[2], cp.last);
if (appending)
j--;
else if (!appending && (piv[2] <= cp.last))
j--; // skip last pivot.
- printk("piv array %u-%u\n", i, j);
+ // printk("piv array %u-%u\n", i, j);
attempt_insert = false;
}
if (!loop_entry && !ma_is_leaf(mn_type))
{
- printk("BUG Here\n");
+ // printk("BUG Here\n");
}
- printk("write array %d %lu to %u entry_cnt %d\n", i, piv[i], slot, entry_cnt);
+ // printk("write array %d %lu to %u entry_cnt %d\n", i, piv[i], slot, entry_cnt);
if (i == 1)
loop_entry = entry;
(slot > split)) {
ret = slot - 1;
if (update_gaps) {
- printk("Write gap %p[%u] -> %lu\n", parent, p_slot, max_gap);
+ // printk("Write gap %p[%u] -> %lu\n", parent, p_slot, max_gap);
parent->ma64.gap[p_slot] = max_gap;
}
else
ret = src_slot - 1;
- printk("Done\n");
+ // printk("Done\n");
return ret;
}
unsigned long max_gap = 0;
unsigned char max_slot = 0;
- mas_encoded_parent(mas);
+ mas_ascend(mas);
mte_set_gap(mas->node, slot, new);
if (mte_is_root(mas->node))
p_slot = mte_parent_slot(mas->node);
mas_dup_state(&parent, mas);
- mas_encoded_parent(&parent);
+ mas_ascend(&parent);
old_parent = parent.node;
ptype = mte_node_type(parent.node);
printk("req slots %d\n", req_slots);
// Check if it's safe to use the slot without a pivot.
- if (max == mas->max) // max of the slot == max of the node.
+ // max of the slot == max of the node.
+ // max of the tree is being set.
+ if ((max == mas->max && mas->max != ULONG_MAX) ||
+ (mas->max == ULONG_MAX && mas->last == ULONG_MAX))
return req_slots;
if (!last_entry) // nothing at the last slot.
printk("Adding %lu-%lu\n", mas->index, mas->last);
new_end = _mas_add_slot_cnt(mas, slot, min, max) - coalesce;
- mt_dump(mas->tree);
printk("%s: %p new_end %u slot_cnt %u\n", __func__, mas_mn(mas),
new_end, slot_cnt);
if (new_end > slot_cnt) {
if (mte_is_root(mas->node))
goto no_entry;
- mas_encoded_parent(mas);
+ mas_ascend(mas);
if (mas->max > max)
goto no_entry;
// Walk up.
while (1) {
slot = mte_parent_slot(mas->node);
- mas_encoded_parent(mas);
+ mas_ascend(mas);
if (mas->min < min)
goto no_entry;
while (1) {
unsigned long min;
- mas_encoded_parent(mas);
+ mas_ascend(mas);
level++;
if (!mas_safe_slot(mas, &slot, -1))
slot = mas_get_slot(mas);
start_piv = mas_get_safe_pivot(mas, slot);
level++;
- mas_encoded_parent(mas);
+ mas_ascend(mas);
if (!mas_safe_slot(mas, &slot, 1)) {
if (mte_is_root(mas->node))
if (!mas_next_nentry(mas, limit, &range_start)) {
void *entry = mte_get_rcu_slot(mas->node, slot - 1);
if (mte_is_leaf(mas->node)) {
- mas->index = range_start;
+ mas->index = range_start - 1;
return entry;
}
mas->max = prev_max;
mas->last = max;
slot = mas_get_slot(mas);
+ printk("%s: slot %u\n", __func__, slot);
if (slot)
mas->index = mas_get_safe_pivot(mas, slot - 1) + 1;
else
return mas_last_entry(mas, ULONG_MAX);
}
- entry = _mas_prev(mas, min);
+ do {
+ entry = _mas_prev(mas, min);
+ } while (!entry || mt_will_coalesce(entry));
+
return entry;
}
EXPORT_SYMBOL_GPL(mas_prev);
struct maple_enode *eparent, unsigned char p_slot,
enum maple_type p_type)
{
- mte_set_rcu_slot(eparent, p_slot, XA_SKIP_ENTRY);
+ mte_set_rcu_slot(eparent, p_slot, XA_DELETED_ENTRY);
mas_set_slot(mas, p_slot);
- mas_coalesce_pivots(mas, p_slot, p_type, true);
+ mas_coalesce_pivots(mas, p_slot, p_type, false);
}
/** Private
this_p_slot = mte_parent_slot(this_enode);
mas_dup_state(&p_state, mas); // set the parent node, etc.
- mas_encoded_parent(&p_state); // Actually make it the parent.
+ mas_ascend(&p_state); // Actually make it the parent.
// Get the next entry.
mas_set_slot(&p_state, this_p_slot + 1);
// this_enode is the right-most node of the parent.
// Reset parent info.
mas_dup_state(&p_state, mas);
- mas_encoded_parent(&p_state);
+ mas_ascend(&p_state);
mas_set_slot(&p_state, this_p_slot);
if (mas_prev_nentry(&p_state, 0, &r_piv)) {
// If there is a node to the left, rebalance the left
printk("ends in null at %p[%u] => %ld\n", this_enode, l_slot_cnt, r_state.max);
mte_set_pivot(this_enode, l_slot_cnt, r_state.max);
do { // FIXME: What about non-end nodes?
- mas_encoded_parent(mas);
+ mas_ascend(mas);
mte_set_pivot(mas->node, this_p_slot, r_state.max);
this_p_slot = mte_parent_slot(mas->node);
} while (!mte_is_root(mas->node));
cp_state.max = cp_state.last; // update cp state max.
cp.src_start = i;
}
- // if right isn't fully consumed
- // mas_copy to new right.
//
mte_to_node(cp_state.node)->parent = mte_to_node(this_enode)->parent;
this_p_slot = mte_parent_slot(this_enode);
mas_dup_state(&p_state, mas); // set the parent node, etc.
- mas_encoded_parent(&p_state); // Actually make it the parent.
+ mas_ascend(&p_state); // Actually make it the parent.
// Get the next entry.
mas_set_slot(&p_state, this_p_slot + 1);
// this_enode is the right-most node of the parent.
// Reset parent info.
mas_dup_state(&p_state, mas);
- mas_encoded_parent(&p_state);
+ mas_ascend(&p_state);
mas_set_slot(&p_state, this_p_slot);
if (mas_prev_nentry(&p_state, 0, &r_piv)) {
// If there is a node to the left, rebalance the left
// No left or right, rebalance the parent.
// But first, remove this entry if it's empty.
if (end < coalesce) {
- printk("%d empty\n", __LINE__);
+ printk("%d empty %d %d\n", __LINE__, end, coalesce);
+ // FIXME: deleted?
+ // deleted.. AND FREE!
mas_coalesce_empty(&p_state, p_state.node, this_p_slot,
mte_node_type(p_state.node));
}
return 1;
}
+ printk("left and right\n");
// If we reached here, then the node to the right exists.
// set the ma_state information and save a copy for this slot.
mas_dup_state(&r_state, &p_state);
printk("r_slot_cnt %u\n", r_slot_cnt);
if (r_end < r_coalesce && r_state.max != ULONG_MAX) {
printk("skip entry?\n");
- // This node needs to be a skip entry.
+ // This node needs to be a deleted entry.
all_slots = l_slot_cnt;
new_type = mte_node_type(this_enode);
l_piv = r_state.max;
if (all_slots > mt_slot_count(this_enode) - 1)
node_cnt++;
- printk("%d l_slot_cnt %d\n", __LINE__, l_slot_cnt);
+ printk("%d l_slot_cnt %d %u %u\n", __LINE__, l_slot_cnt, end, coalesce);
// check if left ends in NULL
if (l_slot_cnt && !mte_get_rcu_slot(this_enode, l_slot_cnt))
l_null_end = true;
printk("ends in null at %p[%u] => %ld\n", this_enode, l_slot_cnt, r_state.max);
mte_set_pivot(this_enode, l_slot_cnt, r_state.max);
do {
- mas_encoded_parent(mas);
+ unsigned old_piv, old_mas_max = mas->max;
+ mas_ascend(mas);
+ old_piv = mte_get_pivot(mas->node, this_p_slot);
+ if (old_piv != old_mas_max)
+ break;
mte_set_pivot(mas->node, this_p_slot, r_state.max);
this_p_slot = mte_parent_slot(mas->node);
} while (!mte_is_root(mas->node));
- return 0;
+ return 1;
}
mas_node_cnt(mas, node_cnt);
- if (mas_is_err(mas))
+ if (mas_is_err(mas)) {
+ // Special case. If we are failing to allocate but the tree
+ // should be collapsed back, then do the right thing (tm).
+ if ((r_end == r_coalesce) &&
+ (r_state.max == ULONG_MAX) &&
+ (end >= coalesce)) {
+ mte_set_pivot(this_enode, l_slot_cnt, r_state.max);
+ do {
+ unsigned old_piv, old_mas_max = mas->max;
+ mas_ascend(mas);
+ old_piv = mte_get_pivot(mas->node, this_p_slot);
+ if (old_piv != old_mas_max)
+ break;
+ mte_set_pivot(mas->node, this_p_slot, r_state.max);
+ this_p_slot = mte_parent_slot(mas->node);
+ } while (!mte_is_root(mas->node));
+ r_p_slot = mte_parent_slot(r_enode);
+ mas_coalesce_empty(&r_state, p_state.node, r_p_slot,
+ mte_node_type(p_state.node));
+ mt_dump(mas->tree);
+ }
return 0;
+ }
printk("here %d\n", __LINE__);
// Coalesce this_enode into a new node.
void *entry;
start:
+ mt_dump(mas->tree);
if (mte_is_root(mas->node))
return mas_coalesce_root(mas);
this_enode = mas->node;
this_type = mte_node_type(this_enode);
end = mas_data_end(mas, this_type, &this_piv, &coalesce);
+ printk("data end of %p = %u\n", mas_mn(mas), end);
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);
h_data = ma_hard_data(end, coalesce);
if (h_data < mt_min_slots[this_type] - 1) {
printk("rebalance?\n");
- if (mas_rebalance(mas, end, coalesce)) {
- mt_dump(mas->tree);
+ if (mas_rebalance(mas, end, coalesce))
goto done;
- }
if (mas_is_err(mas)) {
- if (h_data >= 1)
+ if (end >= coalesce)
return;
if (mas->max == ULONG_MAX)
return;
// Single entry and allocation failed, free this_enode
- printk("failure path?\n");
+ printk("failure path? %u %u\n", end, coalesce);
+ // FIXME: Deleted?
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;
}
}
if (!mt_is_empty(entry))
goto check_start;
- if (end <= coalesce) {
- printk("%d empty %p\n", __LINE__, mas_mn(mas));
- mas_coalesce_empty(mas, eparent, p_slot, p_type);
- check_parent = true;
- }
// Check if next node starts with null.
mas_next_slot(mas, ULONG_MAX);
if (!slot) {
// Empty node...
+ // deleted.. AND FREE!
mas_coalesce_empty(mas, eparent, p_slot, p_type);
check_parent = true;
piv = mas->min;
mas->node = this_enode;
if (check_parent) {
check_parent = false;
- mas_encoded_parent(mas);
+ mas_ascend(mas);
+ printk(" -> max is %lu\n", mas->max);
mte_free(this_enode);
+ printk("going to start with %p\n", mas_mn(mas));
goto start;
}
while (mas_search_cont(mas, index, max, entry)) {
entry = _mas_next(mas, max, &index);
+ printk("%s: %ld -> %p\n", __func__, mas->index, entry);
if (mt_is_empty(entry))
entry = NULL;
}
+ printk("%s: %ld -> %p\n", __func__, mas->index, entry);
if (entry)
mas->index = index;
MA_STATE(r_mas, mas->tree, mas->last + 1, mas->last + 1);
MA_STATE(l_mas, mas->tree, 0, 0);
- mt_dump(mas->tree);
// Count the slots that will be used in the node we landed.
slot_cnt = 3 + mas_get_slot(mas); // 3 is the max a new entry can create.
* calculate the index and last will cause an issue in the gap
* calculation, so fix the ma_state here
*/
- mas_encoded_parent(mas);
+ mas_ascend(mas);
mas->max = mas_get_safe_pivot(mas, pslot);
if (pslot)
mas->min = mas_get_safe_pivot(mas, pslot - 1) + 1;
}
} else {
slot = mte_parent_slot(mas->node);
- mas_encoded_parent(mas);
+ mas_ascend(mas);
}
} while (!slot);
}
} else {
slot = mte_parent_slot(mas->node);
- mas_encoded_parent(mas);
+ mas_ascend(mas);
}
} while (slot > mt_slot_count(mas->node) - 1);
return;
mas->node = mn;
- mas_encoded_parent(mas);
+ mas_ascend(mas);
while (mas->node != MAS_NONE) {
p = mas->node;
p_min = mas->min;