Package org.chaidb.db.index.btree

Source Code of org.chaidb.db.index.btree.BTreeSpec

/*
* Copyright (C) 2006  http://www.chaidb.org
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU General Public License for more details.
*
*/
package org.chaidb.db.index.btree;

import org.chaidb.db.KernelContext;
import org.chaidb.db.exception.ChaiDBException;
import org.chaidb.db.helper.Config;
import org.chaidb.db.index.btree.bufmgr.PageBufferManager;
import org.chaidb.db.index.btree.bufmgr.PageNumber;
import org.chaidb.db.log.logrecord.BTreeSpecLogRecord;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;

/**
* The class contains the config information needed to build a btree.
*
* @version 1.0
*/
public class BTreeSpec {
    //    private static final boolean DEBUG_FLAG = false;

    //storage config info
    //    public static final int MAX_FILESIZE_IN_PAGE = DEBUG_FLAG ? 0x100 : 0x80000;//0x1000;
    public static final int INIT_FILESIZE_IN_PAGE = 0x10;
    public static final int INCREASE_FILESIZE_IN_PAGE = 0x10;

    /**
     * To make page size configurable.
     * TODO make a seperate control file to store page size
     */
    public static final int PAGE_SIZE = 512 * Config.getConfigAsInt("chaidb.db.pagesize", 8);

    /* Remove final key word by ben at Aug, 05, 2002 for supporting modification. */
    public static int NODE_SIZE = 20;

    private int pageSize = PAGE_SIZE;

    //SuperBTree flag.
    public byte treeType;
    public static final byte NORMAL = 0;
    public static final byte SUPER_BTREE = 2;

    /** The maximum leaf node size */
    //    private int leafNodeSize = 20; // 9+8+40
    /**
     * internal page order
     */
    private short internalOrder = (short) ((PAGE_SIZE - PAGE_HEADER_SIZE) / 22);
    /**
     * The maximum internal node size
     */
    private int internalNodeSize = 20; // 9+8

//    private int keySize = 8; // most likely id
//    private int dataSize = 480; // most likely list of ids, 5*8 = 40

    /**
     * the number of layer of BTree, default value is 1.
     * Normal BTree is 1. Id2node is 2. SuperBTree is 3.
     */
    private byte layers = 1;

    /**
     * page structure
     * <P><B>Header:</B> A BTREE page has the following metadata:</P>
     * <PRE>
     * Size  Description
     * 4     Number of this page
     * 4     Page number of preceding page
     * 4     Page number of following page
     * 3     Doc id of this page
     * 1     Key type of this page
     * 4     Reserved 4 bytes
     * 4     Flags:
     * 2     Lower bound of free space on page
     * 2     Upper bound of free space on page
     * </PRE>
     */
    public static final int PAGENUMBER_BYTE_SIZE = 4;//added by marriane 2001-11-28,for specail page for saving freelist
    public static final int OFF_PAGENUMBER = 0;
    public static final int OFF_PREVPAGE = OFF_PAGENUMBER + PAGENUMBER_BYTE_SIZE;
    public static final int OFF_NEXTPAGE = OFF_PREVPAGE + PAGENUMBER_BYTE_SIZE;
    public static final int OFF_DOCID = OFF_NEXTPAGE + PAGENUMBER_BYTE_SIZE;
    //keyType is only one byte
    public static final int OFF_KEYTYPE = OFF_DOCID + 3;
    public static final int OFF_RESERVED = OFF_KEYTYPE + 1;
    public static final int OFF_FLAGS = OFF_RESERVED + 4;
    public static final int OFF_LOWERBOUND = OFF_FLAGS + 4;
    public static final int OFF_UPPERBOUND = OFF_LOWERBOUND + 2;
    public static final int PAGE_HEADER_SIZE = OFF_UPPERBOUND + 2 - OFF_PAGENUMBER;

    /**
     * node structure
     * <P>Each node has the following format:
     * <pre>
     * Size  Description
     *  4    Key Size
     *  4    Page Number for internal nodes, as well as for Leaf nodes
     *  1    Flags: 0x01 for overflow data, 0x02 for overflow key
     *  2    Node offset in DataPage of data nodes pointed by Leaf nodes.
     *       Or space allocated for data nodes.
     *  n    Key
     * </pre>
     */
    public static final int NODE_OFF_KEYSIZE = 0;
    public static final int NODE_OFF_PAGENUMBER = NODE_OFF_KEYSIZE + 4;
    public static final int NODE_OFF_FLAGS = NODE_OFF_PAGENUMBER + 4;
    public static final int NODE_OFF_DATANODEOFFSET = NODE_OFF_FLAGS + 1;
    public static final int NODE_HEADER_SIZE = NODE_OFF_DATANODEOFFSET + 2 - NODE_OFF_KEYSIZE;

    /** constants for data node only
     *  may need to be in a separate spec file later
     */
//    public static final int DATA_NODE_OFF_PAGENUMBER = 0;
//    public static final int DATA_NODE_OFF_FLAGS = DATA_NODE_OFF_PAGENUMBER + 4;
//    public static final int DATA_NODE_OFF_ALLOCATED_SPACE = DATA_NODE_OFF_FLAGS+1; //NODE_OFF_FLAGS + 1;
    //    public static final int DATA_NODE_HEADER_SIZE = DATA_NODE_OFF_ALLOCATED_SPACE + 2-DATA_NODE_OFF_PAGENUMBER;
    /**
     * <P>Each data node has the following format:
     * <pre>
     * Size  Description
     *  4    Data Size
     *  1    Flags:
     *         0x01 for overflow data
     *         0x02 for overflow key
     *         0x04 for duplicated data
     *         0x08 for duplicated data pointer
     *  2    Space allocated for this node within the page
     *  n    Data
     * </pre>
     */
    public static final int DATA_NODE_OFF_DATASIZE = 0;
    public static final int DATA_NODE_OFF_FLAGS = DATA_NODE_OFF_DATASIZE + 4;
    public static final int DATA_NODE_OFF_ALLOCATED_SPACE = DATA_NODE_OFF_FLAGS + 1;
    public static final int DATA_NODE_HEADER_SIZE = DATA_NODE_OFF_ALLOCATED_SPACE + 2 - DATA_NODE_OFF_DATASIZE;
    /**
     * Data node flags
     */
    public static final byte DATA_NODE_NORMAL = 0;
    public static final byte DATA_NODE_OVERFLOW_NODE = 1;
    public static final byte DATA_NODE_OVERFLOW_KEY = 2;
    public static final byte DATA_NODE_DUP = 4;
    public static final byte DATA_NODE_DUP_NEXT = 8;

    /**
     * msb or lsb
     */
    private boolean msbFirst = true;

    public static final int INVALID_PAGENO = -1;
    /**
     * first available page number, retrieve / store in btree first page
     */
    private PageNumber pageNumber = new PageNumber(0, 0, 1);
    /**
     * root page number
     */
    private PageNumber rootPageNumber = new PageNumber(INVALID_PAGENO);

    public PageBufferManager bufferManager = PageBufferManager.getInstance();

    private boolean modified;

    public IBTree btree; //reference to btree

    public int getPageSize() {
        //return pageSize;
        return PAGE_SIZE;

    }

    public boolean getMsbFirst() {
        return isMsbFirst();
    }

    public PageNumber getPageNumber() {
        return pageNumber;
    }

    public PageNumber getRootPageNumber() {
        return new PageNumber(rootPageNumber);
    }

    public void setRootPageNumber(PageNumber rootPageNumber) {
        this.rootPageNumber.setPageNumber(rootPageNumber);
    }

    public void setRootPageNumber(int pn) {
        this.rootPageNumber.setPageNumber(pn);
    }

    public void setBtree(IBTree tree) {
        btree = tree;
        setTreeId(tree.getBtreeId());
    }

    /**
     * Get name of current opened btree
     */
    public String getBtreeName() {
        return btree.getBTreeName();
    }

    public void setNodeOrder(short nodeOrder) {
        internalOrder = nodeOrder;
    }

    public void setNodeSize(int nodeSize) {
        internalNodeSize = (nodeSize < 15) ? 15 : nodeSize;
        internalNodeSize = (nodeSize >= 200) ? 200 : internalNodeSize;
//        leafNodeSize = internalNodeSize;
        NODE_SIZE = internalNodeSize;
        internalOrder = (short) ((pageSize - PAGE_HEADER_SIZE) / (internalNodeSize + 2));
//        leafOrder = internalOrder;
    }

    public short getNodeOrder() {
        return internalOrder;
    }

    public int getNodeSize() {
        /* modified by ben at Aug, 05, 2002 to fit the demand of flexible node size. */
        return internalNodeSize;


    }

    public short getLeafOrder() {
        return getNodeOrder();
    }

    public short getInternalOrder() {
        return getNodeOrder();
    }

    public int getLeafNodeSize() {
        return getNodeSize();
    }

    public int getInternalNodeSize() {
        return getNodeSize();
    }

    /**
     * writes serialized form of the BTreeSpec object
     *
     * @param s The output stream
     * @throws IOException Exception while writing serialized form
     */
    public void writeObject(DataOutputStream s) throws IOException {
        // The format in which this object is serialized is :
        // - pageSize (int)
        // - bufferSize (int)
        // - internalNodeSize (int)
        // - internalOrder (short)
        s.writeInt(pageSize);
        s.writeInt(internalNodeSize);
        s.writeShort(internalOrder);
    }

    /**
     * reads a serialized BTreeSpec object from the given ObjectInputStream
     *
     * @param s The ObjectInputStream from which the BTreeSpec object is to
     *          *    be loaded
     * @throws IOException Exception while deserializing the meta data
     *                     *    object
     */
    public void readObject(DataInputStream s) throws IOException {
        pageSize = s.readInt();
        internalNodeSize = s.readInt();
        internalOrder = s.readShort();
    }

    public void setTreeId(int id) {
        pageNumber.setTreeId(id);
        rootPageNumber.setTreeId(id);
    }


    /**
     * Expand a new page for this btree.
     *
     * @param kc
     * @return old page number
     * @throws ChaiDBException author leon 2002-6-20
     */
    //called by BufferedPage.getFreePage
    public PageNumber expandANewPage(KernelContext kc) throws ChaiDBException {
        synchronized (pageNumber) {
            return _expandANewPage(kc);
        }
    }

//    private LinkedList newPageFIFO = new LinkedList();

    private PageNumber _expandANewPage(KernelContext kc) throws ChaiDBException {
//        if (newPageFIFO.size() != 0) {
//            PageNumber oldPageNumber = new PageNumber(pageNumber);
//            pageNumber.setPageNumber((PageNumber) newPageFIFO.removeFirst());
//            return oldPageNumber;
//        }
//
//        PageNumber currentPageNumber = pageNumber;
//        int count = 10;
//        while (count > 0) {
//            PageNumber newPage = new PageNumber(currentPageNumber);
//            newPage.add(1);
//
//            if (kc != null && kc.getNeedLog()) {
//                BTreeSpecLogRecord logRec = new BTreeSpecLogRecord(
//                        btree.getBtreeId(),
//                        currentPageNumber.getPageNumber(),
//                        newPage.getPageNumber(),
//                        BTreeSpecLogRecord.PAGE_NUMBER_FLAG,
//                        kc.getLocker(),
//                        btree.getType());
//                logRec.log();
//            }
//
//            newPageFIFO.addLast(newPage);
//            currentPageNumber = newPage;
//            count--;
//        }
//
//        PageNumber oldPageNumber = new PageNumber(pageNumber);
//        pageNumber.setPageNumber((PageNumber) newPageFIFO.removeFirst());
//        return oldPageNumber;
        PageNumber p = null;
        PageNumber oldPageNumber = new PageNumber(pageNumber);

        //add by Stanley
        // if current directory does not have the file we will jump to next file
        //whose file number is one more than previous one
        if (!bufferManager.checkTreeExistinCurrentDir(btree.getBtreeId(), oldPageNumber.getFileNumber())) {
            oldPageNumber.jumpToNextFile();
            bufferManager.addVirtualFile(btree.getBtreeId(), oldPageNumber.getFileNumber());
        }

        p = new PageNumber(oldPageNumber);
        p.add(1);
        if (kc != null && kc.getNeedLog()) {
            BTreeSpecLogRecord logRec = new BTreeSpecLogRecord(btree.getBtreeId(), pageNumber.getPageNumber(), p.getPageNumber(), BTreeSpecLogRecord.PAGE_NUMBER_FLAG, kc.getLocker(), btree.getType());
            logRec.log();
        }
        pageNumber.setPageNumber(p);
        return oldPageNumber;
    }


    /**
     * Changes the node size. Be sure to call it before btree.open
     *
     * @param nodeSize The new node size.
     * @param kc       The kernel context.
     * @throws ChaiDBException
     */
    public void changeNodeSize(int nodeSize, KernelContext kc) throws ChaiDBException {
        if (btree == null) return;
        /* whether exist leak here, if btree is created and change
          node size after the first btree.open before operation, it is no problem.
          but if btree is already created, and reopen (e.g. create index, shut down sever, and restart server)
          I'd prefer to control it at upper level, createIndex
        */

        if (kc != null && kc.getNeedLog()) {
            BTreeSpecLogRecord logRec = new BTreeSpecLogRecord(btree.getBtreeId(), internalNodeSize, nodeSize, BTreeSpecLogRecord.NODE_SIZE_FLAG, kc.getLocker(), btree.getType());
            logRec.log();
        }
    }

    /**
     * Set layer of a BTree. This is only called when this BTree is firstly created!
     * Anyone calls this method must guaranteen it!
     *
     * @param layers range (1~127).
     * @param kc
     * @throws ChaiDBException
     */
    public void setLayer(byte layers, KernelContext kc) throws ChaiDBException {
        if (layers > 0 && layers != this.layers) {
            if (kc != null && kc.getNeedLog()) {
                BTreeSpecLogRecord logRec = new BTreeSpecLogRecord(btree.getBtreeId(), this.layers, layers, BTreeSpecLogRecord.LAYER_FLAG, kc.getLocker(), btree.getType());
                logRec.log();
            }
            this.layers = layers;
        }
    }

    public byte getLayers() {
        return layers;
    }


    /**
     * the metadata which are stored in the first page. Set parameters in
     * BTreeSpec and BufferedPage correspondingly.
     * <br>
     * The complete list of DB BTree metadata is show below:
     * <pre>
     *  Size  Description
     *  4     Magic Value: 0x053162 (used to determine endianness)
     *  4     Version of BTREE file
     *  4     Page Size
     *  4     Next available page
     *  1     BTree layer value. .
     *  1     Key type.
     *  1     BTree type : 0, normal btree; 1, superBTree; 2, NestedBTree.
     *  1       (deserved)
     * <p/>
     *  4     Flags:
     *          0x0020 - Duplicate keys are not permitted
     *          0x0080 - R_RECNO: "record oriented tree" (??)
     *  4     Root Page Number
     *  4     node size
     *  4     Latest data page number
     *  4     Number of free pages
     *  List of free page numbers
     * <p/>
     * </pre>
     * Flags is not used at the current version.
     * Assume there are no duplicate keys.
     */

    public static final int MAGIC_OFF = 0;
    public static final int BTREEID_OFF = MAGIC_OFF + 4;
    public static final int PAGE_SIZE_OFF = BTREEID_OFF + 4;
    public static final int NEXT_AVAILABLE_PAGE_OFF = PAGE_SIZE_OFF + 4;
    public static final int LAYER_OFF = NEXT_AVAILABLE_PAGE_OFF + 4;
    public static final int FLAG_OFF = LAYER_OFF + 1;
    public static final int KEYTYPE_SPACE_RESERVED = 14;
    public static final int BTREE_TYPE_OFF = FLAG_OFF + KEYTYPE_SPACE_RESERVED;
    public static final int ROOT_OFF = BTREE_TYPE_OFF + 2;
    public static final int NODE_SIZE_OFF = ROOT_OFF + 4;
    public static final int LATEST_DATA_PAGE_LIST_OFF = NODE_SIZE_OFF + 4;
    public static final int FREE_PAGE_LIST_OFF = LATEST_DATA_PAGE_LIST_OFF + 4;

    public boolean isMsbFirst() {
        return msbFirst;
    }

    public void setMsbFirst(boolean msbFirst) {
        this.msbFirst = msbFirst;
    }

    public boolean isModified() {
        return this.modified;
    }

    public void setModified(boolean modified) {
        this.modified = modified;
    }
}
TOP

Related Classes of org.chaidb.db.index.btree.BTreeSpec

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.