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

📄 jfs_dtree.c

📁 jfs-2.4-1.1.7.tar.gz jfs 2.4-1.1.7 源码
💻 C
📖 第 1 页 / 共 5 页
字号:
	 * keep the child pages pinned while working on the parent.	 * make sure that all pins are released at exit.	 */	while ((parent = BT_POP(btstack)) != NULL) {		/* parent page specified by stack frame <parent> */		/* keep current child pages (<lp>, <rp>) pinned */		lmp = smp;		lp = sp;		/*		 * insert router entry in parent for new right child page <rp>		 */		/* get the parent page <sp> */		DT_GETPAGE(ip, parent->bn, smp, PSIZE, sp, rc);		if (rc) {			DT_PUTPAGE(lmp);			DT_PUTPAGE(rmp);			goto splitOut;		}		/*		 * The new key entry goes ONE AFTER the index of parent entry,		 * because the split was to the right.		 */		skip = parent->index + 1;		/*		 * compute the key for the router entry		 *		 * key suffix compression:		 * for internal pages that have leaf pages as children,		 * retain only what's needed to distinguish between		 * the new entry and the entry on the page to its left.		 * If the keys compare equal, retain the entire key.		 *		 * note that compression is performed only at computing		 * router key at the lowest internal level.		 * further compression of the key between pairs of higher		 * level internal pages loses too much information and		 * the search may fail.		 * (e.g., two adjacent leaf pages of {a, ..., x} {xx, ...,}		 * results in two adjacent parent entries (a)(xx).		 * if split occurs between these two entries, and		 * if compression is applied, the router key of parent entry		 * of right page (x) will divert search for x into right		 * subtree and miss x in the left subtree.)		 *		 * the entire key must be retained for the next-to-leftmost		 * internal key at any level of the tree, or search may fail		 * (e.g., ?)		 */		switch (rp->header.flag & BT_TYPE) {		case BT_LEAF:			/*			 * compute the length of prefix for suffix compression			 * between last entry of left page and first entry			 * of right page			 */			if ((sp->header.flag & BT_ROOT && skip > 1) ||			    sp->header.prev != 0 || skip > 1) {				/* compute uppercase router prefix key */				rc = ciGetLeafPrefixKey(lp,							lp->header.nextindex-1,							rp, 0, &key,							sbi->mntflag);				if (rc) {					DT_PUTPAGE(lmp);					DT_PUTPAGE(rmp);					DT_PUTPAGE(smp);					goto splitOut;				}			} else {				/* next to leftmost entry of				   lowest internal level */				/* compute uppercase router key */				dtGetKey(rp, 0, &key, sbi->mntflag);				key.name[key.namlen] = 0;				if ((sbi->mntflag & JFS_OS2) == JFS_OS2)					ciToUpper(&key);			}			n = NDTINTERNAL(key.namlen);			break;		case BT_INTERNAL:			dtGetKey(rp, 0, &key, sbi->mntflag);			n = NDTINTERNAL(key.namlen);			break;		default:			jfs_err("dtSplitUp(): UFO!");			break;		}		/* unpin left child page */		DT_PUTPAGE(lmp);		/*		 * compute the data for the router entry		 */		data->xd = rpxd;	/* child page xd */		/*		 * parent page is full - split the parent page		 */		if (n > sp->header.freecnt) {			/* init for parent page split */			split->mp = smp;			split->index = skip;	/* index at insert */			split->nslot = n;			split->key = &key;			/* split->data = data; */			/* unpin right child page */			DT_PUTPAGE(rmp);			/* The split routines insert the new entry,			 * acquire txLock as appropriate.			 * return <rp> pinned and its block number <rbn>.			 */			rc = (sp->header.flag & BT_ROOT) ?			    dtSplitRoot(tid, ip, split, &rmp) :			    dtSplitPage(tid, ip, split, &rmp, &rp, &rpxd);			if (rc) {				DT_PUTPAGE(smp);				goto splitOut;			}			/* smp and rmp are pinned */		}		/*		 * parent page is not full - insert router entry in parent page		 */		else {			BT_MARK_DIRTY(smp, ip);			/*			 * acquire a transaction lock on the parent page			 */			tlck = txLock(tid, ip, smp, tlckDTREE | tlckENTRY);			dtlck = (struct dt_lock *) & tlck->lock;			ASSERT(dtlck->index == 0);			lv = & dtlck->lv[0];			/* linelock header */			lv->offset = 0;			lv->length = 1;			dtlck->index++;			/* linelock stbl of non-root parent page */			if (!(sp->header.flag & BT_ROOT)) {				lv++;				n = skip >> L2DTSLOTSIZE;				lv->offset = sp->header.stblindex + n;				lv->length =				    ((sp->header.nextindex -				      1) >> L2DTSLOTSIZE) - n + 1;				dtlck->index++;			}			dtInsertEntry(sp, skip, &key, data, &dtlck);			/* exit propagate up */			break;		}	}	/* unpin current split and its right page */	DT_PUTPAGE(smp);	DT_PUTPAGE(rmp);	/*	 * free remaining extents allocated for split	 */      splitOut:	n = pxdlist.npxd;	pxd = &pxdlist.pxd[n];	for (; n < pxdlist.maxnpxd; n++, pxd++)		dbFree(ip, addressPXD(pxd), (s64) lengthPXD(pxd));      freeKeyName:	kfree(key.name);      dtSplitUp_Exit:	return rc;}/* *	dtSplitPage() * * function: Split a non-root page of a btree. * * parameter: * * return: 0 - success; *	   errno - failure; *	return split and new page pinned; */static int dtSplitPage(tid_t tid, struct inode *ip, struct dtsplit * split,	    struct metapage ** rmpp, dtpage_t ** rpp, pxd_t * rpxdp){	struct super_block *sb = ip->i_sb;	int rc = 0;	struct metapage *smp;	dtpage_t *sp;	struct metapage *rmp;	dtpage_t *rp;		/* new right page allocated */	s64 rbn;		/* new right page block number */	struct metapage *mp;	dtpage_t *p;	s64 nextbn;	struct pxdlist *pxdlist;	pxd_t *pxd;	int skip, nextindex, half, left, nxt, off, si;	struct ldtentry *ldtentry;	struct idtentry *idtentry;	u8 *stbl;	struct dtslot *f;	int fsi, stblsize;	int n;	struct dt_lock *sdtlck, *rdtlck;	struct tlock *tlck;	struct dt_lock *dtlck;	struct lv *slv, *rlv, *lv;	/* get split page */	smp = split->mp;	sp = DT_PAGE(ip, smp);	/*	 * allocate the new right page for the split	 */	pxdlist = split->pxdlist;	pxd = &pxdlist->pxd[pxdlist->npxd];	pxdlist->npxd++;	rbn = addressPXD(pxd);	rmp = get_metapage(ip, rbn, PSIZE, 1);	if (rmp == NULL)		return -EIO;	jfs_info("dtSplitPage: ip:0x%p smp:0x%p rmp:0x%p", ip, smp, rmp);	BT_MARK_DIRTY(rmp, ip);	/*	 * acquire a transaction lock on the new right page	 */	tlck = txLock(tid, ip, rmp, tlckDTREE | tlckNEW);	rdtlck = (struct dt_lock *) & tlck->lock;	rp = (dtpage_t *) rmp->data;	*rpp = rp;	rp->header.self = *pxd;	BT_MARK_DIRTY(smp, ip);	/*	 * acquire a transaction lock on the split page	 *	 * action:	 */	tlck = txLock(tid, ip, smp, tlckDTREE | tlckENTRY);	sdtlck = (struct dt_lock *) & tlck->lock;	/* linelock header of split page */	ASSERT(sdtlck->index == 0);	slv = & sdtlck->lv[0];	slv->offset = 0;	slv->length = 1;	sdtlck->index++;	/*	 * initialize/update sibling pointers between sp and rp	 */	nextbn = le64_to_cpu(sp->header.next);	rp->header.next = cpu_to_le64(nextbn);	rp->header.prev = cpu_to_le64(addressPXD(&sp->header.self));	sp->header.next = cpu_to_le64(rbn);	/*	 * initialize new right page	 */	rp->header.flag = sp->header.flag;	/* compute sorted entry table at start of extent data area */	rp->header.nextindex = 0;	rp->header.stblindex = 1;	n = PSIZE >> L2DTSLOTSIZE;	rp->header.maxslot = n;	stblsize = (n + 31) >> L2DTSLOTSIZE;	/* in unit of slot */	/* init freelist */	fsi = rp->header.stblindex + stblsize;	rp->header.freelist = fsi;	rp->header.freecnt = rp->header.maxslot - fsi;	/*	 *      sequential append at tail: append without split	 *	 * If splitting the last page on a level because of appending	 * a entry to it (skip is maxentry), it's likely that the access is	 * sequential. Adding an empty page on the side of the level is less	 * work and can push the fill factor much higher than normal.	 * If we're wrong it's no big deal, we'll just do the split the right	 * way next time.	 * (It may look like it's equally easy to do a similar hack for	 * reverse sorted data, that is, split the tree left,	 * but it's not. Be my guest.)	 */	if (nextbn == 0 && split->index == sp->header.nextindex) {		/* linelock header + stbl (first slot) of new page */		rlv = & rdtlck->lv[rdtlck->index];		rlv->offset = 0;		rlv->length = 2;		rdtlck->index++;		/*		 * initialize freelist of new right page		 */		f = &rp->slot[fsi];		for (fsi++; fsi < rp->header.maxslot; f++, fsi++)			f->next = fsi;		f->next = -1;		/* insert entry at the first entry of the new right page */		dtInsertEntry(rp, 0, split->key, split->data, &rdtlck);		goto out;	}	/*	 *      non-sequential insert (at possibly middle page)	 */	/*	 * update prev pointer of previous right sibling page;	 */	if (nextbn != 0) {		DT_GETPAGE(ip, nextbn, mp, PSIZE, p, rc);		if (rc) {			discard_metapage(rmp);			return rc;		}		BT_MARK_DIRTY(mp, ip);		/*		 * acquire a transaction lock on the next page		 */		tlck = txLock(tid, ip, mp, tlckDTREE | tlckRELINK);		jfs_info("dtSplitPage: tlck = 0x%p, ip = 0x%p, mp=0x%p",			tlck, ip, mp);		dtlck = (struct dt_lock *) & tlck->lock;		/* linelock header of previous right sibling page */		lv = & dtlck->lv[dtlck->index];		lv->offset = 0;		lv->length = 1;		dtlck->index++;		p->header.prev = cpu_to_le64(rbn);		DT_PUTPAGE(mp);	}	/*	 * split the data between the split and right pages.	 */	skip = split->index;	half = (PSIZE >> L2DTSLOTSIZE) >> 1;	/* swag */	left = 0;	/*	 *      compute fill factor for split pages	 *	 * <nxt> traces the next entry to move to rp	 * <off> traces the next entry to stay in sp	 */	stbl = (u8 *) & sp->slot[sp->header.stblindex];	nextindex = sp->header.nextindex;	for (nxt = off = 0; nxt < nextindex; ++off) {		if (off == skip)			/* check for fill factor with new entry size */			n = split->nslot;		else {			si = stbl[nxt];			switch (sp->header.flag & BT_TYPE) {			case BT_LEAF:				ldtentry = (struct ldtentry *) & sp->slot[si];				if (DO_INDEX(ip))					n = NDTLEAF(ldtentry->namlen);				else					n = NDTLEAF_LEGACY(ldtentry->							   namlen);				break;			case BT_INTERNAL:				idtentry = (struct idtentry *) & sp->slot[si];				n = NDTINTERNAL(idtentry->namlen);				break;			default:				break;			}			++nxt;	/* advance to next entry to move in sp */		}		left += n;		if (left >= half)			break;	}	/* <nxt> poins to the 1st entry to move */	/*	 *      move entries to right page	 *	 * dtMoveEntry() initializes rp and reserves entry for insertion	 *	 * split page moved out entries are linelocked;	 * new/right page moved in entries are linelocked;	 */	/* linelock header + stbl of new right page */	rlv = & rdtlck->lv[rdtlck->index];	rlv->offset = 0;	rlv->length = 5;	rdtlck->index++;	dtMoveEntry(sp, nxt, rp, &sdtlck, &rdtlck, DO_INDEX(ip));	sp->header.nextindex = nxt;	/*	 * finalize freelist of new right page	 */	fsi = rp->header.freelist;	f = &rp->slot[fsi];	for (fsi++; fsi < rp->header.maxslot; f++, fsi++)		f->next = fsi;	f->next = -1;	/*	 * Update directory index table for entries now in right page	 */	if ((rp->header.flag & BT_LEAF) && DO_INDEX(ip)) {		s64 lblock;		mp = 0;		stbl = DT_GETSTBL(rp);		for (n = 0; n < rp->header.nextindex; n++) {			ldtentry = (struct ldtentry *) & rp->slot[stbl[n]];			modify_index(tid, ip, le32_to_cpu(ldtentry->index),				     rbn, n, &mp, &lblock);		}		if (mp)			release_metapage(mp);	}	/*	 * the skipped index was on the left page,	 */	if (skip <= off) {		/* insert the new entry in the split page */		dtInsertEntry(sp, skip, split->key, split->data, &sdtlck);		/* linelock stbl of split page */		if (sdtlck->index >= sdtlck->maxcnt)			sdtlck = (struct dt_lock *) txLinelock(sdtlck);		slv = & sdtlck->lv[sdtlck->index];		n = skip >> L2DTSLOTSIZE;		slv->offset = sp->header.stblindex + n;		slv->length =		    ((sp->header.nextindex - 1) >> L2DTSLOTSIZE) - n + 1;		sdtlck->index++;	}	/*	 * the skipped index was on the right page,	 */	else {		/* adjust the skip index to reflect the new position */		skip -= nxt;		/* insert the new entry in the right page */		dtInsertEntry(rp, skip, split->key, split->data, &rdtlck);	}      out:	*rmpp = rmp;	*rpxdp = *pxd;	ip->i_blocks += LBLK2PBLK(sb, lengthPXD(pxd));	return rc;}/* *	dtExtendPage() * * function: extend 1st/only directory leaf page * * parameter: * * return: 0 - success; *	   errno - failure; *	return extended page pinned; */static int dtExtendPage(tid_t tid,	     struct inode *ip, struct dtsplit * split, struct btstack * btstack){	struct super_block *sb = ip->i_sb;	int rc;	struct metapage *smp, *pmp, *mp;	dtpage_t *sp, *pp;	struct pxdlist *pxdlist;	pxd_t *pxd, *tpxd;	int xlen, xsize;	int newstblindex, newstblsize;	int oldstblindex, oldstblsize;	int fsi, last;	struct dtslot *f;	struct btframe *parent;	int n;	struct dt_lock *dtlck;	s64 xaddr, txaddr;	struct tlock *tlck;	struct pxd_lock *pxdlock;	struct lv *lv;	uint type;	struct ldtentry *ldtentry;	u8 *stbl;	/* get page to extend */	smp = split->mp;	sp = DT_PAGE(ip, smp);	/* get parent/root page */	parent = BT_POP(btstack);	DT_GETPAGE(ip, parent->bn, pmp, PSIZE, pp, rc);	if (rc)		return (rc);	/*	 *      extend the extent	 */	pxdlist = split->pxdlist;	pxd = &pxdlist->pxd[pxdlist->npxd];	pxdlist->npxd++;

⌨️ 快捷键说明

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