/*
* 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.ByteTool;
import org.chaidb.db.index.IDBIndex;
import org.chaidb.db.index.Key;
import org.chaidb.db.index.btree.bufmgr.PageBufferManager;
import org.chaidb.db.index.btree.bufmgr.PageNumber;
import java.util.Enumeration;
import java.util.Hashtable;
/**
* This class implements Enumeration, get all keys from Id2nodeBTree.
* User: arefool
* Date: Mar 14, 2003
* Time: 3:51:31 PM
*/
public class Id2nodeBTreeEnumerator implements TreeEnumerator {
private IBTree btree;
private BTreeSpec btreeSpec;
private PageBufferManager buffer;
/**
* specify the current leaf page number
*/
private PageNumber currentPageNumber;
/**
* indicate the next node index in the leaf page
*/
private int nextNodeIndex;
/**
* KernelContext create this enumerator
*/
private KernelContext kContext;
/**
* BTree enumerator for the special tree
*/
private Enumeration beForSpecialTree;
//this is only for Special BTree, containing visited document root.
private Hashtable visitedRoot;
private Enumeration enumId2root;
public Id2nodeBTreeEnumerator() {
}
/**
* Constructor
*/
public Id2nodeBTreeEnumerator(IBTree bt, BTreeSpec btSpec, PageBufferManager buffer, KernelContext kContext) throws ChaiDBException {
initParameter(bt, btSpec, buffer, kContext);
init();
}
protected void initParameter(IBTree bt, BTreeSpec btSpec, PageBufferManager buffer, KernelContext kContext) {
setBtree(bt);
setBtreeSpec(btSpec);
this.setBuffer(buffer);
setCurrentPageNumber(new PageNumber());
this.setkContext(kContext);
}
protected void init() throws ChaiDBException {
PageNumber root = null;
root = getFirstSubTreeRoot();
setVisitedRoot(new Hashtable());
setEnumId2root(((Id2nodeBTree) getBtree()).id2root.elements());
if (root == null) {
setCurrentPageNumber(new PageNumber(getBtree().getBtreeId(), 0, -1));
return;
}
//remember visited root
getVisitedRoot().put(root, root);
TreeEnumeratorUtils.findLeftMostLeaf(this, root);
}
public boolean hasMoreElements() {
try {
while (true) {
if (getCurrentPageNumber().getPageNumber() < 0) {
//if it's special, get the next sub tree root
if (getBeForSpecialTree().hasMoreElements()) {
((Id2nodeBTree) getBtree()).indexBTree.acquire(kContext, IDBIndex.READ_MODE);
byte[] bRoot = (byte[]) ((Id2nodeBTree) getBtree()).indexBTree.lookup((Key) getBeForSpecialTree().nextElement(), getkContext());
((Id2nodeBTree) getBtree()).indexBTree.release(kContext);
PageNumber subroot = new PageNumber(ByteTool.bytesToInt(bRoot, 0, getBtreeSpec().isMsbFirst()));
subroot.setTreeId(getBtree().getBtreeId());
//remember visited root
getVisitedRoot().put(subroot, subroot);
TreeEnumeratorUtils.findLeftMostLeaf(this, subroot);
} else {
//return false;
boolean notFound = true;
while (getEnumId2root().hasMoreElements()) {
PageNumber subroot = (PageNumber) getEnumId2root().nextElement();
if (!getVisitedRoot().containsKey(subroot)) {
TreeEnumeratorUtils.findLeftMostLeaf(this, subroot);
getVisitedRoot().put(subroot, subroot);
notFound = false;
break;
}
}
if (notFound) return false;
}
}
BTreePage leafPage = new BTreePage(getBtree().getBtreeId(), getCurrentPageNumber(), getBtreeSpec(), getBuffer());
// unfix the leaf page
getBuffer().releasePage(getBtree().getBtreeId(), leafPage.pageNumber, false);
// if current node index is at the end of the page,
// and there is no successing leaf page after the current one, return false
int nodes = leafPage.getCurrNodeNumbers();
if (getNextNodeIndex() >= nodes) {
if (leafPage.nextPage.getPageNumber() > 0) setNextNodeIndex(0);
getCurrentPageNumber().setPageNumber(leafPage.nextPage);
} else return true;
}
} catch (Exception e) {
return false;
}
}
public Object nextElement() {
return TreeEnumeratorUtils.nextElement(this);
}
/**
* Get the first sub tree's root in a forest
*/
//(id2node.idb)
protected PageNumber getFirstSubTreeRoot() throws ChaiDBException {
((Id2nodeBTree) getBtree()).indexBTree.acquire(kContext, IDBIndex.READ_MODE);
setBeForSpecialTree(((Id2nodeBTree) getBtree()).indexBTree.keys(getkContext()));
((Id2nodeBTree) getBtree()).indexBTree.release(kContext);
if (getBeForSpecialTree().hasMoreElements()) {
((Id2nodeBTree) getBtree()).indexBTree.acquire(kContext, IDBIndex.READ_MODE);
byte[] bRoot = (byte[]) ((Id2nodeBTree) getBtree()).indexBTree.lookup((Key) getBeForSpecialTree().nextElement(), getkContext());
((Id2nodeBTree) getBtree()).indexBTree.release(kContext);
PageNumber subroot = new PageNumber(ByteTool.bytesToInt(bRoot, 0, getBtreeSpec().isMsbFirst()));
subroot.setTreeId(getBtree().getBtreeId());
return subroot;
}
return null;
}
public IBTree getBtree() {
return btree;
}
public void setBtree(IBTree btree) {
this.btree = btree;
}
public BTreeSpec getBtreeSpec() {
return btreeSpec;
}
public void setBtreeSpec(BTreeSpec btreeSpec) {
this.btreeSpec = btreeSpec;
}
public PageBufferManager getBuffer() {
return buffer;
}
public void setBuffer(PageBufferManager buffer) {
this.buffer = buffer;
}
public PageNumber getCurrentPageNumber() {
return currentPageNumber;
}
public void setCurrentPageNumber(PageNumber currentPageNumber) {
this.currentPageNumber = currentPageNumber;
}
public int getNextNodeIndex() {
return nextNodeIndex;
}
public void setNextNodeIndex(int nextNodeIndex) {
this.nextNodeIndex = nextNodeIndex;
}
public KernelContext getkContext() {
return kContext;
}
public void setkContext(KernelContext kContext) {
this.kContext = kContext;
}
public Enumeration getBeForSpecialTree() {
return beForSpecialTree;
}
public void setBeForSpecialTree(Enumeration beForSpecialTree) {
this.beForSpecialTree = beForSpecialTree;
}
public Hashtable getVisitedRoot() {
return visitedRoot;
}
public void setVisitedRoot(Hashtable visitedRoot) {
this.visitedRoot = visitedRoot;
}
public Enumeration getEnumId2root() {
return enumId2root;
}
public void setEnumId2root(Enumeration enumId2root) {
this.enumId2root = enumId2root;
}
}