unsigned long pivots[3];
void *slots[3];
unsigned long gaps[2];
- bool unfinished;
+ //bool unfinished;
unsigned char skip;
bool leaf;
};
part->size++;
}
- part->unfinished = false;
+ //part->unfinished = false;
part->dst_max_off = 255;
part->skip = wr_mas->offset_end - wr_mas->mas->offset + 1;
part->leaf = true;
}
part->pos = 0;
- part->unfinished = false;
+ //part->unfinished = false;
part->dst_max_off = 255;
part->skip = 1;
part->leaf = false;
}
+#if 0
static __always_inline
void mni_insert_part(struct ma_node_part *part,
struct ma_node_info *dst)
//WARN_ON_ONCE(1);
part->unfinished = true;
}
+#endif
static inline
void _mni_node_init(struct ma_node_info *mni, struct maple_node *node,
ni->insert_off = mas->offset;
}
-#if 0
-static void mas_wr_rebalance_nodes(
- struct ma_node_info *l_src,
- struct ma_node_info *r_src,
- struct ma_node_info *left,
- struct ma_node_info *right,
- bool left_store,
- unsigned char split,
- struct ma_node_part *part,
- unsigned char mas_off,
- unsigned char new_end
- )
-{
- unsigned char l_end, r_end;
-
- /*
- * l_src, part, and r_src will be split between the new left and
- * right nodes. Depending on where the split and the store offset
- * (mas_off) falls within the data will determine where the new data
- * will end up in the new nodes (left and right).
- *
- * This is further complicated by the insert potentially spanning the
- * nodes and the left node ending on a NULL. If left does end in null,
- * then the data is shifted forward one (if possible), or back one.
- * Shifting back means copying the data to the right node. Shifting
- * forward is complicated by a potential insert splitting the nodes,
- * which means the new data going to the left will have to come from the
- * part. This is all taken care of in mas_wr_split_no_null().
- */
-
- l_end = l_src->end;
- r_end = r_src->end;
- if (left_store) { /* Store is targeting l_src */
- printk("%s %d\n", __func__, __LINE__);
- if (mas_off <= split) { /* Store will end up in left */
- printk("%s %d\n", __func__, __LINE__);
- if (mas_off)
- mni_cp(l_src, left, mas_off);
-
- part->dst_max_off = split;
- mni_insert_part(part, left);
- l_src->offset+= part->skip;
- printk("%d\n", __LINE__);
-
- printk("\tright min %lu left max %lu\n", right->min, left->max);
- if (left->offset <= split)
- mni_cp(l_src, left, split - left->offset + 1);
-
- printk("\tright min %lu left max %lu\n", right->min, left->max);
- mas_wr_split_no_null(l_src, left, right,
- r_end + new_end + 1, part);
- right->min = left->max + 1;
- printk("\tright min %lu left max %lu\n", right->min, left->max);
- if (part->unfinished)
- mni_insert_part(part, right);
-
- if (l_end >= l_src->offset)
- mni_cp(l_src, right, l_end - l_src->offset + 1);
-
- } else { /* Store will end up in right */
- printk("%s %d\n", __func__, __LINE__);
- mni_cp(l_src, left, split + 1);
- mas_wr_split_no_null(l_src, left, right,
- r_end + new_end + 1, part);
- right->min = left->max + 1;
- mni_cp(l_src, right, mas_off - l_src->offset);
- mni_insert_part(part, right);
- //printk("%d\n", __LINE__);
- l_src->offset+= part->skip;
- if (l_end >= l_src->offset)
- mni_cp(l_src, right, l_end - l_src->offset + 1);
- }
-
- mni_cp(r_src, right, r_end + 1);
- } else { /* Store is targeting r_src */
- printk("%s %d\n", __func__, __LINE__);
- if (split <= l_end) { /* Store will end up in right */
- printk("%s %d\n", __func__, __LINE__);
- mni_cp(l_src, left, split + 1);
- mas_wr_split_no_null(l_src, left, right,
- l_end + new_end + 1, part);
-
- mni_cp(l_src, right, l_end - l_src->offset + 1);
- right->min = left->max + 1;
- mni_cp(r_src, right, mas_off);
- mni_insert_part(part, right);
- //printk("%d\n", __LINE__);
- r_src->offset+= part->skip;
- if (r_src->offset <= r_end)
- mni_cp(r_src, right, r_end - r_src->offset + 1);
-
- } else { /* Store will end up in left */
- unsigned char r_split;
-
- printk("%s %d\n", __func__, __LINE__);
- r_split = split - l_end - 1;
- mni_cp(l_src, left, l_end + 1);
- if (mas_off <= r_split) {
- if (mas_off)
- mni_cp(r_src, left, mas_off);
- part->dst_max_off = split;
- mni_insert_part(part, left);
- //printk("%d\n", __LINE__);
- r_src->offset+= part->skip;
- if (r_src->offset < r_split)
- mni_cp(r_src, left,
- r_split - r_src->offset);
-
- mas_wr_split_no_null(r_src, left, right,
- l_end + new_end + 1,
- part);
-
- if (part->unfinished)
- mni_insert_part(part, right);
-
- right->min = left->max + 1;
- } else {
- mni_cp(r_src, left, r_split + 1);
- mas_wr_split_no_null(r_src, left, right,
- l_end + new_end + 1,
- part);
- right->min = left->max + 1;
- if (mas_off > r_src->offset)
- mni_cp(r_src, right,
- mas_off - r_src->offset);
- mni_insert_part(part, right);
- //printk("%d\n", __LINE__);
- r_src->offset+= part->skip;
- }
-
- if (r_src->offset <= r_end)
- mni_cp(r_src, right, r_end - r_src->offset + 1);
- }
- }
-}
-#endif
/*
* Assemble all the states into the dst within those states
unsigned char space; /* The space left in the current destination node */
unsigned char split; /* Proposed split of data */
unsigned char insert; /* Insert location of destination */
+ unsigned char insert_end;/* Insert end location of destination */
unsigned char new_end; /* Total data */
unsigned char src_ins_end; /* Offset into source data where the write ends */
unsigned char len; /* Number of ma_node_states in the states array */
mni_finalise(dst);
}
+static int state_setup(struct ma_node_state *state, struct ma_node_info *src,
+ struct ma_node_info *dst, struct ma_node_part *part,
+ struct split_data *sd, int node_off)
+{
+ unsigned char copied;
+ unsigned char inc_off;
+
+ /* Configure one state */
+ state = &sd->states[sd->len];
+ if (sd->offset >= sd->insert && sd->offset <= sd->insert_end) {
+ copied = min(part->size - part->pos, sd->space);
+ state->part = part;
+ printk("insert part at %u first entry is %p\n", sd->offset, part->slots[0]);
+ mns_mni_init(state, dst, part->pos , copied);
+ state->use_part = true;
+ part->pos += copied;
+ inc_off = sd->src_ins_end + 1;
+ } else {
+ state->info = src;
+ if (sd->offset < sd->insert_end) {
+ /*
+ * First part of node, may split across node
+ * boundaries though
+ */
+ copied = min(sd->space, sd->insert - sd->offset);
+ } else {
+ copied = min(sd->space, (src->end - node_off + 1));
+ }
+ BUG_ON(copied == 0);
+ mns_mni_init(state, dst, node_off, copied);
+ inc_off = copied;
+ }
+
+ sd->offset += copied;
+ sd->space -= copied;
+ printk("offset %u split %u\n", sd->offset, sd->split);
+ return inc_off;
+}
+
/*
* mt_wr_split_data() - Split the combined data into ma_node_state parts.
*
struct ma_node_part *part, struct split_data *sd)
{
unsigned char insert_end;
- unsigned char node_off, part_off;
+ unsigned char node_off;
struct ma_node_info *to;
struct ma_node_state *state;
printk("%s\n", __func__);
/* Offset into the destination data where the insert ends */
- insert_end = sd->insert + part->size - 1;
+ sd->insert_end = sd->insert + part->size - 1;
to = left;
node_off = 0; /* src */
- part_off = 0;
do {
- unsigned char copied = 0;
-
+ /* Configure one state */
state = &sd->states[sd->len];
- if (sd->offset >= sd->insert && sd->offset <= insert_end) {
- copied = min(part->size - part_off, sd->space);
- state->part = part;
- printk("insert part at %u first entry is %p\n", sd->offset, part->slots[0]);
- mns_mni_init(state, to, part_off, copied);
- state->use_part = true;
- part_off += copied;
- node_off = sd->src_ins_end + 1;
- } else {
- state->info = src;
- if (sd->offset < insert_end) {
- /*
- * First part of node, may split across node
- * boundaries though
- */
- copied = min(sd->space, sd->insert - sd->offset);
- } else {
- copied = min(sd->space, (src->end - node_off + 1));
- }
- BUG_ON(copied == 0);
- mns_mni_init(state, to, node_off, copied);
- node_off += copied;
- }
+ node_off += state_setup(state, src, to, part, sd, node_off);
- sd->offset += copied;
- sd->space -= copied;
+ /*
+ * Potentially remove one entry from the state if it's NULL and
+ * the destination is switching
+ */
if ((to == left) && (sd->offset >= sd->split)) {
if (ma_is_leaf(src->type) &&
mns_ends_in_null(state)) {
sd->offset--;
sd->space++;
if (state->use_part) {
- part_off--;
+ part->pos--;
} else {
node_off--;
}
return true;
}
-#if 1
-
+/*
+ * mas_wr_rebalance_two() - rebalance data into two nodes, expects data to
+ * be decreasing (vs splitting pushing data to a neighbour).
+ */
static void mas_wr_rebalance_two(struct ma_wr_state *wr_mas,
struct ma_node_info *left,
struct ma_node_info *right,
bool left_store)
{
if (!left_store) {
- printk("store right->n");
+ char len;
+
+ /*
+ * Store to the right implies left is going to donate data to
+ * the right node
+ */
+ printk("store right\n");
left->min = src2->min;
right->max = src->max;
sd->offset = src2->end + 1;
- sd->space = sd->split - src2->end;
+ sd->split++;
sd->states[sd->len].info = src2;
/* The first state to copy is the left node */
- mns_mni_init(&sd->states[sd->len], left, 0, src2->end + 1);
+ printk("cp to left %u-%u\n", 0, src2->end + 1);
+ mns_mni_init(&sd->states[sd->len], left, 0, sd->split);
sd->len++;
+ /* Copy the remainder of the left to the start of the right */
+ len = src2->end + 1 - sd->split;
+ sd->states[sd->len].info = src2;
+ mns_mni_init(&sd->states[sd->len], right, sd->split, len);
+ sd->space = mt_slots[right->type];
+ sd->split = 255;
} else {
printk("store left\n");
sd->space = sd->split;
left->min = src2->min;
left->max = src->max;
sd->offset = src2->end + 1;
- sd->space = sd->split - src2->end;
+ sd->space = sd->new_end + 1;
sd->states[sd->len].info = src2;
/* The first state to copy is the left node */
mns_mni_init(&sd->states[sd->len], left, 0, src2->end + 1);
}
printk("REDUCE %p %p\n", src.node, src2.node);
+ sd.split = 255;
mas_wr_rebalance_reduce(wr_mas, &left, &src, &src2, &part, &sd, left_store);
/* Must go again */
left.node->parent = mas_mn(mas)->parent;
mas->node = left.enode;
mas->depth = mas_mt_height(mas) - 1;
+ if (mas->depth == 1)
+
mas_set_height(mas);
goto new_root;
}
mtree_range_walk(mas);
mt_dump(mas->tree, mt_dump_dec);
mt_validate(mas->tree);
- return;
-
- /*
- * allocate left
- * set alloc in left
- * figure out src2
- * rebalance leaves {
- * allocate right, if needed
- * set right alloc to left value
- * set up split data
- * split the data
- * set up part
- * }
- *
- * while ( parent is insufficient including overwrite, extra part) {
- * allocate left
- * figure out src2
- * rebalance src and src 2 {
- * allocate right, if needed
- * set right alloc to left value
- * set up split data
- * split the data and insert part
- * set up next part
- * }
- *
- * allocate new parent
- * converge
- * copy to insert
- * insert part
- * skip entry (or 2)
- * copy to end
- * put in tree
- *
- */
-
- while (height--) {
- printk("height %d\n", height);
- mas_wr_ascend_init(&tmp_mas, &parent);
- max = mt_slots[src.type] - 1;
- if (ma_is_leaf(src.type))
- max--;
-
- src.end = mas->end;
- if (parent.insert_off != mas->end) {
- /* Right sibling exists, rebalance against right */
- tmp_mas.offset = parent.insert_off + 1;
- mas_descend(&tmp_mas);
- mni_mas_init(&src2, &tmp_mas);
- mni_set_end(&src2);
- left_store = true;
- sd.insert = mas->offset;
- } else {
- /* Rebalance against left sibling */
- tmp_mas.offset--;
- mas_descend(&tmp_mas);
- mni_mas_init(&src2, &tmp_mas);
- mni_node_init(&right, mas_pop_node(mas), wr_mas->type);
- parent.insert_off--;
- sd.insert = mas->offset + src2.end + 1;
- }
-
- sd.new_end += src2.end + 1;
- mni_node_init(&left, mas_pop_node(mas), wr_mas->type);
- if (sd.new_end > 2 * mt_min_slots[src.type]) {
- printk("Rebalance\n");
- mni_node_init(&right, mas_pop_node(mas), wr_mas->type);
- sd.split = mas_wr_rebalance_calc(sd.new_end,
- src2.type);
- /*
- * Rebalance between nodes is possible, so the
- * operation stops early.
- */
-
- /* Taken from mas_wr_try_rebalance */
- if (left_store) {
- /* Left pushes data right. */
- sd.insert = mas->offset;
- sd.space = sd.split;
- sd.offset = 0;
- } else {
- /* Right pushes data left */
- sd.insert = mas->offset + src2.end + 1;
- sd.offset = src2.end + 1;
- sd.space = sd.split - src2.end;
- sd.states[sd.len].info = &src2;
- mns_mni_init(&sd.states[sd.len], &left, 0, src2.end + 1);
- sd.len++;
- }
-
- /*
- * There are two splits of src, at insert and insert_end.
- * There can also be a split between nodes that may happen at these
- * boundaries, or elsewhere.
- */
- mt_wr_split_data(&src, &left, &right, &part, &sd);
- if (left_store) {
- sd.states[sd.len].info = &src2;
- mns_mni_init(&sd.states[sd.len], &right, 0, src2.end + 1);
- sd.len++;
- }
-
- mns_assemble(sd.states, sd.len);
- mni_finalise(&left);
- mni_finalise(&right);
- mni_node_part_init(&part, &left, &right);
- part.skip = 2;
- mas_ascend(mas);
- mas->end = parent.end;
- mas->offset = parent.insert_off;
- mas_wr_converged(&parent, &new_parent, &part, mas, &sd);
- src.enode = parent.enode;
- mas->node = new_parent.enode;
- /* FIXME: make another function */
- /* We can stop rebalancing here */
- goto replace_node;
- } else {
- /*
- * Absorb all the data from two nodes, which may need
- * more rebalancing
- */
- printk("Absorb src %p src2 %p\n", src.node, src2.node);
- sd.split = sd.new_end + 2; /* No split */
-
- if (!left_store) {
- sd.states[sd.len].info = &src2;
- mns_mni_init(&sd.states[sd.len], &left, 0, src2.end + 1);
- sd.len++;
- }
- mt_wr_split_data(&src, &left, NULL, &part, &sd);
-
- if (left_store) {
- sd.states[sd.len].info = &src2;
- mns_mni_init(&sd.states[sd.len], &left, 0, src2.end + 1);
- sd.len++;
- }
-
- mns_assemble(sd.states, sd.len);
- mni_finalise(&left);
- if (ma_is_root(parent.node) && parent.end == 1) {
- /* New root */
- }
- if (parent.end > mt_min_slots[parent.type]) {
- mni_node_part_init(&part, &left, NULL);
- break;
- }
- }
- }
-
- mas_ascend(mas);
- mas->end = parent.end - 1;
- mas->offset = parent.insert_off;
- mas_wr_converged(&parent, &new_parent, &part, mas, &sd);
- src.enode = parent.enode;
- mas->node = new_parent.enode;
-replace_node:
- mas_wmb_replace(mas, src.enode);
- mtree_range_walk(mas);
- mt_dump(mas->tree, mt_dump_dec);
- mt_validate(mas->tree);
-}
-#endif
-
-#if 0
-/*
- * There is insufficient data in the node after a store.
- * This rebalance will succeed, not like the split variant that will attempt
- * to rebalance.
- *
- * Rebalance leaves
- * Continue upwards until parent is sufficient, or root is reached. If root
- * has a single child, replace root with new root.
- */
-static void mas_wr_rebalance(struct ma_wr_state *wr_mas)
-{
- struct ma_state *mas = wr_mas->mas;
- struct ma_node_state src, parent, l_src, r_src;
- struct ma_node_info src_info;
- struct ma_node_state left, right;
- struct ma_node_part part;
- unsigned char total, split, height;
- unsigned char insert;
-
- trace_ma_op(__func__, mas);
- mt_dump(mas->tree, mt_dump_dec);
- height = mas_mt_height(mas);
- mns_mas_init(&src, &src_info, mas);
- mns_node_part_leaf_init(&part, wr_mas, &src);
- /* Total will lack sibling data until the sibling is known */
- printk("end %p %u\n", mas->node, mas->end);
- total = mas->end + part.size - part.skip - 1;
- printk("%p will have %u in the end\n", mas->node, total);
- printk("Skip %u\n", part.skip);
- // Skipping is causing a copy beyond the end of the src.
-
- printk("Rebalance %p %lu-%lu", mas->node, mas->index, mas->last);
-
- insert = mas->offset;
- printk("Write to node at %u\n", insert);
- while (mas->depth) {
- bool l_store;
-
- mas_wr_ascend_init(mas, &parent);
- printk("Ascend to parent %p\n", parent.node);
- printk("offset of child is %u\n", mas->offset);
- mas->depth--;
- parent.insert = mas->offset;
- printk("parent insert is %u\n", parent.insert);
-
- if (parent.insert < parent.end) {
- /* Pull data from r_src */
- printk("Pull from right\n");
- mns_pmns_init(&r_src, &parent, mas->offset + 1, mas->tree);
- mns_set_end(&r_src);
- printk("right is %p %lu-%lu\n", r_src.node, r_src.min, r_src.max);
- l_src = src;
- l_src.insert = insert;
- total += r_src.end;
- l_store = true;
- } else {
- /* Pull data from l_src */
- printk("Pull from left\n");
- mns_pmns_init(&l_src, &parent, mas->offset - 1, mas->tree);
- printk("left is %p\n", l_src.node);
- r_src = src;
- r_src.insert = insert;
- mns_set_end(&l_src);
- total += l_src.end;
- l_store = false;
- parent.insert--;
- }
-
- printk("\tNew total will be %u\n", total);
- mni_node_init(&left, mas_pop_node(mas), l_src.type);
- /*
- * Two possibilities:
- * 1. keep two nodes if possible and limit ripple
- * 2. make one node if possible and limit memory use
- *
- * Case 1:
- * Left takes data from right.
- * Fill left up to split from l_src and part - Func_1
- * Fill left up from l_src remainder - Func_2
- * Fill left up to split from right. - Func_2
- * fill right with remainder of right. - Func_2
- *
- * Right takes data from left
- * Copy left to new left up to split - Func_2
- * Fill right with remainder of left - Func_2
- * Fill right from old right or part - Func_1
- */
- if ((total > 2 * mt_min_slots[l_src.type] ) ||
- ma_is_root(parent.node)) {
- struct ma_node_state new_parent;
-
- printk("Rebalance\n");
- /*
- * Rebalance between nodes is possible, so the
- * operation stops early.
- */
-
- mni_node_init(&right, mas_pop_node(mas), r_src.type);
- printk("new right will be %p\n", right.node);
- split = mas_wr_rebalance_calc(total, l_src.type);
- printk("split is %u\n", split);
- left.min = l_src.min;
- mas_wr_rebalance_nodes(&l_src, &r_src, &left, &right,
- l_store, split, &part,
- insert, total);
-
- mni_finalise(&left);
- mni_finalise(&right);
- mni_node_part_init(&part, &left, &right);
- part.skip = 2;
- mas_wr_converged(&parent, &new_parent, &part, mas);
- src.enode = parent.enode;
- mas->node = new_parent.enode;
- mas->depth = height;
- printk("Height is %u\n", mas->depth);
- break;
- }
-
- printk("consume\n");
- /* Reduce two nodes into one */
- if (l_store) {
- if (l_src.insert)
- mni_cp(&l_src, &left, l_src.insert);
- mni_insert_part(&part, &left);
- l_src.offset += part.skip;
- if (l_src.offset <= l_src.end)
- mni_cp(&l_src, &left,
- l_src.end - l_src.offset + 1);
- mni_cp(&r_src, &left, r_src.end);
-
- } else {
- mni_cp(&l_src, &left, l_src.end);
- if (r_src.insert)
- mni_cp(&r_src, &left, r_src.insert);
- mni_insert_part(&part, &left);
- r_src.offset += part.skip;
- if (r_src.offset <= r_src.end)
- mni_cp(&r_src, &left,
- r_src.end - r_src.offset + 1);
- }
- left.node->parent = l_src.node->parent;
- mni_finalise(&left);
- if (mte_is_root(parent.enode)) {
- /* Height reduction */
- if (mas->depth)
- mas->depth = --height;
- else
- mas->depth = height;
-
- mas_set_height(mas);
- break;
- }
- }
-
-
- mas_wmb_replace(mas, parent.enode);
- mtree_range_walk(mas);
- mt_dump(mas->tree, mt_dump_dec);
}
-#endif
/*
* There is not enough room to contain the store in one node.