/*
* 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.index.Key;
import org.chaidb.db.index.btree.bufmgr.PageNumber;
import java.util.NoSuchElementException;
public class SuperBTreeEnumerator implements java.util.Enumeration {
SuperBTree nBTree;
KernelContext kContext;
int[] nextNodeIndexes;
PageNumber[] currentPageNumbers;
Key[] keys;
public SuperBTreeEnumerator(SuperBTree nBTree, KernelContext kContext) throws ChaiDBException {
this.nBTree = nBTree;
this.kContext = kContext;
init();
}
private void init() throws ChaiDBException {
nextNodeIndexes = new int[nBTree.getLayers()];
currentPageNumbers = new PageNumber[nextNodeIndexes.length];
keys = new Key[nextNodeIndexes.length];
PageNumber root = new PageNumber(nBTree.getTopRoot());
resetLayers(0, root);
}
private void resetLayers(int layer, PageNumber root) throws ChaiDBException {
PageNumber tmpRoot = new PageNumber(root);
for (int i = layer; i < nextNodeIndexes.length; i++) {
BTreePage bPage = nBTree.findLeftMostLeaf(tmpRoot);
currentPageNumbers[i] = new PageNumber(bPage.getPageNumber());
if (bPage.getPage() == null) return;
nextNodeIndexes[i] = 0;
if (i < nextNodeIndexes.length - 1) {
BTreeNode node = bPage.getNode(nextNodeIndexes[i]);
tmpRoot = new PageNumber((PageNumber) nBTree.convertValue(node.getData(kContext), i));
}
bPage.release(false);
}
}
/**
* Move the node index of the specified layer
*
* @param layer
* @param bPage
* @return true if all pages in the specified layer run up. Otherwise, false.
*/
private boolean moveNextNode(int layer, BTreePage bPage) throws ChaiDBException {
nextNodeIndexes[layer]++;
if (nextNodeIndexes[layer] == bPage.getCurrNodeNumbers()) {
currentPageNumbers[layer] = bPage.nextPage;
if (bPage.nextPage.getPageInFile() != BTreeSpec.INVALID_PAGENO) {
bPage.release(false);
bPage = new BTreePage(nBTree.getBtreeId(), currentPageNumbers[layer], nBTree.btreeSpec, nBTree.getBuffer());
nextNodeIndexes[layer] = 0;
} else return true;
}
//reset the underlying btree
if (layer < nextNodeIndexes.length - 1) {
BTreeNode node = bPage.getNode(nextNodeIndexes[layer]);
PageNumber root = (PageNumber) (nBTree.convertValue(node.getData(kContext), layer));
resetLayers(layer + 1, root);
}
return false;
}
public Object nextElement() {
boolean changeTree = false;
try {
for (int i = nextNodeIndexes.length - 1; i >= 0; i--) {
BTreePage bPage = new BTreePage(nBTree.getBtreeId(), currentPageNumbers[i], nBTree.btreeSpec, nBTree.getBuffer());
keys[i] = bPage.getNode(nextNodeIndexes[i]).getKey();
if (i == nextNodeIndexes.length - 1 || changeTree) changeTree = moveNextNode(i, bPage);
bPage.release(false);
}
return keys;
} catch (Exception e) {
throw new NoSuchElementException("Maybe this element is deleted by another thread");
}
}
public boolean hasMoreElements() {
return currentPageNumbers[0].getPageInFile() > BTreeSpec.INVALID_PAGENO;
}
}