blob: ec07a44617f76476082b9d5e318a3248fcee17ca [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.jena.tdb.index.bplustree;
import java.util.Iterator;
import java.util.NoSuchElementException;
import org.apache.jena.atlas.lib.Pair ;
import org.apache.jena.tdb.base.buffer.PtrBuffer ;
import org.apache.jena.tdb.base.buffer.RecordBuffer ;
import org.apache.jena.tdb.base.record.Record ;
import org.apache.jena.tdb.base.record.RecordFactory ;
/** Take a stream of (block id,split record) pairs and generate B+Tree Nodes */
class BPTreeNodeBuilder implements Iterator<Pair<Integer, Record>>
{
private Pair<Integer, Record> slot ;
private Iterator<Pair<Integer, Record>> iter ;
private final BPTreeNodeMgr mgr ;
private final boolean leafLayer ;
private final RecordFactory recordFactory ;
BPTreeNodeBuilder(Iterator<Pair<Integer, Record>> iter, BPTreeNodeMgr mgr, boolean leafLayer, RecordFactory recordFactory)
{
this.iter = iter ;
this.mgr = mgr ;
this.leafLayer = leafLayer ;
this.recordFactory = recordFactory ;
}
@Override
public boolean hasNext()
{
if ( slot != null )
return true ;
if ( iter == null )
return false ;
if ( ! iter.hasNext() )
{
// Start of next block, no more input.
iter = null ;
return false ;
}
// At least one element to put in a new node.
// Unknown parent. Does not matter (parent is only in-memory)
BPTreeNode bptNode = mgr.createNode(-1) ;
bptNode.setIsLeaf(leafLayer) ;
RecordBuffer recBuff = bptNode.getRecordBuffer() ;
PtrBuffer ptrBuff = bptNode.getPtrBuffer() ;
recBuff.setSize(0) ;
ptrBuff.setSize(0) ; // Creation leaves this junk.
final boolean debug = false ;
int rMax = recBuff.maxSize() ;
int pMax = ptrBuff.maxSize() ;
if ( debug ) System.out.printf("Max: (%d, %d)\n", rMax, pMax) ;
for ( ; iter.hasNext() ; )
{
int X = bptNode.getCount() ;
int X2 = bptNode.getMaxSize() ;
int P = ptrBuff.size() ;
int P2 = ptrBuff.maxSize() ;
int R = recBuff.size() ;
int R2 = recBuff.maxSize() ;
// bptNode.getMaxSize() is drivel
//System.out.printf("N: %d/%d : P %d/%d : R %d/%d\n", X, X2, P, P2, R, R2) ;
Pair<Integer, Record> pair = iter.next() ;
if ( debug ) System.out.println("** Item: "+pair) ;
Record r = pair.cdr() ;
// [Issue: FREC]
// The record buffer size is wrong.
// Writes the whole record, only need to write the key part.
// **** r = recordFactory.createKeyOnly(r) ;
// [Issue: FREC]
// The record is key-only (which is correct) but until FREC fixed, we need key,value
r = recordFactory.create(r.getKey()) ;
// -- End FREC
// Always add - so ptrBuff is one ahead when we finish.
// There is always one more ptr than record in a B+Tree node.
if ( ptrBuff.isFull() )
System.err.println("PtrBuffer is full") ;
// Add pointer.
ptrBuff.add(pair.car()) ;
// [Issue: FREC]
// Either test should work but due to the missetting of record buffer size
// testing recBuff does not work.
//if ( recBuff.isFull() )
// .... test ptrBuff
if ( ptrBuff.isFull() )
{
// End of this block.
// Does not add to ptrBuff so the one extra slot is done.
// Instead, the high point goes to the next level up.
// Internal consistency check.
if ( ! ptrBuff.isFull() )
System.err.println("PtrBuffer is not full") ;
// The split point for the next level up.
slot = new Pair<>(bptNode.getId(), pair.cdr()) ;
if ( debug ) System.out.printf("Write(1): %d\n", bptNode.getId()) ;
if ( debug ) System.out.println(bptNode) ;
if ( debug ) System.out.println("Slot = "+slot) ;
mgr.put(bptNode) ;
// No count increment needed.
return true ;
}
recBuff.add(r) ;
bptNode.setCount(bptNode.getCount()+1) ;
}
// If we get here, the input stream ran out before we finished a complete block.
// Fix up block (remove the last record)
Record r = recBuff.getHigh() ;
recBuff.removeTop() ;
bptNode.setCount(bptNode.getCount()-1) ;
slot = new Pair<>(bptNode.getId(), r) ;
if ( debug ) System.out.printf("Write(2): %d\n", bptNode.getId()) ;
if ( debug ) System.out.println(bptNode) ;
if ( debug ) System.out.println("Slot = "+slot) ;
mgr.put(bptNode) ;
return true ;
}
@Override
public Pair<Integer, Record> next()
{
if ( ! hasNext() ) throw new NoSuchElementException() ;
Pair<Integer, Record> x = slot ;
slot = null ;
return x ;
}
@Override
public void remove()
{ throw new UnsupportedOperationException() ; }
}