⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 bt_split.c

📁 asterisk 一个模拟IPPBX的源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
	 * Split right.  The key/data pairs aren't sorted in the btree page so	 * it's simpler to copy the data from the split page onto two new pages	 * instead of copying half the data to the right page and compacting	 * the left page in place.  Since the left page can't change, we have	 * to swap the original and the allocated left page after the split.	 */	tp = bt_psplit(t, h, l, r, skip, ilen);	/* Move the new left page onto the old left page. */	memmove(h, l, t->bt_psize);	if (tp == l)		tp = h;	free(l);	*lp = h;	*rp = r;	return (tp);}/* * BT_ROOT -- Split the root page of a btree. * * Parameters: *	t:	tree *	h:	root page *	lp:	pointer to left page pointer *	rp:	pointer to right page pointer *	skip:	pointer to index to leave open *	ilen:	insert length * * Returns: *	Pointer to page in which to insert or NULL on error. */static PAGE *bt_root(t, h, lp, rp, skip, ilen)	BTREE *t;	PAGE *h, **lp, **rp;	indx_t *skip;	size_t ilen;{	PAGE *l, *r, *tp;	pgno_t lnpg, rnpg;#ifdef STATISTICS	++bt_split;	++bt_rootsplit;#endif	/* Put the new left and right pages for the split into place. */	if ((l = __bt_new(t, &lnpg)) == NULL ||	    (r = __bt_new(t, &rnpg)) == NULL)		return (NULL);	l->pgno = lnpg;	r->pgno = rnpg;	l->nextpg = r->pgno;	r->prevpg = l->pgno;	l->prevpg = r->nextpg = P_INVALID;	l->lower = r->lower = BTDATAOFF;	l->upper = r->upper = t->bt_psize;	l->flags = r->flags = h->flags & P_TYPE;	/* Split the root page. */	tp = bt_psplit(t, h, l, r, skip, ilen);	*lp = l;	*rp = r;	return (tp);}/* * BT_RROOT -- Fix up the recno root page after it has been split. * * Parameters: *	t:	tree *	h:	root page *	l:	left page *	r:	right page * * Returns: *	RET_ERROR, RET_SUCCESS */static intbt_rroot(t, h, l, r)	BTREE *t;	PAGE *h, *l, *r;{	char *dest;	/* Insert the left and right keys, set the header information. */	h->linp[0] = h->upper = t->bt_psize - NRINTERNAL;	dest = (char *)h + h->upper;	WR_RINTERNAL(dest,	    l->flags & P_RLEAF ? NEXTINDEX(l) : rec_total(l), l->pgno);	h->linp[1] = h->upper -= NRINTERNAL;	dest = (char *)h + h->upper;	WR_RINTERNAL(dest,	    r->flags & P_RLEAF ? NEXTINDEX(r) : rec_total(r), r->pgno);	h->lower = BTDATAOFF + 2 * sizeof(indx_t);	/* Unpin the root page, set to recno internal page. */	h->flags &= ~P_TYPE;	h->flags |= P_RINTERNAL;	mpool_put(t->bt_mp, h, MPOOL_DIRTY);	return (RET_SUCCESS);}/* * BT_BROOT -- Fix up the btree root page after it has been split. * * Parameters: *	t:	tree *	h:	root page *	l:	left page *	r:	right page * * Returns: *	RET_ERROR, RET_SUCCESS */static intbt_broot(t, h, l, r)	BTREE *t;	PAGE *h, *l, *r;{	BINTERNAL *bi;	BLEAF *bl;	u_int32_t nbytes;	char *dest;	/*	 * If the root page was a leaf page, change it into an internal page.	 * We copy the key we split on (but not the key's data, in the case of	 * a leaf page) to the new root page.	 *	 * The btree comparison code guarantees that the left-most key on any	 * level of the tree is never used, so it doesn't need to be filled in.	 */	nbytes = NBINTERNAL(0);	h->linp[0] = h->upper = t->bt_psize - nbytes;	dest = (char *)h + h->upper;	WR_BINTERNAL(dest, 0, l->pgno, 0);	switch (h->flags & P_TYPE) {	case P_BLEAF:		bl = GETBLEAF(r, 0);		nbytes = NBINTERNAL(bl->ksize);		h->linp[1] = h->upper -= nbytes;		dest = (char *)h + h->upper;		WR_BINTERNAL(dest, bl->ksize, r->pgno, 0);		memmove(dest, bl->bytes, bl->ksize);		/*		 * If the key is on an overflow page, mark the overflow chain		 * so it isn't deleted when the leaf copy of the key is deleted.		 */		if (bl->flags & P_BIGKEY &&		    bt_preserve(t, *(pgno_t *)bl->bytes) == RET_ERROR)			return (RET_ERROR);		break;	case P_BINTERNAL:		bi = GETBINTERNAL(r, 0);		nbytes = NBINTERNAL(bi->ksize);		h->linp[1] = h->upper -= nbytes;		dest = (char *)h + h->upper;		memmove(dest, bi, nbytes);		((BINTERNAL *)dest)->pgno = r->pgno;		break;	default:		abort();	}	/* There are two keys on the page. */	h->lower = BTDATAOFF + 2 * sizeof(indx_t);	/* Unpin the root page, set to btree internal page. */	h->flags &= ~P_TYPE;	h->flags |= P_BINTERNAL;	mpool_put(t->bt_mp, h, MPOOL_DIRTY);	return (RET_SUCCESS);}/* * BT_PSPLIT -- Do the real work of splitting the page. * * Parameters: *	t:	tree *	h:	page to be split *	l:	page to put lower half of data *	r:	page to put upper half of data *	pskip:	pointer to index to leave open *	ilen:	insert length * * Returns: *	Pointer to page in which to insert. */static PAGE *bt_psplit(t, h, l, r, pskip, ilen)	BTREE *t;	PAGE *h, *l, *r;	indx_t *pskip;	size_t ilen;{	BINTERNAL *bi;	BLEAF *bl;	CURSOR *c;	RLEAF *rl;	PAGE *rval;	void *src = 0;	indx_t full, half, nxt, off, skip, top, used;	u_int32_t nbytes;	int bigkeycnt, isbigkey;	/*	 * Split the data to the left and right pages.  Leave the skip index	 * open.  Additionally, make some effort not to split on an overflow	 * key.  This makes internal page processing faster and can save	 * space as overflow keys used by internal pages are never deleted.	 */	bigkeycnt = 0;	skip = *pskip;	full = t->bt_psize - BTDATAOFF;	half = full / 2;	used = 0;	for (nxt = off = 0, top = NEXTINDEX(h); nxt < top; ++off) {		if (skip == off) {			nbytes = ilen;			isbigkey = 0;		/* XXX: not really known. */		} else			switch (h->flags & P_TYPE) {			case P_BINTERNAL:				src = bi = GETBINTERNAL(h, nxt);				nbytes = NBINTERNAL(bi->ksize);				isbigkey = bi->flags & P_BIGKEY;				break;			case P_BLEAF:				src = bl = GETBLEAF(h, nxt);				nbytes = NBLEAF(bl);				isbigkey = bl->flags & P_BIGKEY;				break;			case P_RINTERNAL:				src = GETRINTERNAL(h, nxt);				nbytes = NRINTERNAL;				isbigkey = 0;				break;			case P_RLEAF:				src = rl = GETRLEAF(h, nxt);				nbytes = NRLEAF(rl);				isbigkey = 0;				break;			default:				abort();			}		/*		 * If the key/data pairs are substantial fractions of the max		 * possible size for the page, it's possible to get situations		 * where we decide to try and copy too much onto the left page.		 * Make sure that doesn't happen.		 */		if ((skip <= off && used + nbytes + sizeof(indx_t) >= full)		    || nxt == top - 1) {			--off;			break;		}		/* Copy the key/data pair, if not the skipped index. */		if (skip != off) {			++nxt;			l->linp[off] = l->upper -= nbytes;			memmove((char *)l + l->upper, src, nbytes);		}		used += nbytes + sizeof(indx_t);		if (used >= half) {			if (!isbigkey || bigkeycnt == 3)				break;			else				++bigkeycnt;		}	}	/*	 * Off is the last offset that's valid for the left page.	 * Nxt is the first offset to be placed on the right page.	 */	l->lower += (off + 1) * sizeof(indx_t);	/*	 * If splitting the page that the cursor was on, the cursor has to be	 * adjusted to point to the same record as before the split.  If the	 * cursor is at or past the skipped slot, the cursor is incremented by	 * one.  If the cursor is on the right page, it is decremented by the	 * number of records split to the left page.	 */	c = &t->bt_cursor;	if (F_ISSET(c, CURS_INIT) && c->pg.pgno == h->pgno) {		if (c->pg.index >= skip)			++c->pg.index;		if (c->pg.index < nxt)			/* Left page. */			c->pg.pgno = l->pgno;		else {					/* Right page. */			c->pg.pgno = r->pgno;			c->pg.index -= nxt;		}	}	/*	 * If the skipped index was on the left page, just return that page.	 * Otherwise, adjust the skip index to reflect the new position on	 * the right page.	 */	if (skip <= off) {		skip = 0;		rval = l;	} else {		rval = r;		*pskip -= nxt;	}	for (off = 0; nxt < top; ++off) {		if (skip == nxt) {			++off;			skip = 0;		}		switch (h->flags & P_TYPE) {		case P_BINTERNAL:			src = bi = GETBINTERNAL(h, nxt);			nbytes = NBINTERNAL(bi->ksize);			break;		case P_BLEAF:			src = bl = GETBLEAF(h, nxt);			nbytes = NBLEAF(bl);			break;		case P_RINTERNAL:			src = GETRINTERNAL(h, nxt);			nbytes = NRINTERNAL;			break;		case P_RLEAF:			src = rl = GETRLEAF(h, nxt);			nbytes = NRLEAF(rl);			break;		default:			abort();		}		++nxt;		r->linp[off] = r->upper -= nbytes;		memmove((char *)r + r->upper, src, nbytes);	}	r->lower += off * sizeof(indx_t);	/* If the key is being appended to the page, adjust the index. */	if (skip == top)		r->lower += sizeof(indx_t);	return (rval);}/* * BT_PRESERVE -- Mark a chain of pages as used by an internal node. * * Chains of indirect blocks pointed to by leaf nodes get reclaimed when the * record that references them gets deleted.  Chains pointed to by internal * pages never get deleted.  This routine marks a chain as pointed to by an * internal page. * * Parameters: *	t:	tree *	pg:	page number of first page in the chain. * * Returns: *	RET_SUCCESS, RET_ERROR. */static intbt_preserve(t, pg)	BTREE *t;	pgno_t pg;{	PAGE *h;	if ((h = mpool_get(t->bt_mp, pg, 0)) == NULL)		return (RET_ERROR);	h->flags |= P_PRESERVE;	mpool_put(t->bt_mp, h, MPOOL_DIRTY);	return (RET_SUCCESS);}/* * REC_TOTAL -- Return the number of recno entries below a page. * * Parameters: *	h:	page * * Returns: *	The number of recno entries below a page. * * XXX * These values could be set by the bt_psplit routine.  The problem is that the * entry has to be popped off of the stack etc. or the values have to be passed * all the way back to bt_split/bt_rroot and it's not very clean. */static recno_trec_total(h)	PAGE *h;{	recno_t recs;	indx_t nxt, top;	for (recs = 0, nxt = 0, top = NEXTINDEX(h); nxt < top; ++nxt)		recs += GETRINTERNAL(h, nxt)->nrecs;	return (recs);}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -