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