/* * 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() ; } }