public void Put(object obj, int mask)
#endif
        {
            StorageImpl db = (StorageImpl)Storage;

            if (db == null)
            {
                throw new StorageError(StorageError.ErrorCode.DELETED_OBJECT);
            }
            Key ins = new Key(mask, db.MakePersistent(obj));

            if (root == 0)
            {
                root   = BitIndexPage.allocate(db, 0, ins);
                height = 1;
            }
            else
            {
                BtreeResult result = BitIndexPage.insert(db, root, ins, height);
                if (result == BtreeResult.Overflow)
                {
                    root    = BitIndexPage.allocate(db, root, ins);
                    height += 1;
                }
            }
            updateCounter += 1;
            nElems        += 1;
            Modify();
        }
        public bool Remove(object obj)
#endif
        {
            StorageImpl db = (StorageImpl)Storage;

            if (db == null)
            {
                throw new StorageError(StorageError.ErrorCode.DELETED_OBJECT);
            }
            if (root == 0)
            {
                return(false);
            }
            BtreeResult result = BitIndexPage.remove(db, root, db.GetOid(obj), height);

            if (result == BtreeResult.NotFound)
            {
                return(false);
            }
            nElems -= 1;
            if (result == BtreeResult.Underflow)
            {
                Page pg = db.getPage(root);
                if (BitIndexPage.getnItems(pg) == 0)
                {
                    int newRoot = 0;
                    if (height != 1)
                    {
                        newRoot = BitIndexPage.getItem(pg, BitIndexPage.maxItems - 1);
                    }
                    db.freePage(root);
                    root    = newRoot;
                    height -= 1;
                }
                db.pool.unfix(pg);
            }
            updateCounter += 1;
            Modify();
            return(true);
        }
            internal static BtreeResult remove(StorageImpl db, int pageId, int oid, int height)
            {
                Page pg = db.getPage(pageId);

                try
                {
                    int i, n = getnItems(pg), l = 0, r = n;
                    if (--height == 0)
                    {
                        while (l < r)
                        {
                            i = (l + r) >> 1;
                            if (oid > getItem(pg, maxItems - 1 - i))
                            {
                                l = i + 1;
                            }
                            else
                            {
                                r = i;
                            }
                        }
                        if (r < n && getItem(pg, maxItems - r - 1) == oid)
                        {
                            db.pool.unfix(pg);
                            pg = null;
                            pg = db.putPage(pageId);
                            memcpy(pg, r, pg, r + 1, n - r - 1);
                            memcpy(pg, maxItems - n + 1, pg, maxItems - n, n - r - 1);
                            setnItems(pg, --n);
                            return(n < max / 3 ? BtreeResult.Underflow : BtreeResult.Done);
                        }
                        return(BtreeResult.NotFound);
                    }
                    else
                    {
                        while (l < r)
                        {
                            i = (l + r) >> 1;
                            if (oid > getItem(pg, i))
                            {
                                l = i + 1;
                            }
                            else
                            {
                                r = i;
                            }
                        }
                        BtreeResult result = remove(db, getItem(pg, maxItems - r - 1), oid, height);
                        if (result == BtreeResult.Underflow)
                        {
                            db.pool.unfix(pg);
                            pg = null;
                            pg = db.putPage(pageId);
                            return(handlePageUnderflow(db, pg, r, height));
                        }
                        return(result);
                    }
                }
                finally
                {
                    if (pg != null)
                    {
                        db.pool.unfix(pg);
                    }
                }
            }
            internal static BtreeResult insert(StorageImpl db, int pageId, Key ins, int height)
            {
                Page pg = db.getPage(pageId);
                int  l = 0, n = getnItems(pg), r = n;
                int  oid = ins.oid;

                try
                {
                    if (--height != 0)
                    {
                        while (l < r)
                        {
                            int i = (l + r) >> 1;
                            if (oid > getItem(pg, i))
                            {
                                l = i + 1;
                            }
                            else
                            {
                                r = i;
                            }
                        }
                        Debug.Assert(l == r);
                        /* insert before e[r] */
                        BtreeResult result = insert(db, getItem(pg, maxItems - r - 1), ins, height);
                        Debug.Assert(result != BtreeResult.NotFound);
                        if (result != BtreeResult.Overflow)
                        {
                            return(result);
                        }
                        n += 1;
                    }
                    else
                    {
                        while (l < r)
                        {
                            int i = (l + r) >> 1;
                            if (oid > getItem(pg, maxItems - 1 - i))
                            {
                                l = i + 1;
                            }
                            else
                            {
                                r = i;
                            }
                        }
                        if (r < n && oid == getItem(pg, maxItems - 1 - r))
                        {
                            db.pool.unfix(pg);
                            pg = null;
                            pg = db.putPage(pageId);
                            setItem(pg, r, ins.key);
                            return(BtreeResult.Overwrite);
                        }
                    }
                    db.pool.unfix(pg);
                    pg = null;
                    pg = db.putPage(pageId);
                    if (n < max)
                    {
                        memcpy(pg, r + 1, pg, r, n - r);
                        memcpy(pg, maxItems - n - 1, pg, maxItems - n, n - r);
                        setItem(pg, r, ins.key);
                        setItem(pg, maxItems - 1 - r, ins.oid);
                        setnItems(pg, getnItems(pg) + 1);
                        return(BtreeResult.Done);
                    }
                    else
                    { /* page is full then divide page */
                        pageId = db.allocatePage();
                        Page b = db.putPage(pageId);
                        Debug.Assert(n == max);
                        int m = (max + 1) / 2;
                        if (r < m)
                        {
                            memcpy(b, 0, pg, 0, r);
                            memcpy(b, r + 1, pg, r, m - r - 1);
                            memcpy(pg, 0, pg, m - 1, max - m + 1);
                            memcpy(b, maxItems - r, pg, maxItems - r, r);
                            setItem(b, r, ins.key);
                            setItem(b, maxItems - 1 - r, ins.oid);
                            memcpy(b, maxItems - m, pg, maxItems - m + 1, m - r - 1);
                            memcpy(pg, maxItems - max + m - 1, pg, maxItems - max, max - m + 1);
                        }
                        else
                        {
                            memcpy(b, 0, pg, 0, m);
                            memcpy(pg, 0, pg, m, r - m);
                            memcpy(pg, r - m + 1, pg, r, max - r);
                            memcpy(b, maxItems - m, pg, maxItems - m, m);
                            memcpy(pg, maxItems - r + m, pg, maxItems - r, r - m);
                            setItem(pg, r - m, ins.key);
                            setItem(pg, maxItems - 1 - r + m, ins.oid);
                            memcpy(pg, maxItems - max + m - 1, pg, maxItems - max, max - r);
                        }
                        ins.oid = pageId;
                        if (height == 0)
                        {
                            ins.key = getItem(b, maxItems - m);
                            setnItems(pg, max - m + 1);
                            setnItems(b, m);
                        }
                        else
                        {
                            ins.key = getItem(b, m - 1);
                            setnItems(pg, max - m);
                            setnItems(b, m - 1);
                        }
                        db.pool.unfix(b);
                        return(BtreeResult.Overflow);
                    }
                }
                finally
                {
                    if (pg != null)
                    {
                        db.pool.unfix(pg);
                    }
                }
            }