static int remove(StorageImpl db, int pageId, Btree tree, BtreeKey rem, int height)
    {
        Page pg = db.getPage(pageId);
        try { 
            int i, n = getnItems(pg), l = 0, r = n;
            
            if (tree.type == ClassDescriptor.tpString) { 
                while (l < r)  {
                    i = (l+r) >> 1;
                    if (compareStr(rem.key, pg, i) > 0) { 
                        l = i+1; 
                    } else { 
                        r = i;
                    }
                }
                if (--height != 0) {
                    do {  
                        switch (remove(db, getKeyStrOid(pg, r), tree, rem, height)) {
                          case Btree.op_underflow: 
                            db.pool.unfix(pg);
                            pg = null;
                            pg = db.putPage(pageId);
                            return handlePageUnderflow(db, pg, r, tree.type, rem, height);
                          case Btree.op_done:
                            return Btree.op_done;
                          case Btree.op_overflow:
                            db.pool.unfix(pg);
                            pg = null;
                            pg = db.putPage(pageId);
                            return insertStrKey(db, pg, r, rem, height);
                        }
                    } while (++r <= n);
                } else { 
                    while (r < n) { 
                        if (compareStr(rem.key, pg, r) == 0) {
                            int oid = getKeyStrOid(pg, r);
                            if (oid == rem.oid || rem.oid == 0) { 
                                rem.oldOid = oid;
                                db.pool.unfix(pg);
                                pg = null;
                                pg = db.putPage(pageId);
                                return removeStrKey(pg, r);
                            }
                        } else { 
                            break;
                        }
                        r += 1;
                    }
                }
            } else if (tree.type == ClassDescriptor.tpArrayOfByte) {
                while (l < r)  {
                    i = (l+r) >> 1;
                    if (tree.compareByteArrays(rem.key, pg, i) > 0) { 
                        l = i+1; 
                    } else { 
                        r = i;
                    }
                }
                if (--height != 0) {
                    do {  
                        switch (remove(db, getKeyStrOid(pg, r), tree, rem, height)) {
                          case Btree.op_underflow: 
                            db.pool.unfix(pg);
                            pg = null;
                            pg = db.putPage(pageId);
                            return handlePageUnderflow(db, pg, r, tree.type, rem, height);
                          case Btree.op_done:
                            return Btree.op_done;
                          case Btree.op_overflow:
                            db.pool.unfix(pg);
                            pg = null;
                            pg = db.putPage(pageId);
                            return insertByteArrayKey(db, pg, r, rem, height);
                        }
                    } while (++r <= n);
                } else { 
                    while (r < n) { 
                        if (tree.compareByteArrays(rem.key, pg, r) == 0) { 
                            int oid = getKeyStrOid(pg, r);
                            if (oid == rem.oid || rem.oid == 0) { 
                                rem.oldOid = oid;
                                db.pool.unfix(pg);
                                pg = null;
                                pg = db.putPage(pageId);
                                return removeByteArrayKey(pg, r);
                            }
                        } else { 
                            break;
                        }
                        r += 1;
                    }
                }
            } else { // scalar types
                int itemSize = ClassDescriptor.sizeof[tree.type];
                while (l < r)  {
                    i = (l+r) >> 1;
                    if (compare(rem.key, pg, i) > 0) { 
                        l = i+1; 
                    } else { 
                        r = i;
                    }
                }
                if (--height == 0) {
                    int oid = rem.oid;
                    while (r < n) {
                        if (compare(rem.key, pg, r) == 0) {
                            if (getReference(pg, maxItems-r-1) == oid || oid == 0) {
                                rem.oldOid = getReference(pg, maxItems-r-1);
                                db.pool.unfix(pg);
                                pg = null;
                                pg = db.putPage(pageId);
                                memcpy(pg, r, pg, r+1, n - r - 1, itemSize);
                                memcpy(pg, maxItems-n+1, pg, maxItems-n, n - r - 1, 4);
                                setnItems(pg, --n);
                                return n*(itemSize + 4) < keySpace/3
                                    ? Btree.op_underflow : Btree.op_done;
                            }
                        } else {
                            break;
                        }
                        r += 1;
                    }
                    return Btree.op_not_found;
                }
                do { 
                    switch (remove(db, getReference(pg, maxItems-r-1), tree, rem, height)) {
                      case Btree.op_underflow: 
                        db.pool.unfix(pg);
                        pg = null;
                        pg = db.putPage(pageId);
                        return handlePageUnderflow(db, pg, r, tree.type, rem, height);
                      case Btree.op_done:
                        return Btree.op_done;
                    } 
                } while (++r <= n);
            }
            return Btree.op_not_found;
        } finally { 
            if (pg != null) { 
                db.pool.unfix(pg);
            }
        }
    }