BitIndexImpl.java :  » Database-DBMS » perst » org » garret » perst » impl » Java Open Source

Java Open Source » Database DBMS » perst 
perst » org » garret » perst » impl » BitIndexImpl.java
package org.garret.perst.impl;
import  org.garret.perst.*;
import  java.util.*;

class BitIndexImpl<T extends IPersistent> extends Btree<T> implements BitIndex<T> 
{ 
    BitIndexImpl() {
        super(ClassDescriptor.tpInt, true);
    }

    static class Key { 
        int key;
        int oid;

        Key(int key, int oid) { 
            this.key = key;
            this.oid = oid;
        }
    }
        
    public int get(T obj) 
    {
        StorageImpl db = (StorageImpl)getStorage();
        if (root == 0) { 
            throw new StorageError(StorageError.KEY_NOT_FOUND);
        } 
        return BitIndexPage.find(db, root, obj.getOid(), height);
    }
 
    public void put(T obj, int mask) 
    {
        StorageImpl db = (StorageImpl)getStorage();
        if (db == null) {             
            throw new StorageError(StorageError.DELETED_OBJECT);
        }
        if (!obj.isPersistent()) { 
            db.makePersistent(obj);
        }
        Key ins = new Key(mask, obj.getOid());
        if (root == 0) { 
            root = BitIndexPage.allocate(db, 0, ins);
            height = 1;
        } else { 
            int result = BitIndexPage.insert(db, root, ins, height);
            if (result == op_overflow) { 
                root = BitIndexPage.allocate(db, root, ins);
                height += 1;
            }
        }
        updateCounter += 1;
        nElems += 1;
        modify();
    }

    public void remove(T obj) 
    {
        StorageImpl db = (StorageImpl)getStorage();
        if (db == null) {             
            throw new StorageError(StorageError.DELETED_OBJECT);
        }
        if (root == 0) {
            throw new StorageError(StorageError.KEY_NOT_FOUND);
        }
        int result = BitIndexPage.remove(db, root, obj.getOid(), height);
        if (result == op_not_found) { 
            throw new StorageError(StorageError.KEY_NOT_FOUND);
        }
        nElems -= 1;
        if (result == op_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();
    }
        
    class BitIndexIterator<E> extends IterableIterator<E> implements PersistentIterator 
    { 
        BitIndexIterator(int set, int clear) 
        { 
            sp = 0;
            counter = updateCounter;
            if (height == 0) { 
                return;
            }
            int pageId = root;
            StorageImpl db = (StorageImpl)getStorage();
            if (db == null) {             
                throw new StorageError(StorageError.DELETED_OBJECT);
            }
            int h = height;
            this.set = set;
            this.clear = clear;
            
            pageStack = new int[h];
            posStack = new int[h];
            
            while (true) { 
                pageStack[sp] = pageId;
                Page pg = db.getPage(pageId);
                sp += 1;
                if (--h == 0) { 
                    gotoNextItem(pg, 0);
                    break;
                }
                pageId = BitIndexPage.getItem(pg, BitIndexPage.maxItems-1);
                db.pool.unfix(pg);
            }
        }

        public boolean hasNext() 
        {
            if (counter != updateCounter) { 
                throw new ConcurrentModificationException();
            }
            return sp != 0;
        }

        public E next() 
        {
            return (E)((StorageImpl)getStorage()).lookupObject(nextOid(), null);
        }

        public int nextOid() 
        {
            if (!hasNext()) { 
                throw new NoSuchElementException();
            }
            StorageImpl db = (StorageImpl)getStorage();
            int pos = posStack[sp-1];   
            Page pg = db.getPage(pageStack[sp-1]);
            int oid = BitIndexPage.getItem(pg, BitIndexPage.maxItems-1-pos);
            gotoNextItem(pg, pos+1);
            return oid;
        }

        private final void gotoNextItem(Page pg, int pos)
        {
            StorageImpl db = (StorageImpl)getStorage();
                
            do { 
                int end = BitIndexPage.getnItems(pg); 
                while (pos < end) { 
                    int mask = BitIndexPage.getItem(pg, pos);
                    if ((set & mask) == set && (clear & mask) == 0) { 
                        posStack[sp-1] = pos;
                        db.pool.unfix(pg);
                        return;
                    }
                    pos += 1;
                }
                while (--sp != 0) { 
                    db.pool.unfix(pg);
                    pos = posStack[sp-1];
                    pg = db.getPage(pageStack[sp-1]);
                    if (++pos <= BitIndexPage.getnItems(pg)) {
                        posStack[sp-1] = pos;
                        do { 
                            int pageId = BitIndexPage.getItem(pg, BitIndexPage.maxItems-1-pos);
                            db.pool.unfix(pg);
                            pg = db.getPage(pageId);
                            pageStack[sp] = pageId;
                            posStack[sp] = pos = 0;
                        } while (++sp < pageStack.length);
                        break;
                    }
                }
            } while (sp != 0);

            db.pool.unfix(pg);
        }

        public void remove() 
        { 
            throw new UnsupportedOperationException();
        }

        int[]       pageStack;
        int[]       posStack;
        int         sp;
        int         set;
        int         clear;
        int         counter;
    }

    public Iterator<T> iterator() 
    {
        return iterator(0, 0);
    }

    public IterableIterator<T> iterator(int set, int clear) 
    { 
        return new BitIndexIterator<T>(set, clear);
    }

    static class BitIndexPage extends BtreePage { 
        static final int max = keySpace / 8;    

        static int getItem(Page pg, int index) { 
            return Bytes.unpack4(pg.data, firstKeyOffs + index*4);
        }
    
        static void setItem(Page pg, int index, int mask) { 
            Bytes.pack4(pg.data, firstKeyOffs + index*4, mask);
        }

        static int allocate(StorageImpl db, int root, Key ins) 
        {
            int pageId = db.allocatePage();
            Page pg = db.putPage(pageId);
            setnItems(pg, 1);
            setItem(pg, 0, ins.key);
            setItem(pg, maxItems-1, ins.oid);
            setItem(pg, maxItems-2, root);
            db.pool.unfix(pg);
            return pageId;
        }
        
        static void memcpy(Page dst_pg, int dst_idx, Page src_pg, int src_idx, int len) 
        { 
            System.arraycopy(src_pg.data, firstKeyOffs + src_idx*4, 
                             dst_pg.data, firstKeyOffs + dst_idx*4, 
                             len*4);
        }
        
        static int find(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) {
                        return getItem(pg, r);
                    }
                    throw new StorageError(StorageError.KEY_NOT_FOUND);                    
                } else { 
                    while (l < r)  {
                        i = (l+r) >> 1;
                        if (oid > getItem(pg, i)) { 
                            l = i+1; 
                        } else { 
                            r = i;
                        }
                    }
                    return find(db, getItem(pg, maxItems-r-1), oid, height);
                }
            } finally { 
                if (pg != null) { 
                    db.pool.unfix(pg);
                }
            }
        }

        static int 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;
                        }
                    }
                    Assert.that(l == r);
                    /* insert before e[r] */
                    int result = insert(db, getItem(pg, maxItems-r-1), ins, height);
                    Assert.that(result != op_not_found);
                    if (result != op_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 op_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 op_done;
                } else { /* page is full then divide page */
                    pageId = db.allocatePage();
                    Page b = db.putPage(pageId);
                    Assert.that(n == max);
                    int m = max/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 op_overflow;
                }
            } finally { 
                if (pg != null) { 
                    db.pool.unfix(pg);
                }
            }
        }

    
        static int handlePageUnderflow(StorageImpl db, Page pg, int r, int height)
        {
            int nItems = getnItems(pg);
            Page a = db.putPage(getItem(pg, maxItems-r-1));
            int an = getnItems(a);
            if (r < nItems) { // exists greater page
                Page b = db.getPage(getItem(pg, maxItems-r-2));
                int bn = getnItems(b); 
                Assert.that(bn >= an);
                if (height != 1) { 
                    memcpy(a, an, pg, r, 1);
                    an += 1;
                    bn += 1;
                }
                if (an+bn > max) { 
                    // reallocation of nodes between pages a and b
                    int i = bn - ((an + bn) >> 1);
                    db.pool.unfix(b);
                    b = db.putPage(getItem(pg, maxItems-r-2));
                    memcpy(a, an, b, 0, i);
                    memcpy(b, 0, b, i, bn-i);
                    memcpy(a, maxItems-an-i, b, maxItems-i, i);
                    memcpy(b, maxItems-bn+i, b, maxItems-bn, bn-i);
                    if (height != 1) { 
                        memcpy(pg, r, a, an+i-1, 1);
                    } else { 
                        memcpy(pg, r, a, maxItems-an-i, 1);
                    }
                    setnItems(b, getnItems(b) - i);
                    setnItems(a, getnItems(a) + i);
                    db.pool.unfix(a);
                    db.pool.unfix(b);
                    return op_done;
                } else { // merge page b to a  
                    memcpy(a, an, b, 0, bn);
                    memcpy(a, maxItems-an-bn, b, maxItems-bn, bn);
                    db.freePage(getItem(pg, maxItems-r-2));
                    memcpy(pg, maxItems-nItems, pg, maxItems-nItems-1, 
                           nItems - r - 1);
                    memcpy(pg, r, pg, r+1, nItems - r - 1);
                    setnItems(a, getnItems(a) + bn);
                    setnItems(pg, nItems - 1);
                    db.pool.unfix(a);
                    db.pool.unfix(b);
                    return nItems < max/2 ? op_underflow : op_done;
                }
            } else { // page b is before a
                Page b = db.getPage(getItem(pg, maxItems-r));
                int bn = getnItems(b); 
                Assert.that(bn >= an);
                if (height != 1) { 
                    an += 1;
                    bn += 1;
                }
                if (an+bn > max) { 
                    // reallocation of nodes between pages a and b
                    int i = bn - ((an + bn) >> 1);
                    db.pool.unfix(b);
                    b = db.putPage(getItem(pg, maxItems-r));
                    memcpy(a, i, a, 0, an);
                    memcpy(a, 0, b, bn-i, i);
                    memcpy(a, maxItems-an-i, a, maxItems-an, an);
                    memcpy(a, maxItems-i, b, maxItems-bn, i);
                    if (height != 1) { 
                        memcpy(a, i-1, pg, r-1, 1);
                        memcpy(pg, r-1, b, bn-i-1, 1);
                    } else { 
                        memcpy(pg, r-1, b, maxItems-bn+i, 1);
                    }
                    setnItems(b, getnItems(b) - i);
                    setnItems(a, getnItems(a) + i);
                    db.pool.unfix(a);
                    db.pool.unfix(b);
                    return op_done;
                } else { // merge page b to a
                    memcpy(a, bn, a, 0, an);
                    memcpy(a, 0, b, 0, bn);
                    memcpy(a, maxItems-an-bn, a, maxItems-an, an);
                    memcpy(a, maxItems-bn, b, maxItems-bn, bn);
                    if (height != 1) { 
                        memcpy(a, bn-1, pg, r-1, 1);
                    }
                    db.freePage(getItem(pg, maxItems-r));
                    setItem(pg, maxItems-r, getItem(pg, maxItems-r-1));
                    setnItems(a, getnItems(a) + bn);
                    setnItems(pg, nItems - 1);
                    db.pool.unfix(a);
                    db.pool.unfix(b);
                    return nItems < max/2 ? op_underflow : op_done;
                }
            }
        }
   
        static int 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/2 ? op_underflow : op_done;
                    }
                    return op_not_found;
                } else { 
                    while (l < r)  {
                        i = (l+r) >> 1;
                        if (oid > getItem(pg, i)) { 
                            l = i+1; 
                        } else { 
                            r = i;
                        }
                    }
                    int result = remove(db, getItem(pg, maxItems-r-1), oid, height);
                    if (result == op_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);
                }
            }
        }
    }
}

java2s.com  | Contact Us | Privacy Policy
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.