/*
* 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.hbt;
import org.apache.log4j.Logger;
import org.chaidb.db.KernelContext;
import org.chaidb.db.exception.ChaiDBException;
import org.chaidb.db.index.btree.AbstractBTree;
import org.chaidb.db.index.btree.BTreeSpec;
import org.chaidb.db.index.btree.DataPage;
import org.chaidb.db.index.btree.bufmgr.PageBufferManager;
import org.chaidb.db.index.btree.bufmgr.PageNumber;
import java.util.NoSuchElementException;
public class HyperBTreeBasicIterator extends HyperBTreeIterator {
private static final Logger logger = Logger.getLogger(HyperBTreeBasicIterator.class);
/**
* The dupNextCountForTest is used to count the continuous dup_next node.
* In new implement of HyperBTree, it should never occur two or more
* continuous dup_next node.
*/
int dupNextCountForTest;
private int dupNextCountForNextNode;
public HyperBTreeBasicIterator(AbstractBTree btree, KernelContext kContext) {
super(btree, kContext);
}
public void initIterator(NodePosition firstNode) {
super.initIterator(firstNode);
_nextNode = getNextDataNode(_nextNode.nodeNextPosition);
}
public boolean hasNext() {
if (_nextNode == null || _nextNode.data == null) {
return false;
}
return true; //default template
}
public Object next() throws NoSuchElementException {
if (_nextNode == null || _nextNode.data == null) {
throw new NoSuchElementException();
}
_prevNode = _curNode;
_curNode = _nextNode;
if (!finished) {
_nextNode = getNextDataNode(_nextNode.nodeNextPosition);
} else {
_nextNode = null;
}
return _curNode.data;
}
/**
* Get next data node from a position
*
* @param nodePos
* @return next data node
*/
protected NodeInfo getNextDataNode(NodePosition nodePos) {
if (finished) {
return null;
}
int id = btree.getBtreeId();
final PageBufferManager buffer = btree.getBuffer();
final BTreeSpec btreeSpec = btree.getBTreeSpec();
dupNextCountForTest = dupNextCountForNextNode;
dupNextCountForNextNode = 0;
int curPageNo = nodePos.getPageNo();
PageNumber dupPageNumber = new PageNumber(curPageNo);
try {
DataPage dupDataPage = new DataPage(id, dupPageNumber, btreeSpec, buffer);
NodeInfo node = new NodeInfo();
node.nodePosition = nodePos;
while (true) {
int ret = getNode(dupDataPage, node);
if ((ret & DUP_FINISHED) == DUP_FINISHED) {
finished = true;
if ((ret & DUP_NEXT) == DUP_NEXT) {
break;
}
}
if ((ret & DUP_DATA) == DUP_DATA) {
return node;
} else if ((ret & DUP_NEXT) == DUP_NEXT) {
node.nodePosition = node.nodeNextPosition;
if (node.nodeNextPosition.getPageNo() != curPageNo) {
curPageNo = node.nodeNextPosition.getPageNo();
buffer.releasePage(id, dupPageNumber, false);
dupPageNumber = new PageNumber(curPageNo);
dupDataPage = new DataPage(id, dupPageNumber, btreeSpec, buffer);
}
} else {
logger.error("Failed to get next dup node.");
break;
}
}
} catch (ChaiDBException e) {
logger.error(e);
} finally {
buffer.releasePage(id, dupPageNumber, false);
}
return null;
}
}