コード例 #1
0
ファイル: tree.c プロジェクト: FromPointer/nessDB
static void _root_split(struct tree *t,
                        struct node *new_root,
                        struct node *old_root)
{
	struct node *a;
	struct node *b;
	struct msg *split_key = NULL;

	__DEBUG("root split begin, old NID %"PRIu64" , height %d"
	        , old_root->nid
	        , old_root->height);

	if (old_root->height > 0 || old_root->n_children > 2)
		_node_split(t, old_root, &a, &b, &split_key);
	else
		_leaf_and_lmb_split(t, old_root, &a, &b, &split_key);

	/* swap two roots */
	_root_swap(new_root, old_root);

	msgcpy(&new_root->pivots[0], split_key);
	new_root->parts[0].child_nid = a->nid;
	new_root->parts[1].child_nid = b->nid;
	msgfree(split_key);

	cache_unpin(t->cf, b->cpair, make_cpair_attr(b));

	node_set_dirty(old_root);
	node_set_dirty(new_root);

	t->hdr->height++;
	status_increment(&t->e->status->tree_root_new_nums);
	__DEBUG("root split end, old NID %"PRIu64, old_root->nid);
}
コード例 #2
0
ファイル: arrange.c プロジェクト: thejan2009/sway
void arrange_container(struct sway_container *container) {
	if (config->reloading) {
		return;
	}
	if (container->view) {
		view_autoconfigure(container->view);
		node_set_dirty(&container->node);
		return;
	}
	struct wlr_box box;
	container_get_box(container, &box);
	arrange_children(container->children, container->layout, &box);
	node_set_dirty(&container->node);
}
コード例 #3
0
ファイル: leaf.c プロジェクト: BohuTANG/nessDB
/*
 * EFFECT:
 *	- split leaf&lmb into two leaves:a & b
 *	  a&b are both the half of the lmb
 *
 * PROCESS:
 *	- leaf:
 *		+-----------------------------------+
 *		|  0  |  1  |  2  |  3  |  4  |  5  |
 *		+-----------------------------------+
 *
 *	- split:
 *				   root
 *				 +--------+
 *				 |   2    |
 *				 +--------+
 *              /          \
 *	+-----------------+	 +------------------+
 *	    	|  0  |  1  |  2  |	 |  3  |  4  |  5   |
 *	    	+-----------------+	 +------------------+
 *	    	      nodea			nodeb
 *
 * ENTER:
 *	- leaf is already locked (L_WRITE)
 * EXITS:
 *	- a is locked
 *	- b is locked
 */
void leaf_split(void *tree,
                struct node *node,
                struct node **a,
                struct node **b,
                struct msg **split_key)
{
	struct partition *pa;
	struct partition *pb;
	struct node *leafa;
	struct node *leafb;
	struct lmb *mb;
	struct lmb *mba;
	struct lmb *mbb;
	struct msg *sp_key = NULL;
	struct buftree *t = (struct buftree*)tree;

	leafa = node;
	pa = &leafa->parts[0];

	/* split lmb of leaf to mba & mbb */
	mb = pa->msgbuf;
	lmb_split(mb, &mba, &mbb, &sp_key);
	lmb_free(mb);

	/* reset leafa buffer */
	pa->msgbuf = mba;

	/* new leafb */
	NID nid = hdr_next_nid(t->hdr);
	leaf_new(t->hdr,
	         nid,
	         0,
	         1,
	         &leafb);
	leaf_msgbuf_init(leafb);

	cache_put_and_pin(t->cf, nid, leafb);

	pb = &leafb->parts[0];
	lmb_free(pb->msgbuf);
	pb->msgbuf = mbb;

	/* set dirty */
	node_set_dirty(leafa);
	node_set_dirty(leafb);

	*a = leafa;
	*b = leafb;
	*split_key = sp_key;
}
コード例 #4
0
ファイル: flusher.c プロジェクト: yqingp/testness
/*
 * EFFECT:
 *	- flush in background thread
 * ENTER:
 *	- parent is already locked
 * EXIT:
 *	- nodes are all unlocked
 */
void tree_flush_node_on_background(struct tree *t, struct node *parent)
{
    LOG;
	int childnum;
	enum reactivity re;
	struct node *child;
	struct partition *part;

	nassert(parent->height > 0);
	childnum = node_find_heaviest_idx(parent);
	part = &parent->parts[childnum];

	/* pin the child */
	if (cache_get_and_pin(t->cf, part->child_nid, (void**)&child, L_WRITE) != NESS_OK) {
		__ERROR("cache get node error, nid [%" PRIu64 "]", part->child_nid);
		return;
	}

	re = get_reactivity(t, child);
	if (re == STABLE) {
		/* detach buffer from parent */
		struct nmb *buf = part->ptr.u.nonleaf->buffer;
		node_set_dirty(parent);
		part->ptr.u.nonleaf->buffer = nmb_new(t->e);

		/* flush it in background thread */
		_place_node_and_buffer_on_background(t, child, buf);
		cache_unpin(t->cf, parent->cpair, make_cpair_attr(parent));
	} else {
		/* the child is reactive, we deal it in main thread */
		_child_maybe_reactivity(t, parent, child);
	}
}
コード例 #5
0
ファイル: flusher.c プロジェクト: yqingp/testness
/*
 * EFFECT:
 *	- do flush in a background thread
 * PROCESS:
 *	- if buf is NULL, we will do _flush_some_child
 *	- if buf is NOT NULL, we will do _flush_buffer_to_child
 * ENTER:
 *	- fe->node is already locked
 * EXIT:
 *	- nodes are unlocked
 */
static void _flush_node_func(void *fe)
{
	enum reactivity re;
	struct flusher_extra *extra = (struct flusher_extra*)fe;
	struct tree *t = extra->tree;
	struct node *n = extra->node;
	struct nmb *buf = extra->buffer;

	node_set_dirty(n);
	if (buf) {
		_flush_buffer_to_child(t, n, buf);
		nmb_free(buf);

		/* check the child node */
		re = get_reactivity(t, n);
		if (re == FLUSHBLE)
			_flush_some_child(t, n);
		else
			cache_unpin(t->cf, n->cpair, make_cpair_attr(n));
	} else {
		/* we want flush some buffer from n */
		_flush_some_child(t, n);
	}

	xfree(extra);
}
コード例 #6
0
ファイル: leaf.c プロジェクト: koolhazz/nessDB
/*
 * apply a msg to leaf basement
 * neither the leaf type is LE_CLEAN or LE_MVCC
 * basement will always keep multi-snapshot
 * the difference between LE_CLEAN and LE_MVCC is gc affects.
 *
 */
int leaf_apply_msg(struct node *leaf, struct bt_cmd *cmd)
{
	write_lock(&leaf->u.l.le->rwlock);
	switch (cmd->type & 0xff) {
	case MSG_INSERT:
	case MSG_DELETE:
	case MSG_UPDATE: {
			/* TODO: do msg update, node->node_op->update */
		}
	case MSG_COMMIT:
	case MSG_ABORT:
	default:
		basement_put(leaf->u.l.le->bsm,
		             cmd->msn,
		             cmd->type,
		             cmd->key,
		             cmd->val,
		             &cmd->xidpair);
	}
	leaf->msn = cmd->msn > leaf->msn ? cmd->msn : leaf->msn;
	node_set_dirty(leaf);
	write_unlock(&leaf->u.l.le->rwlock);

	return NESS_OK;
}
コード例 #7
0
ファイル: tree.c プロジェクト: yqingp/testness
/*
 * EFFECT:
 *	- put cmd to leaf
 * ENTER:
 *	- leaf is already locked(L_WRITE)
 * EXITS:
 *	- leaf is locked
 */
void leaf_put_cmd(struct node *leaf, struct bt_cmd *cmd)
{
    LOG;
	leaf_apply_msg(leaf, cmd);
	leaf->msn = cmd->msn > leaf->msn ? cmd->msn : leaf->msn;
	node_set_dirty(leaf);
}
コード例 #8
0
ファイル: tree.c プロジェクト: FromPointer/nessDB
/*
 *
 * PROCESS:
 *	- if the layout as follows(3 pivots, 4 partitions):
 *
 *			+--------+--------+--------+
 *	 		|   15   |   17   |   19   | +∞
 *	 		+--------+--------+--------+\
 *	 		  pidx0    pidx1    pidx2    pidx3
 *
 *
 *	- so if spk is 16, pidx = 1, after added(4 pivtos, 5 partitions):
 *
 *			+--------+--------+--------+--------+
 *	 		|   15   |  [16]  |   17   |   19   | +∞
 *	 		+--------+--------+--------+--------+\
 *	 		  pidx0   [pidx1]   pidx2    pidx3     pidx4
 *
 *
 * ENTER:
 *	- parent is already locked(L_WRITE)
 *	- node a is already locked(L_WRITE)
 *	- node b is already locked(L_WRITE)
 */
static void _add_pivot_to_parent(struct tree *t,
                                 struct node *parent,
                                 int child_num,
                                 struct node *a,
                                 struct node *b,
                                 struct msg *spk)
{
	int i;
	int pidx;
	struct child_pointer *cptr;

	pidx = child_num;
	parent->pivots = xrealloc(parent->pivots, parent->n_children * PIVOT_SIZE);
	parent->parts = xrealloc(parent->parts, (parent->n_children + 1) * PART_SIZE);

	/* slide pivots */
	for (i = (parent->n_children - 1); i > pidx; i--)
		parent->pivots[i] = parent->pivots[i - 1];

	/* slide parts */
	for (i = parent->n_children; i > pidx; i--)
		parent->parts[i] = parent->parts[i - 1];

	/* new part */
	msgcpy(&parent->pivots[pidx], spk);
	parent->parts[pidx].child_nid = a->nid;
	cptr = &parent->parts[pidx].ptr;
	cptr->u.nonleaf = create_nonleaf(t->e);

	parent->parts[pidx + 1].child_nid = b->nid;
	parent->n_children += 1;
	node_set_dirty(parent);

	status_increment(&t->e->status->tree_add_pivots_nums);
}
コード例 #9
0
ファイル: leaf.c プロジェクト: BohuTANG/nessDB
/*
 * apply a msg to leaf msgbuf
 * neither the leaf type is LE_CLEAN or LE_MVCC
 * msgbuf will always keep multi-snapshot
 * the difference between LE_CLEAN and LE_MVCC is gc affects.
 *
 */
int leaf_put(struct node *leaf, struct bt_cmd *cmd)
{
	int ret = NESS_ERR;
	struct lmb *buffer = (struct lmb*)leaf->parts[0].msgbuf;

	switch (cmd->type & 0xff) {
	case MSG_INSERT:
		lmb_put(buffer,
		        cmd->msn,
		        cmd->type,
		        cmd->key,
		        cmd->val,
		        &cmd->xidpair);
		return NESS_OK;
		break;
	case MSG_DELETE:
		break;
	case MSG_UPDATE:
		break;
	case MSG_COMMIT:
		break;
	case MSG_ABORT:
		break;
	default:
		break;
	}

	leaf->msn = cmd->msn > leaf->msn ? cmd->msn : leaf->msn;
	node_set_dirty(leaf);

	return ret;
}
コード例 #10
0
ファイル: leaf.c プロジェクト: BohuTANG/nessDB
void leaf_new(struct hdr *hdr,
              NID nid,
              uint32_t height,
              uint32_t children,
              struct node **n)
{
	struct node *node;

	nassert(height == 0);
	nassert(children == 1);
	node = xcalloc(1, sizeof(*node));
	nassert(node);
	node->nid = nid;
	node->height = height;
	ness_mutex_init(&node->attr.mtx);
	ness_mutex_init(&node->mtx);
	ness_rwlock_init(&node->rwlock, &node->mtx);

	node->n_children = children;
	node->layout_version = hdr->layout_version;

	if (children > 0) {
		node->pivots = xcalloc(children - 1, PIVOT_SIZE);
		node->parts = xcalloc(children, PART_SIZE);
	}

	node->opts = hdr->opts;
	node->i = &leaf_operations;
	node_set_dirty(node);

	*n = node;
}
コード例 #11
0
ファイル: arrange.c プロジェクト: thejan2009/sway
void arrange_workspace(struct sway_workspace *workspace) {
	if (config->reloading) {
		return;
	}
	if (!workspace->output) {
		// Happens when there are no outputs connected
		return;
	}
	struct sway_output *output = workspace->output;
	struct wlr_box *area = &output->usable_area;
	sway_log(SWAY_DEBUG, "Usable area for ws: %dx%d@%d,%d",
			area->width, area->height, area->x, area->y);
	workspace_remove_gaps(workspace);

	bool first_arrange = workspace->width == 0 && workspace->height == 0;
	double prev_x = workspace->x;
	double prev_y = workspace->y;
	workspace->width = area->width;
	workspace->height = area->height;
	workspace->x = output->wlr_output->lx + area->x;
	workspace->y = output->wlr_output->ly + area->y;

	// Adjust any floating containers
	double diff_x = workspace->x - prev_x;
	double diff_y = workspace->y - prev_y;
	if (!first_arrange && (diff_x != 0 || diff_y != 0)) {
		for (int i = 0; i < workspace->floating->length; ++i) {
			struct sway_container *floater = workspace->floating->items[i];
			container_floating_translate(floater, diff_x, diff_y);
			double center_x = floater->x + floater->width / 2;
			double center_y = floater->y + floater->height / 2;
			struct wlr_box workspace_box;
			workspace_get_box(workspace, &workspace_box);
			if (!wlr_box_contains_point(&workspace_box, center_x, center_y)) {
				container_floating_move_to_center(floater);
			}
		}
	}

	workspace_add_gaps(workspace);
	node_set_dirty(&workspace->node);
	sway_log(SWAY_DEBUG, "Arranging workspace '%s' at %f, %f", workspace->name,
			workspace->x, workspace->y);
	if (workspace->fullscreen) {
		struct sway_container *fs = workspace->fullscreen;
		fs->x = output->lx;
		fs->y = output->ly;
		fs->width = output->width;
		fs->height = output->height;
		arrange_container(fs);
	} else {
		struct wlr_box box;
		workspace_get_box(workspace, &box);
		arrange_children(workspace->tiling, workspace->layout, &box);
		arrange_floating(workspace->floating);
	}
}
コード例 #12
0
ファイル: node.c プロジェクト: Numetric/nessDB
/*
 * EFFECT:
 *	- alloc node header
 */
struct node *node_alloc_empty(NID nid, int height) {
	struct node *node;

	node = xcalloc(1, sizeof(*node));
	node->nid = nid;
	node->height = height;
	node->node_op = &nop;

	mutex_init(&node->attr.mtx);
	node_set_dirty(node);

	return node;
}
コード例 #13
0
ファイル: tree.c プロジェクト: FromPointer/nessDB
/*
 * EFFECT:
 *	- put cmd to nonleaf
 * ENTER:
 *	- node is already locked (L_READ)
 * EXITS:
 *	- node is locked
 */
void nonleaf_put_cmd(struct node *node, struct bt_cmd *cmd)
{
	uint32_t pidx;
	struct nmb *buffer;

	pidx = node_partition_idx(node, cmd->key);
	buffer = node->parts[pidx].ptr.u.nonleaf->buffer;

	nassert(buffer);
	nmb_put(buffer,
	        cmd-> msn,
	        cmd->type,
	        cmd->key,
	        cmd->val,
	        &cmd->xidpair);
	node->msn = cmd->msn > node->msn ? cmd->msn : node->msn;
	node_set_dirty(node);
}
コード例 #14
0
ファイル: tree.c プロジェクト: FromPointer/nessDB
/*
 * 	+-----------------------------------------------+
 * 	| 	5 	| 	7 	| 	9 	|
 * 	+-----------------------------------------------+
 * 				|
 * 			+---------------+
 * 			|  60 | 61 | 62 |
 * 			+---------------+
 *
 * 	+---------------------------------------------------------------+
 * 	|  	5 	| 	60	 |	7 	| 	9 	|
 * 	+---------------------------------------------------------------+
 * 				|		|
 * 			    +--------+	    +---------+
 * 			    |   60   |	    | 61 | 62 |
 * 			    +--------+	    +---------+
 *
 *
 * ENTER:
 *	- node is already locked(L_WRITE)
 * EXITS:
 *	- a is locked(L_WRITE)
 *	- b is locked(L_WRITE)
 */
static void _node_split(struct tree *t,
                        struct node *node,
                        struct node **a,
                        struct node **b,
                        struct msg **split_key)
{
	int i;
	int pivots_old;
	int pivots_in_a;
	int pivots_in_b;
	struct node *nodea;
	struct node *nodeb;
	struct msg *spk;

	__DEBUG("nonleaf split begin, NID %"PRIu64""
	        ", nodesz %d"
	        ", nodec %d"
	        ", children %d"
	        , node->nid
	        , node_size(node)
	        , node_count(node)
	        , node->n_children);

	nodea = node;
	pivots_old = node->n_children - 1;
	nassert(pivots_old > 2);

	pivots_in_a = pivots_old / 2;
	pivots_in_b = pivots_old - pivots_in_a;

	/* node a */
	nodea->n_children = pivots_in_a + 1;

	/* node b */
	NID nid = hdr_next_nid(t->hdr);
	node_create_light(nid, node->height > 0 ? 1 : 0, pivots_in_b + 1, t->hdr->version, t->e, &nodeb);
	cache_put_and_pin(t->cf, nid, nodeb);

	for (i = 0; i < (pivots_in_b); i++)
		nodeb->pivots[i] = nodea->pivots[pivots_in_a + i];

	for (i = 0; i < (pivots_in_b + 1); i++)
		nodeb->parts[i] = nodea->parts[pivots_in_a + i];

	/* the rightest partition of nodea */
	struct child_pointer *ptr = &nodea->parts[pivots_in_a].ptr;

	if (nodea->height > 0)
		ptr->u.nonleaf = create_nonleaf(t->e);
	else
		ptr->u.leaf = create_leaf(t->e);


	/* split key */
	spk = msgdup(&node->pivots[pivots_in_a - 1]);

	node_set_dirty(nodea);
	node_set_dirty(nodeb);

	__DEBUG("nonleaf split end, nodea NID %"PRIu64""
	        ", nodesz %d"
	        ", nodec %d"
	        ", children %d"
	        , nodea->nid
	        , node_size(nodea)
	        , node_count(nodea)
	        , nodea->n_children);

	__DEBUG("nonleaf split end, nodeb NID %"PRIu64""
	        ", nodesz %d"
	        ", nodec %d"
	        ", children %d"
	        , nodeb->nid
	        , node_size(nodeb)
	        , node_count(nodeb)
	        , nodeb->n_children);

	*a = nodea;
	*b = nodeb;
	*split_key = spk;
}
コード例 #15
0
ファイル: tree.c プロジェクト: FromPointer/nessDB
struct tree *tree_open(const char *dbname,
                       struct env *e,
                       struct tree_callback *tcb) {
	int fd;
	int flag;
	mode_t mode;
	int is_create = 0;
	struct tree *t;
	struct node *root;
	struct cache_file *cf;

	t = xcalloc(1, sizeof(*t));
	t->e = e;

	mode = S_IRWXU | S_IRWXG | S_IRWXO;
	flag = O_RDWR | O_BINARY;
	if (e->use_directio)
		fd = ness_os_open_direct(dbname, flag, mode);
	else
		fd = ness_os_open(dbname, flag, mode);

	if (fd == -1) {
		if (e->use_directio)
			fd = ness_os_open(dbname, flag | O_CREAT, mode);
		else
			fd = ness_os_open_direct(dbname, flag | O_CREAT, mode);
		if (fd == -1)
			goto ERR;
		is_create = 1;
	}

	t->fd = fd;
	t->hdr = hdr_new(e);

	/* tree header */
	if (!is_create) {
		tcb->fetch_hdr_cb(fd, t->hdr);
	}

	/* create cache file */
	cf = cache_file_create(e->cache, t->fd, t->hdr, tcb);
	t->cf = cf;

	/* tree root node */
	if (is_create) {
		NID nid = hdr_next_nid(t->hdr);
		node_create(nid, 0, 1, t->hdr->version, t->e, &root);
		cache_put_and_pin(cf, nid, root);
		root->isroot = 1;
		node_set_dirty(root);

		cache_unpin(cf, root->cpair, make_cpair_attr(root));
		t->hdr->root_nid = root->nid;
		__DEBUG("create new root, NID %"PRIu64, root->nid);
	} else {
		/* get the root node */
		if (cache_get_and_pin(cf, t->hdr->root_nid, (void**)&root, L_READ) != NESS_OK)
			__PANIC("get root from cache error [%" PRIu64 "]", t->hdr->root_nid);

		root->isroot = 1;
		cache_unpin(cf, root->cpair, make_cpair_attr(root));
		__DEBUG("fetch root, NID %"PRIu64, root->nid);
	}

	return t;

ERR:
	xfree(t);
	return NESS_ERR;
}
コード例 #16
0
ファイル: flusher.c プロジェクト: yqingp/testness
void _flush_buffer_to_child(struct tree *t, struct node *child, struct nmb *buf)
{
	struct mb_iter iter;

	mb_iter_init(&iter, buf->pma);
	while (mb_iter_next(&iter)) {
		/* TODO(BohuTANG): check msn */
		struct nmb_values nvalues;

		nmb_get_values(&iter, &nvalues);

		struct bt_cmd cmd = {
			.msn = nvalues.msn,
			.type = nvalues.type,
			.key = &nvalues.key,
			.val = &nvalues.val,
			.xidpair = nvalues.xidpair
		};
		node_put_cmd(t, child, &cmd);
	}
}

void _flush_some_child(struct tree *t, struct node *parent);

/*
 * PROCESS:
 *	- check child reactivity
 *	- if FISSIBLE: split child
 *	- if FLUSHBLE: flush buffer from child
 * ENTER:
 *	- parent is already locked
 *	- child is already locked
 * EXIT:
 *	- parent is unlocked
 *	- no nodes are locked
 */
void _child_maybe_reactivity(struct tree *t, struct node *parent, struct node *child)
{
	enum reactivity re = get_reactivity(t, child);

	switch (re) {
	case STABLE:
		cache_unpin(t->cf, child->cpair, make_cpair_attr(child));
		cache_unpin(t->cf, parent->cpair, make_cpair_attr(parent));
		break;
	case FISSIBLE:
		node_split_child(t, parent, child);
		cache_unpin(t->cf, child->cpair, make_cpair_attr(child));
		cache_unpin(t->cf, parent->cpair, make_cpair_attr(parent));
		break;
	case FLUSHBLE:
		cache_unpin(t->cf, parent->cpair, make_cpair_attr(parent));
		_flush_some_child(t, child);
		break;
	}
}

/*
 * PROCESS:
 *	- pick a heaviest child of parent
 *	- flush from parent to child
 *	- maybe split/flush child recursively
 * ENTER:
 *	- parent is already locked
 * EXIT:
 *	- parent is unlocked
 *	- no nodes are locked
 */
void _flush_some_child(struct tree *t, struct node *parent)
{
	int childnum;
	enum reactivity re;
	struct node *child;
	struct partition *part;
	struct nmb *buffer;
	struct timespec t1, t2;

	childnum = node_find_heaviest_idx(parent);
	nassert(childnum < parent->n_children);
	part = &parent->parts[childnum];
	buffer = part->ptr.u.nonleaf->buffer;
	if (cache_get_and_pin(t->cf, part->child_nid, (void**)&child, L_WRITE) != NESS_OK) {
		__ERROR("cache get node error, nid [%" PRIu64 "]", part->child_nid);
		return;
	}

	ngettime(&t1);
	re = get_reactivity(t, child);
	if (re == STABLE) {
		node_set_dirty(parent);
		part->ptr.u.nonleaf->buffer = nmb_new(t->e);
		_flush_buffer_to_child(t, child, buffer);
		nmb_free(buffer);
	}
	ngettime(&t2);
	status_add(&t->e->status->tree_flush_child_costs, time_diff_ms(t1, t2));
	status_increment(&t->e->status->tree_flush_child_nums);

	_child_maybe_reactivity(t, parent, child);
}
コード例 #17
0
ファイル: tree.c プロジェクト: FromPointer/nessDB
/*
 * EFFECT:
 *	- split leaf&lmb into two leaves:a & b
 *	  a&b are both the half of the lmb
 *
 * PROCESS:
 *	- leaf:
 *		+-----------------------------------+
 *		|  0  |  1  |  2  |  3  |  4  |  5  |
 *		+-----------------------------------+
 *
 *	- split:
 *				   root
 *				 +--------+
 *				 |   2    |
 *				 +--------+
 *	  	                /          \
 *	    	+-----------------+	 +------------------+
 *	    	|  0  |  1  |  2  |	 |  3  |  4  |  5   |
 *	    	+-----------------+	 +------------------+
 *	    	      nodea			nodeb
 *
 * ENTER:
 *	- leaf is already locked (L_WRITE)
 * EXITS:
 *	- a is locked
 *	- b is locked
 */
static void _leaf_and_lmb_split(struct tree *t,
                                struct node *leaf,
                                struct node **a,
                                struct node **b,
                                struct msg **split_key)
{
	struct child_pointer *cptra;
	struct child_pointer *cptrb;
	struct node *leafa;
	struct node *leafb;
	struct lmb *mb;
	struct lmb *mba;
	struct lmb *mbb;
	struct msg *sp_key = NULL;

	__DEBUG("leaf split begin, NID %"PRIu64""
	        ", nodesz %d"
	        ", nodec %d"
	        ", children %d"
	        , leaf->nid
	        , node_size(leaf)
	        , node_count(leaf)
	        , leaf->n_children);

	leafa = leaf;
	cptra = &leafa->parts[0].ptr;

	/* split lmb of leaf to mba & mbb */
	mb = cptra->u.leaf->buffer;
	lmb_split(mb, &mba, &mbb, &sp_key);
	lmb_free(mb);

	/* reset leafa buffer */
	cptra->u.leaf->buffer = mba;

	/* new leafb */
	NID nid = hdr_next_nid(t->hdr);
	node_create(nid, 0, 1, t->hdr->version, t->e, &leafb);
	cache_put_and_pin(t->cf, nid, leafb);

	cptrb = &leafb->parts[0].ptr;
	lmb_free(cptrb->u.leaf->buffer);
	cptrb->u.leaf->buffer = mbb;

	/* set dirty */
	node_set_dirty(leafa);
	node_set_dirty(leafb);

	__DEBUG("leaf split end, leafa NID %"PRIu64""
	        ", nodesz %d"
	        ", nodec %d"
	        ", children %d"
	        , leafa->nid
	        , node_size(leafa)
	        , node_count(leafa)
	        , leafa->n_children);

	__DEBUG("leaf split end, leafb NID %"PRIu64""
	        ", nodesz %d"
	        ", nodec %d"
	        ", children %d"
	        , leafb->nid
	        , node_size(leafb)
	        , node_count(leafb)
	        , leafb->n_children);

	*a = leafa;
	*b = leafb;
	*split_key = sp_key;
	status_increment(&t->e->status->tree_leaf_split_nums);
}