org.apache.jena.tdb.index.bplustree.BPlusTreeParams Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of jena-tdb Show documentation
Show all versions of jena-tdb Show documentation
TDB is a storage subsystem for Jena and ARQ, it is a native triple store providing persistent storage of triples/quads.
/*
* 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 static org.apache.jena.tdb.sys.SystemTDB.SizeOfPointer ;
import org.apache.jena.atlas.logging.Log ;
import org.apache.jena.tdb.TDBException ;
import org.apache.jena.tdb.base.file.MetaFile ;
import org.apache.jena.tdb.base.record.RecordFactory ;
import org.apache.jena.tdb.sys.Names ;
import org.apache.jena.tdb.sys.SystemTDB ;
import org.slf4j.Logger;
/** Configuration for a B+Tree */
final
public class BPlusTreeParams
{
// Global settings
public static boolean CheckingTree = SystemTDB.Checking ; // Check on exit of B+Tree modifiying operations
public static boolean CheckingNode = false ; // Check within BPTreeNode
public static boolean CheckingConcurrency = SystemTDB.Checking ; // Check on exit of B+Tree modifiying operations
// Metadata
//public static final String NS = BPlusTreeParams.class.getName() ;
public static final String NS = Names.keyNSBPlusTree ;
public static final String ParamOrder = NS+".order" ;
public static final String ParamKeyLength = NS+".keyLength" ;
public static final String ParamValueLength = NS+".valueLength" ;
public static final String ParamBlockSize = NS+".blockSize" ;
public static void checkAll()
{
CheckingTree = true ;
CheckingNode = true ;
}
public static boolean DumpTree = false ; // Dump the tree during top level logging
public static boolean Logging = false ; // Turn on/off logging the hard way
public static void infoAll()
{
DumpTree = true ;
Logging = true ;
}
/* The gap is extra space in a node - some books have node size as 2*N
* (often for the classic insertion algorithm where it's easier to implement
* by inserting then splitting).
*/
private static final int Gap = 0 ;
public static final int RootId = 0 ;
public static final int RootParent = -2 ;
public static final int NoParent = -99 ;
// Per instance settings
/** Order of the BTree */
final int order ;
/** Record factory */
final RecordFactory recordFactory ;
/** Factory for key-only records */
final RecordFactory keyFactory ;
// ---- Derived constants.
/** Maximum number of keys per non-leaf block */
final int MaxRec ;
/** Maximum number of pointers per block per non-leaf block */
final int MaxPtr ;
/** Minimum number of keys per non-leaf block */
final int MinRec ;
/** Minimum number of pointers per block */
final int MinPtr ;
/** Index of the split point */
final int SplitIndex ;
/** High index of keys array */
final int HighRec ;
/** High index of pointers array */
final int HighPtr ;
/** Space in a block needed for extra information - the count
* The parent is not stored on-disk because a block is always created by fetching from it's parent.
*/
static int BlockHeaderSize = 4 ;
static final boolean logging(Logger log)
{
return Logging && log.isDebugEnabled() ;
}
@Override
public String toString()
{
return String.format("Order=%d : Records [key=%d, value=%d] : records=[%d,%d] : pointers=[%d,%d] : split=%d",
order,
keyFactory.keyLength() ,
recordFactory.valueLength() ,
MinRec, MaxRec,
MinPtr, MaxPtr,
SplitIndex
) ;
}
public static BPlusTreeParams readMeta(MetaFile mf)
{
try {
int pOrder = mf.getPropertyAsInteger(ParamOrder) ;
int pKeyLen = mf.getPropertyAsInteger(ParamKeyLength) ;
int pRecLen = mf.getPropertyAsInteger(ParamValueLength) ;
return new BPlusTreeParams(pOrder, pKeyLen, pRecLen) ;
} catch (NumberFormatException ex)
{
Log.error(BPlusTreeParams.class, "Badly formed metadata for B+Tree") ;
throw new TDBException("Failed to read metadata") ;
}
}
public void addToMetaData(MetaFile mf)
{
mf.setProperty(ParamOrder, order) ;
mf.setProperty(ParamKeyLength, recordFactory.keyLength()) ;
mf.setProperty(ParamValueLength, recordFactory.valueLength()) ;
mf.flush() ;
}
public BPlusTreeParams(int order, int keyLen, int valLen)
{
this(order, new RecordFactory(keyLen, valLen)) ;
}
public BPlusTreeParams(int order, RecordFactory factory)
{
// BTrees of order one aren't strictly BTrees, where the order is >= 2
// Order 1 => Min size = 0 and max size = 2*N-1 = 1.
// If there is a gap, then the code may be defensive enough
// and something will work. The B+Trees may have empty nodes
// (i.e. no keys, single child).
if ( order < 2 )
throw new IllegalArgumentException("BPTree: illegal order (min 2): "+order);
this.order = order ;
recordFactory = factory ;
keyFactory = factory.keyFactory() ;
// Derived constants.
MaxRec = 2*order-1 + Gap ;
MaxPtr = 2*order + Gap ;
MinRec = order-1 ;
MinPtr = order ;
SplitIndex = order-1+Gap;
HighPtr = MaxPtr - 1 ;
HighRec = HighPtr-1 ;
}
public int getOrder()
{
return order ;
}
public int getPtrLength()
{
return SizeOfPointer ;
}
public int getRecordLength()
{
return recordFactory.recordLength() ;
}
public RecordFactory getRecordFactory()
{
return recordFactory ;
}
public int getKeyLength()
{
return keyFactory.recordLength() ;
}
public RecordFactory getKeyFactory()
{
return keyFactory ;
}
public int getCalcBlockSize()
{
return calcBlockSize(order, recordFactory) ;
}
/** Return the best fit for the blocksize and the record length.
* Knows about block header space.
*/
public static int calcOrder(int blockSize, RecordFactory factory)
{
return calcOrder(blockSize, factory.recordLength()) ;
}
/** Return the best fit for the blocksize and the record length.
* Knows about block header space.
*/
public static int calcOrder(int blockSize, int recordLength)
{
// Length = X*recordLength+(X+1)*PtrLength
// => X = (Length-PtrLength)/(recordLength+PtrLength)
// BTree order N
// MaxRec = 2N-1+Gap = X
// N = (X+1-Gap)/2
blockSize -= BlockHeaderSize ;
int X = (blockSize-recordLength)/(recordLength+SizeOfPointer) ;
int order = (X+1-Gap)/2 ;
return order ;
}
/** return the size of a block */
public static int calcBlockSize(int bpTreeOrder, RecordFactory factory)
{
BPlusTreeParams p = new BPlusTreeParams(bpTreeOrder, factory) ;
int x = p.getMaxRec()*factory.recordLength() + p.getMaxPtr()*SizeOfPointer ;
x += BlockHeaderSize ;
return x ;
}
public int getMaxRec()
{
return MaxRec ;
}
public int getMaxPtr()
{
return MaxPtr ;
}
public int getMinRec()
{
return MinRec;
}
public int getMinPtr()
{
return MinPtr ;
}
// /** return the size of a block */
// public static int calcBlockSize(int bTreeOrder, int recordLength)
// {
// BTreeParams p = new BTreeParams(bTreeOrder, recordLength, 0) ;
// int x = p.getMaxRec()*recordLength + p.getMaxPtr()*PtrLength ;
// x += BlockHeaderSize ;
// return x ;
// }
}