if (cmd == NOTHING_FURTHER) goto done;
__bam_c_physdel(dbp, cp, h)	DB *dbp;	CURSOR *cp;	PAGE *h;{	BOVERFLOW bo;	BTREE *t;	DBT dbt;	DB_LOCK lock;	db_indx_t indx;	db_pgno_t pgno, next_pgno, prev_pgno;	int local, normal, ret;	t = dbp->internal;	ret = 0;	/* Figure out what we're deleting. */	if (cp->dpgno == PGNO_INVALID) {		pgno = cp->pgno;		indx = cp->indx;	} else {		pgno = cp->dpgno;		indx = cp->dindx;	}	/*	 * If the item is referenced by another cursor, leave it up to that	 * cursor to do the delete.	 */	if (__bam_ca_delete(dbp, pgno, indx, cp, 0) != 0)		return (0);	/*	 * If we don't already have the page locked, get it and delete the	 * items.	 */	if ((h == NULL || h->pgno != pgno)) {		if ((ret = __bam_lget(dbp, 0, pgno, DB_LOCK_WRITE, &lock)) != 0)			return (ret);		if ((ret = __bam_pget(dbp, &h, &pgno, 0)) != 0)			return (ret);		local = 1;	} else		local = 0;	/*	 * If we're deleting a duplicate entry and there are other duplicate	 * entries remaining, call the common code to do the work and fix up	 * the parent page as necessary.  Otherwise, do a normal btree delete.	 *	 * There are 5 possible cases:	 *	 * 1. It's not a duplicate item: do a normal btree delete.	 * 2. It's a duplicate item:	 *	2a: We delete an item from a page of duplicates, but there are	 *	    more items on the page.	 *      2b: We delete the last item from a page of duplicates, deleting	 *	    the last duplicate.	 *      2c: We delete the last item from a page of duplicates, but there	 *	    is a previous page of duplicates.	 *      2d: We delete the last item from a page of duplicates, but there	 *	    is a following page of duplicates.	 *	 * In the case of:	 *	 *  1: There's nothing further to do.	 * 2a: There's nothing further to do.	 * 2b: Do the normal btree delete instead of a duplicate delete, as	 *     that deletes both the duplicate chain and the parent page's	 *     entry.	 * 2c: There's nothing further to do.	 * 2d: Delete the duplicate, and update the parent page's entry.	 */	if (TYPE(h) == P_DUPLICATE) {		pgno = PGNO(h);		prev_pgno = PREV_PGNO(h);		next_pgno = NEXT_PGNO(h);		if (NUM_ENT(h) == 1 &&		    prev_pgno == PGNO_INVALID && next_pgno == PGNO_INVALID)			normal = 1;		else {			normal = 0;			/* Delete the duplicate. */			if ((ret = __db_drem(dbp, &h, indx, __bam_free)) != 0)				goto err;			/*			 * 2a: h != NULL, h->pgno == pgno			 * 2b: We don't reach this clause, as the above test			 *     was true.			 * 2c: h == NULL, prev_pgno != PGNO_INVALID			 * 2d: h != NULL, next_pgno != PGNO_INVALID			 *			 * Test for 2a and 2c: if we didn't empty the current			 * page or there was a previous page of duplicates, we			 * don't need to touch the parent page.			 */			if ((h != NULL && pgno == h->pgno) ||			    prev_pgno != PGNO_INVALID)				goto done;		}		/* Release any page we're holding and its lock. */		if (local) {			if (h != NULL)				(void)memp_fput(dbp->mpf, h, 0);			(void)__BT_TLPUT(dbp, lock);			local = 0;		}		/* Acquire the parent page. */		if ((ret =		    __bam_lget(dbp, 0, cp->pgno, DB_LOCK_WRITE, &lock)) != 0)			goto err;		if ((ret = __bam_pget(dbp, &h, &cp->pgno, 0)) != 0) {			(void)__BT_TLPUT(dbp, lock);			goto err;		}		local = 1;		/* Switch to the parent page's entry. */		indx = cp->indx;		if (normal)			goto btd;		/*		 * Copy, delete, update, add-back the parent page's data entry.		 *		 * XXX		 * This may be a performance/logging problem.  We should add a		 * log message which simply logs/updates a random set of bytes		 * on a page, and use it instead of doing a delete/add pair.		 */		indx += O_INDX;		bo = *GET_BOVERFLOW(h, indx);		(void)__db_ditem(dbp, h, indx, BOVERFLOW_SIZE);		bo.pgno = next_pgno;		memset(&dbt, 0, sizeof(dbt));		dbt.data = &bo;		dbt.size = BOVERFLOW_SIZE;		(void)__db_pitem(dbp, h, indx, BOVERFLOW_SIZE, &dbt, NULL);		(void)memp_fset(dbp->mpf, h, DB_MPOOL_DIRTY);		goto done;	}	/* Otherwise, do a normal btree delete. */btd:	if ((ret = __bam_ditem(dbp, h, indx)) != 0)		goto err;	if ((ret = __bam_ditem(dbp, h, indx)) != 0)		goto err;	/*	 * If the page is empty, delete it.  To delete a leaf page we need a	 * copy of a key from the page.  We use the first one that was there,	 * since it's the last key that the page held.  We malloc the page	 * information instead of using the return key/data memory because	 * we've already set them -- the reason that we've already set them	 * is because we're (potentially) about to do a reverse split, which	 * would make our saved page information useless.	 *	 * XXX	 * The following operations to delete a page might deadlock.  I think	 * that's OK.  The problem is if we're deleting an item because we're	 * closing cursors because we've already deadlocked and want to call	 * txn_abort().  If we fail due to deadlock, we'll leave an locked	 * empty page in the tree, which won't be empty long because we're	 * going to undo the delete.	 */	if (NUM_ENT(h) == 0 && h->pgno != PGNO_ROOT) {		memset(&dbt, 0, sizeof(DBT));		dbt.flags = DB_DBT_MALLOC | DB_DBT_INTERNAL;		if ((ret = __db_ret(dbp, h, 0, &dbt, NULL, NULL)) != 0)			goto err;		if (local) {			(void)memp_fput(dbp->mpf, h, 0);			(void)__BT_TLPUT(dbp, lock);			local = 0;		}		ret = __bam_dpage(dbp, &dbt);		__db_free(dbt.data);	}err:done:	if (local) {		(void)memp_fput(dbp->mpf, h, 0);		(void)__BT_TLPUT(dbp, lock);	}	if (ret == 0)		++t->lstat.bt_deleted;	return (ret);}