Return-Path: X-Original-To: apmail-directory-commits-archive@www.apache.org Delivered-To: apmail-directory-commits-archive@www.apache.org Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by minotaur.apache.org (Postfix) with SMTP id 21F1F1867E for ; Sun, 1 Nov 2015 23:01:09 +0000 (UTC) Received: (qmail 99028 invoked by uid 500); 1 Nov 2015 23:01:09 -0000 Delivered-To: apmail-directory-commits-archive@directory.apache.org Received: (qmail 98984 invoked by uid 500); 1 Nov 2015 23:01:09 -0000 Mailing-List: contact commits-help@directory.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@directory.apache.org Delivered-To: mailing list commits@directory.apache.org Received: (qmail 98975 invoked by uid 99); 1 Nov 2015 23:01:08 -0000 Received: from Unknown (HELO spamd1-us-west.apache.org) (209.188.14.142) by apache.org (qpsmtpd/0.29) with ESMTP; Sun, 01 Nov 2015 23:01:08 +0000 Received: from localhost (localhost [127.0.0.1]) by spamd1-us-west.apache.org (ASF Mail Server at spamd1-us-west.apache.org) with ESMTP id 66422C2416 for ; Sun, 1 Nov 2015 23:01:08 +0000 (UTC) X-Virus-Scanned: Debian amavisd-new at spamd1-us-west.apache.org X-Spam-Flag: NO X-Spam-Score: 1.79 X-Spam-Level: * X-Spam-Status: No, score=1.79 tagged_above=-999 required=6.31 tests=[KAM_ASCII_DIVIDERS=0.8, KAM_LAZY_DOMAIN_SECURITY=1, T_RP_MATCHES_RCVD=-0.01] autolearn=disabled Received: from mx1-eu-west.apache.org ([10.40.0.8]) by localhost (spamd1-us-west.apache.org [10.40.0.7]) (amavisd-new, port 10024) with ESMTP id Dk0Y6CqyUgq0 for ; Sun, 1 Nov 2015 23:01:03 +0000 (UTC) Received: from mailrelay1-us-west.apache.org (mailrelay1-us-west.apache.org [209.188.14.139]) by mx1-eu-west.apache.org (ASF Mail Server at mx1-eu-west.apache.org) with ESMTP id 59CA320751 for ; Sun, 1 Nov 2015 23:01:02 +0000 (UTC) Received: from svn01-us-west.apache.org (svn.apache.org [10.41.0.6]) by mailrelay1-us-west.apache.org (ASF Mail Server at mailrelay1-us-west.apache.org) with ESMTP id 984B4E0E95 for ; Sun, 1 Nov 2015 23:01:01 +0000 (UTC) Received: from svn01-us-west.apache.org (localhost [127.0.0.1]) by svn01-us-west.apache.org (ASF Mail Server at svn01-us-west.apache.org) with ESMTP id 961BB3A0473 for ; Sun, 1 Nov 2015 23:01:01 +0000 (UTC) Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: svn commit: r1711861 [3/4] - in /directory/mavibot/branches/single-value/mavibot/src: main/java/org/apache/directory/mavibot/btree/ main/java/org/apache/directory/mavibot/btree/exception/ test/java/org/apache/directory/mavibot/btree/ Date: Sun, 01 Nov 2015 23:01:01 -0000 To: commits@directory.apache.org From: elecharny@apache.org X-Mailer: svnmailer-1.0.9 Message-Id: <20151101230101.961BB3A0473@svn01-us-west.apache.org> Modified: directory/mavibot/branches/single-value/mavibot/src/main/java/org/apache/directory/mavibot/btree/RecordManager.java URL: http://svn.apache.org/viewvc/directory/mavibot/branches/single-value/mavibot/src/main/java/org/apache/directory/mavibot/btree/RecordManager.java?rev=1711861&r1=1711860&r2=1711861&view=diff ============================================================================== --- directory/mavibot/branches/single-value/mavibot/src/main/java/org/apache/directory/mavibot/btree/RecordManager.java (original) +++ directory/mavibot/branches/single-value/mavibot/src/main/java/org/apache/directory/mavibot/btree/RecordManager.java Sun Nov 1 23:01:00 2015 @@ -26,6 +26,7 @@ import java.io.RandomAccessFile; import java.nio.ByteBuffer; import java.nio.channels.FileChannel; import java.util.ArrayList; +import java.util.Collection; import java.util.HashMap; import java.util.HashSet; import java.util.LinkedHashMap; @@ -41,6 +42,7 @@ import java.util.concurrent.locks.Reentr import org.apache.directory.mavibot.btree.exception.BTreeAlreadyManagedException; import org.apache.directory.mavibot.btree.exception.BTreeCreationException; +import org.apache.directory.mavibot.btree.exception.CursorException; import org.apache.directory.mavibot.btree.exception.EndOfFileExceededException; import org.apache.directory.mavibot.btree.exception.FileException; import org.apache.directory.mavibot.btree.exception.InvalidOffsetException; @@ -98,9 +100,6 @@ public class RecordManager extends Abstr public AtomicLong nbUpdateBtreeHeader = new AtomicLong( 0 ); public AtomicLong nbUpdatePageIOs = new AtomicLong( 0 ); - /** The offset of the end of the file */ - private long endOfFileOffset; - /** * A B-tree used to manage the page that has been copied in a new version. * Those pages can be reclaimed when the associated version is dead. @@ -224,6 +223,9 @@ public class RecordManager extends Abstr private boolean disableReclaimer = false; public Map writeCounter = new HashMap(); + + /** The transaction context */ + private TransactionContext context; /** @@ -281,9 +283,6 @@ public class RecordManager extends Abstr RandomAccessFile randomFile = new RandomAccessFile( file, "rw" ); fileChannel = randomFile.getChannel(); - // get the current end of file offset - endOfFileOffset = fileChannel.size(); - if ( isNewFile ) { initRecordManager(); @@ -322,6 +321,7 @@ public class RecordManager extends Abstr reclaimer.reclaim(); // must update the headers after reclaim operation updateRecordManagerHeader(); + writeRecordManagerHeader(); } catch ( Exception e ) { @@ -395,9 +395,7 @@ public class RecordManager extends Abstr currentBtreeOfBtreesOffset = NO_PAGE; updateRecordManagerHeader(); - - // Set the offset of the end of the file - endOfFileOffset = fileChannel.size(); + writeRecordManagerHeader(); // First, create the btree of btrees createBtreeOfBtrees(); @@ -408,11 +406,11 @@ public class RecordManager extends Abstr // Inject these B-trees into the RecordManager. They are internal B-trees. try { - manageSubBtree( btreeOfBtrees ); + beginTransaction(); + writeManagementTree( btreeOfBtrees ); currentBtreeOfBtreesOffset = ( ( PersistedBTree ) btreeOfBtrees ).getBtreeHeader() .getBTreeHeaderOffset(); - updateRecordManagerHeader(); // Inject the BtreeOfBtrees into the currentBtreeHeaders map currentBTreeHeaders.put( BTREE_OF_BTREES_NAME, @@ -420,18 +418,20 @@ public class RecordManager extends Abstr newBTreeHeaders.put( BTREE_OF_BTREES_NAME, ( ( PersistedBTree ) btreeOfBtrees ).getBtreeHeader() ); - // The FreePage B-tree - manageSubBtree( copiedPageBtree ); + // The Copied Pages B-tree + writeManagementTree( copiedPageBtree ); currentCopiedPagesBtreeOffset = ( ( PersistedBTree ) copiedPageBtree ) .getBtreeHeader().getBTreeHeaderOffset(); - updateRecordManagerHeader(); // Inject the CopiedPagesBTree into the currentBtreeHeaders map currentBTreeHeaders.put( COPIED_PAGE_BTREE_NAME, ( ( PersistedBTree ) copiedPageBtree ).getBtreeHeader() ); newBTreeHeaders.put( COPIED_PAGE_BTREE_NAME, ( ( PersistedBTree ) copiedPageBtree ).getBtreeHeader() ); + + // And finally, commit the transaction + commit(); } catch ( BTreeAlreadyManagedException btame ) { @@ -488,9 +488,10 @@ public class RecordManager extends Abstr * @throws NoSuchFieldException * @throws SecurityException * @throws IllegalArgumentException + * @throws CursorException */ private void loadRecordManager() throws IOException, ClassNotFoundException, IllegalAccessException, - InstantiationException, IllegalArgumentException, SecurityException, NoSuchFieldException, KeyNotFoundException + InstantiationException, IllegalArgumentException, SecurityException, NoSuchFieldException, KeyNotFoundException, CursorException { if ( fileChannel.size() != 0 ) { @@ -608,9 +609,6 @@ public class RecordManager extends Abstr // Add the btree into the map of managed B-trees managedBtrees.put( btreeName, ( BTree ) btree ); } - - // We are done ! Let's finish with the last initialization parts - endOfFileOffset = fileChannel.size(); } } @@ -637,6 +635,19 @@ public class RecordManager extends Abstr TXN_LOG.debug( "..o The current thread already holds the lock" ); } + // Create the context + try + { + context = new TransactionContext( fileChannel.size() ); + } + catch ( IOException ioe ) + { + String name = Thread.currentThread().getName(); + String err = "This thread, '" + name + "' cannot get the file size "; + TXN_LOG.error( err ); + throw new RecordManagerException( err ); + } + // Now, check the TLS state incrementTxnLevel(); } @@ -688,9 +699,22 @@ public class RecordManager extends Abstr return; case 1: + // First, write all the pageIos that are present in the context + Collection walObjects = context.getPages(); + + try + { + flushObjects( walObjects ); + } + catch ( IOException ioe ) + { + + } + // We are done with the transaction, we can update the RMHeader and swap the BTreeHeaders // First update the RMHeader to be sure that we have a way to restore from a crash updateRecordManagerHeader(); + writeRecordManagerHeader(); // Swap the BtreeHeaders maps swapCurrentBtreeHeaders(); @@ -715,6 +739,7 @@ public class RecordManager extends Abstr // And update the RMHeader again, removing the old references to BOB and CPB b-tree headers // here, we have to erase the old references to keep only the new ones. updateRecordManagerHeader(); + writeRecordManagerHeader(); commitCount++; @@ -961,7 +986,7 @@ public class RecordManager extends Abstr */ /* no qualifier */void checkOffset( long offset ) { - if ( ( offset < 0 ) || ( offset > endOfFileOffset ) || ( ( offset % pageSize ) != 0 ) ) + if ( ( offset < 0 ) || ( offset > context.getLastOffset() ) || ( ( offset % pageSize ) != 0 ) ) { throw new InvalidOffsetException( "Bad Offset : " + offset ); } @@ -1077,10 +1102,6 @@ public class RecordManager extends Abstr BTreeFactory.setValueSerializer( btree, valueSerializerFqcn ); // The B-tree allowDuplicates flag - int allowDuplicates = readInt( infoPageIos, dataPos ); - ( ( PersistedBTree ) btree ).setAllowDuplicates( allowDuplicates != 0 ); - dataPos += INT_SIZE; - // Set the recordManager in the btree ( ( PersistedBTree ) btree ).setRecordManager( this ); @@ -1193,43 +1214,23 @@ public class RecordManager extends Abstr leaf.setLastOffset( pageIos[pageIos.length - 1].getOffset() ); int[] keyLengths = new int[nbElems]; - int[] valueLengths = new int[nbElems]; - - boolean isNotSubTree = ( btree.getType() != BTreeTypeEnum.PERSISTED_SUB ); + int valueLength = 0; // Read each key and value for ( int i = 0; i < nbElems; i++ ) { - if ( isNotSubTree ) - { - // Read the number of values - int nbValues = byteBuffer.getInt(); - PersistedValueHolder valueHolder = null; + // Read the number of values + PersistedValueHolder valueHolder = null; - if ( nbValues < 0 ) - { - // This is a sub-btree - byte[] btreeOffsetBytes = new byte[LONG_SIZE]; - byteBuffer.get( btreeOffsetBytes ); + // Read the value's length + valueLength = byteBuffer.getInt(); - // Create the valueHolder. As the number of values is negative, we have to switch - // to a positive value but as we start at -1 for 0 value, add 1. - valueHolder = new PersistedValueHolder( btree, 1 - nbValues, btreeOffsetBytes ); - } - else - { - // This is an array - // Read the value's array length - valueLengths[i] = byteBuffer.getInt(); + // This is a value, read the byte[] associated with it + byte[] valuBytes = new byte[valueLength]; + byteBuffer.get( valuBytes ); + valueHolder = new PersistedValueHolder( btree, valuBytes ); - // This is an Array of values, read the byte[] associated with it - byte[] arrayBytes = new byte[valueLengths[i]]; - byteBuffer.get( arrayBytes ); - valueHolder = new PersistedValueHolder( btree, nbValues, arrayBytes ); - } - - BTreeFactory.setValue( btree, leaf, i, valueHolder ); - } + BTreeFactory.setValue( btree, leaf, i, valueHolder ); keyLengths[i] = byteBuffer.getInt(); byte[] data = new byte[keyLengths[i]]; @@ -1548,6 +1549,20 @@ public class RecordManager extends Abstr return value; } + + private BTreeInfo createBtreeInfo( BTree btree ) + { + BTreeInfo btreeInfo = new BTreeInfo(); + + btreeInfo.setBtree( btree ); + btreeInfo.setPageSize( btree.getPageSize() ); + btreeInfo.setBtreeName( btree.getName() ); + btreeInfo.setKeySerializer( btree.getKeySerializerFQCN() ); + btreeInfo.setValueSerializer( btree.getValueSerializerFQCN() ); + + return btreeInfo; + } + /** * Manage a B-tree. The btree will be added and managed by this RecordManager. We will create a @@ -1582,29 +1597,27 @@ public class RecordManager extends Abstr throw new BTreeAlreadyManagedException( name ); } - // Now, write the B-tree informations - long btreeInfoOffset = writeBtreeInfo( btree ); + // Get the B-tree header offset + PageIO[] btreeHeaderPageIos = getFreePageIOs( 0 ); + long btreeHeaderOffset = btreeHeaderPageIos[0].getOffset(); BTreeHeader btreeHeader = ( ( AbstractBTree ) btree ).getBtreeHeader(); + ( ( PersistedBTree ) btree ).setBtreeHeaderOffset( btreeHeaderOffset ); + context.addPage( btreeHeaderOffset, btreeHeader ); + + // Get the B-tree info offset + BTreeInfo btreeInfo = createBtreeInfo( btree ); + PageIO[] btreeInfoPageIos = getFreePageIOs( 0 ); + long btreeInfoOffset = btreeInfoPageIos[0].getOffset(); ( ( PersistedBTree ) btree ).setBtreeInfoOffset( btreeInfoOffset ); + context.addPage( btreeInfoOffset, btreeInfo ); - // Serialize the B-tree root page + // Get the B-tree root page offset Page rootPage = btreeHeader.getRootPage(); - - PageIO[] rootPageIos = serializePage( btree, btreeHeader.getRevision(), rootPage ); - - // Get the reference on the first page + PageIO[] rootPageIos = getFreePageIOs( 0 ); long rootPageOffset = rootPageIos[0].getOffset(); - - // Store the rootPageOffset into the Btree header and into the rootPage btreeHeader.setRootPageOffset( rootPageOffset ); ( ( PersistedLeaf ) rootPage ).setOffset( rootPageOffset ); - LOG.debug( "Flushing the newly managed '{}' btree rootpage", btree.getName() ); - flushPages( rootPageIos ); - - // And the B-tree header - long btreeHeaderOffset = writeBtreeHeader( btree, btreeHeader ); - // Now, if this is a new B-tree, add it to the B-tree of B-trees // Add the btree into the map of managed B-trees managedBtrees.put( name, ( BTree ) btree ); @@ -1620,7 +1633,8 @@ public class RecordManager extends Abstr NameRevision nameRevision = new NameRevision( name, 0L ); // Inject it into the B-tree of B-tree - btreeOfBtrees.insert( nameRevision, btreeHeaderOffset ); + btreeOfBtrees.insert( nameRevision, btreeHeader.getId() ); + commit(); } catch ( IOException ioe ) @@ -1632,9 +1646,81 @@ public class RecordManager extends Abstr /** - * Managing a btree is a matter of storing an reference to the managed B-tree in the B-tree Of B-trees. - * We store a tuple of NameRevision (where revision is 0L) and a offset to the B-tree header. - * At the same time, we keep a track of the managed B-trees in a Map. + * Write the B-tree informations on disk. We will write the following informations : + *
+     * +------------+
+     * | pageSize   | The B-tree page size (ie, the number of elements per page max)
+     * +------------+
+     * | nameSize   | The B-tree name size
+     * +------------+
+     * | name       | The B-tree name
+     * +------------+
+     * | keySerSize | The keySerializer FQCN size
+     * +------------+
+     * | keySerFQCN | The keySerializer FQCN
+     * +------------+
+     * | valSerSize | The Value serializer FQCN size
+     * +------------+
+     * | valSerKQCN | The valueSerializer FQCN
+     * +------------+
+     * 
+ * @param btree The B-tree which header has to be written + * @return The B-tree header offset + * @throws IOException If we weren't able to write the B-tree header + */ + private long writeBtreeInfo( BTree btree ) throws IOException + { + // We will add the newly managed B-tree at the end of the header. + byte[] btreeNameBytes = Strings.getBytesUtf8( btree.getName() ); + byte[] keySerializerBytes = Strings.getBytesUtf8( btree.getKeySerializerFQCN() ); + byte[] valueSerializerBytes = Strings.getBytesUtf8( btree.getValueSerializerFQCN() ); + + int bufferSize = + INT_SIZE + // The page size + INT_SIZE + // The name size + btreeNameBytes.length + // The name + INT_SIZE + // The keySerializerBytes size + keySerializerBytes.length + // The keySerializerBytes + INT_SIZE + // The valueSerializerBytes size + valueSerializerBytes.length; // The valueSerializerBytes + + // Get the pageIOs we need to store the data. We may need more than one. + PageIO[] btreeHeaderPageIos = getFreePageIOs( bufferSize ); + + // Keep the B-tree header Offset into the B-tree + long btreeInfoOffset = btreeHeaderPageIos[0].getOffset(); + + // Now store the B-tree information data in the pages : + // - the B-tree page size + // - the B-tree name + // - the keySerializer FQCN + // - the valueSerializer FQCN + // Starts at 0 + long position = 0L; + + // The B-tree page size + position = store( position, btree.getPageSize(), btreeHeaderPageIos ); + + // The tree name + position = store( position, btreeNameBytes, btreeHeaderPageIos ); + + // The keySerializer FQCN + position = store( position, keySerializerBytes, btreeHeaderPageIos ); + + // The valueSerialier FQCN + position = store( position, valueSerializerBytes, btreeHeaderPageIos ); + + // And flush the pages to disk now + LOG.debug( "Flushing the newly managed '{}' btree header", btree.getName() ); + flushPages( btreeHeaderPageIos ); + + return btreeInfoOffset; + } + + + /** + * Write the management BTrees (BOB and CPB). There are special BTrees, we can write them on disk immediately + * (this is done only once anyway : when we create the RecordManager). * * @param btree The new B-tree to manage. * @param treeType flag indicating if this is an internal tree @@ -1642,7 +1728,7 @@ public class RecordManager extends Abstr * @throws BTreeAlreadyManagedException If the B-tree is already managed * @throws IOException */ - public synchronized void manageSubBtree( BTree btree ) + private synchronized void writeManagementTree( BTree btree ) throws BTreeAlreadyManagedException, IOException { LOG.debug( "Managing the sub-btree {}", btree.getName() ); @@ -1650,13 +1736,6 @@ public class RecordManager extends Abstr String name = btree.getName(); - if ( managedBtrees.containsKey( name ) ) - { - // There is already a subB-tree with this name in the recordManager... - LOG.error( "There is already a sub-B-tree named '{}' managed by this recordManager", name ); - throw new BTreeAlreadyManagedException( name ); - } - // Now, write the subB-tree informations long btreeInfoOffset = writeBtreeInfo( btree ); BTreeHeader btreeHeader = ( ( AbstractBTree ) btree ).getBtreeHeader(); @@ -1666,7 +1745,7 @@ public class RecordManager extends Abstr Page rootPage = btreeHeader.getRootPage(); PageIO[] rootPageIos = serializePage( btree, btreeHeader.getRevision(), rootPage ); - + // Get the reference on the first page long rootPageOffset = rootPageIos[0].getOffset(); @@ -1678,37 +1757,9 @@ public class RecordManager extends Abstr LOG.debug( "Flushing the newly managed '{}' btree rootpage", btree.getName() ); flushPages( rootPageIos ); - // And the B-tree header - long btreeHeaderOffset = writeBtreeHeader( btree, btreeHeader ); - - // Now, if this is a new B-tree, add it to the B-tree of B-trees - // Add the btree into the map of managed B-trees - if ( ( btree.getType() != BTreeTypeEnum.BTREE_OF_BTREES ) && - ( btree.getType() != BTreeTypeEnum.COPIED_PAGES_BTREE ) && - ( btree.getType() != BTreeTypeEnum.PERSISTED_SUB ) ) - { - managedBtrees.put( name, ( BTree ) btree ); - } - - // And in the Map of currentBtreeHeaders and newBtreeHeaders + // Now, if this is a new B-tree, add it t // And in the Map of currentBtreeHeaders and newBtreeHeaders currentBTreeHeaders.put( name, btreeHeader ); newBTreeHeaders.put( name, btreeHeader ); - - // Create the new NameRevision - NameRevision nameRevision = new NameRevision( name, 0L ); - - // Inject it into the B-tree of B-tree - if ( ( btree.getType() != BTreeTypeEnum.BTREE_OF_BTREES ) && - ( btree.getType() != BTreeTypeEnum.COPIED_PAGES_BTREE ) && - ( btree.getType() != BTreeTypeEnum.PERSISTED_SUB ) ) - { - // We can safely increment the number of managed B-trees - nbBtree++; - - btreeOfBtrees.insert( nameRevision, btreeHeaderOffset ); - } - - updateRecordManagerHeader(); } @@ -1734,8 +1785,6 @@ public class RecordManager extends Abstr { int nbElems = page.getNbElems(); - boolean isNotSubTree = ( btree.getType() != BTreeTypeEnum.PERSISTED_SUB ); - if ( nbElems == 0 ) { return serializeRootPage( revision ); @@ -1787,11 +1836,7 @@ public class RecordManager extends Abstr } else { - if ( isNotSubTree ) - { - dataSize += serializeLeafValue( ( PersistedLeaf ) page, pos, serializedData ); - } - + dataSize += serializeLeafValue( ( PersistedLeaf ) page, pos, serializedData ); dataSize += serializeLeafKey( ( PersistedLeaf ) page, pos, serializedData ); } } @@ -1905,54 +1950,22 @@ public class RecordManager extends Abstr private int serializeLeafValue( PersistedLeaf leaf, int pos, List serializedData ) throws IOException { - // The value can be an Array or a sub-btree, but we don't care - // we just iterate on all the values ValueHolder valueHolder = leaf.getValue( pos ); int dataSize = 0; - int nbValues = valueHolder.size(); - if ( nbValues == 0 ) - { - // No value. - byte[] buffer = IntSerializer.serialize( nbValues ); - serializedData.add( buffer ); + // We have a serialized value. Just flush it + byte[] data = ( ( PersistedValueHolder ) valueHolder ).getRaw(); + dataSize += data.length; - return buffer.length; - } - - if ( !valueHolder.isSubBtree() ) - { - // Write the nb elements first - byte[] buffer = IntSerializer.serialize( nbValues ); - serializedData.add( buffer ); - dataSize = INT_SIZE; - - // We have a serialized value. Just flush it - byte[] data = ( ( PersistedValueHolder ) valueHolder ).getRaw(); - dataSize += data.length; - - // Store the data size - buffer = IntSerializer.serialize( data.length ); - serializedData.add( buffer ); - dataSize += INT_SIZE; + // Store the data size + byte[] buffer = IntSerializer.serialize( data.length ); + serializedData.add( buffer ); + dataSize += INT_SIZE; - // and add the data if it's not 0 - if ( data.length > 0 ) - { - serializedData.add( data ); - } - } - else + // and add the data if it's not 0 + if ( data.length > 0 ) { - // Store the nbVlues as a negative number. We add 1 so that 0 is not confused with an Array value - byte[] buffer = IntSerializer.serialize( -( nbValues + 1 ) ); - serializedData.add( buffer ); - dataSize += buffer.length; - - // the B-tree offset - buffer = LongSerializer.serialize( ( ( PersistedValueHolder ) valueHolder ).getOffset() ); - serializedData.add( buffer ); - dataSize += buffer.length; + serializedData.add( data ); } return dataSize; @@ -2009,7 +2022,7 @@ public class RecordManager extends Abstr * +---------------------+ * */ - public void updateRecordManagerHeader() + public ByteBuffer updateRecordManagerHeader() { // The page size int position = writeData( RECORD_MANAGER_HEADER_BYTES, 0, pageSize ); @@ -2095,9 +2108,17 @@ public class RecordManager extends Abstr LOG_PAGES.debug( "Update RM Header : \n{}", sb.toString() ); } + return RECORD_MANAGER_HEADER_BUFFER; + } + + + /** + * Write the RecordmanagerHeader in disk + */ + private void writeRecordManagerHeader() + { try { - Integer nbTxnStarted = CONTEXT.get(); if ( ( nbTxnStarted == null ) || ( nbTxnStarted <= 1 ) ) @@ -2331,84 +2352,41 @@ public class RecordManager extends Abstr return btreeHeaderOffset; } - + /** - * Write the B-tree informations on disk. We will write the following informations : - *
-     * +------------+
-     * | pageSize   | The B-tree page size (ie, the number of elements per page max)
-     * +------------+
-     * | nameSize   | The B-tree name size
-     * +------------+
-     * | name       | The B-tree name
-     * +------------+
-     * | keySerSize | The keySerializer FQCN size
-     * +------------+
-     * | keySerFQCN | The keySerializer FQCN
-     * +------------+
-     * | valSerSize | The Value serializer FQCN size
-     * +------------+
-     * | valSerKQCN | The valueSerializer FQCN
-     * +------------+
-     * | dups       | The flags that tell if the dups are allowed
-     * +------------+
-     * 
- * @param btree The B-tree which header has to be written - * @return The B-tree header offset - * @throws IOException If we weren't able to write the B-tree header + * Write the RootPage content. + * + * @param btree The BTree we are working on + * @param btreeHeader The BtreeHeader for this BTree + * @return The offset of the rootPage + * @throws IOException If we have had an error while accessing to the underlying file */ - private long writeBtreeInfo( BTree btree ) throws IOException + private long writeRootPage( BTree btree, BTreeHeader btreeHeader ) throws IOException { - // We will add the newly managed B-tree at the end of the header. - byte[] btreeNameBytes = Strings.getBytesUtf8( btree.getName() ); - byte[] keySerializerBytes = Strings.getBytesUtf8( btree.getKeySerializerFQCN() ); - byte[] valueSerializerBytes = Strings.getBytesUtf8( btree.getValueSerializerFQCN() ); - - int bufferSize = - INT_SIZE + // The page size - INT_SIZE + // The name size - btreeNameBytes.length + // The name - INT_SIZE + // The keySerializerBytes size - keySerializerBytes.length + // The keySerializerBytes - INT_SIZE + // The valueSerializerBytes size - valueSerializerBytes.length + // The valueSerializerBytes - INT_SIZE; // The allowDuplicates flag - - // Get the pageIOs we need to store the data. We may need more than one. - PageIO[] btreeHeaderPageIos = getFreePageIOs( bufferSize ); - - // Keep the B-tree header Offset into the B-tree - long btreeInfoOffset = btreeHeaderPageIos[0].getOffset(); - - // Now store the B-tree information data in the pages : - // - the B-tree page size - // - the B-tree name - // - the keySerializer FQCN - // - the valueSerializer FQCN - // - the flags that tell if the dups are allowed - // Starts at 0 - long position = 0L; - - // The B-tree page size - position = store( position, btree.getPageSize(), btreeHeaderPageIos ); + Page rootPage = btreeHeader.getRootPage(); + long pageId = context.getPageId(); - // The tree name - position = store( position, btreeNameBytes, btreeHeaderPageIos ); + context.addPage( pageId, rootPage ); + + return pageId; - // The keySerializer FQCN - position = store( position, keySerializerBytes, btreeHeaderPageIos ); + /* + PageIO[] rootPageIos = serializePage( btree, btreeHeader.getRevision(), rootPage ); - // The valueSerialier FQCN - position = store( position, valueSerializerBytes, btreeHeaderPageIos ); + // Get the reference on the first page + long rootPageOffset = rootPageIos[0].getOffset(); - // The allowDuplicates flag - position = store( position, ( btree.isAllowDuplicates() ? 1 : 0 ), btreeHeaderPageIos ); + // Store the rootPageOffset into the Btree header and into the rootPage + btreeHeader.setRootPageOffset( rootPageOffset ); - // And flush the pages to disk now - LOG.debug( "Flushing the newly managed '{}' btree header", btree.getName() ); - flushPages( btreeHeaderPageIos ); + ( ( AbstractPage ) rootPage ).setOffset( rootPageOffset ); - return btreeInfoOffset; + LOG.debug( "Flushing the newly managed '{}' btree rootpage", btree.getName() ); + + // Store the PageIO and the rootPage + storePages( rootPageIos ); + context.addPage( rootPageOffset, rootPage ); + */ } @@ -2590,6 +2568,12 @@ public class RecordManager extends Abstr */ private void flushPages( PageIO... pageIos ) throws IOException { + if ( pageIos == null ) + { + LOG.debug( "No PageIO to flush" ); + return; + } + if ( LOG.isDebugEnabled() ) { for ( PageIO pageIo : pageIos ) @@ -2627,6 +2611,88 @@ public class RecordManager extends Abstr } } + + private void flushObjects( Collection walObjects ) throws IOException + { + if ( ( walObjects == null ) || ( walObjects.size() == 0 ) ) + { + LOG.debug( "No Page to flush" ); + return; + } + + if ( LOG.isDebugEnabled() ) + { + //for ( Page page : pages ) + { + //dump( page ); + } + } + + for ( WALObject walObject : walObjects ) + { + if ( walObject instanceof BTreeHeader ) + { + // We need to update the rootPage offset first + PageIO[] pageIos = walObject.serialize(); + flushPages( pageIos ); + } + else if ( walObject instanceof BTreeInfo ) + { + // Serialize the instance and write it + PageIO[] pageIos = walObject.serialize(); + flushPages( pageIos ); + } + else if ( walObject instanceof PersistedNode ) + { + + } + else if ( walObject instanceof PersistedLeaf ) + { + // We can write pages immediately + PageIO[] pageIos = walObject.serialize(); + flushPages( pageIos ); + } + + //BTree btree = ( ( AbstractPage ) page ).getBtree(); + //PageIO[] pageIos = serializePage( btree, ( ( AbstractPage ) page ).getRevision(), page ); + + + //LOG.debug( "Flushing the newly managed '{}' btree rootpage", btree.getName() ); + //ushPages( pageIos ); + } + } + + /** + * Store the pages in the context. If the page has no Offset, we will + * use a virtual offset (ie, a negative one) + * + * @param pageIos The list of pages to write + * @throws IOException If the store failed + */ + /* No qualifier */void storePages( PageIO... pageIos ) throws IOException + { + if ( LOG.isDebugEnabled() ) + { + for ( PageIO pageIo : pageIos ) + { + dump( pageIo ); + } + } + + for ( PageIO pageIo : pageIos ) + { + pageIo.getData().rewind(); + long offset = pageIo.getOffset(); + + LOG.debug( "Writing a page at position {}", offset ); + //context.addPageIo( offset, pageIo ); + + writeCounter.put( offset, writeCounter.containsKey( offset ) ? writeCounter.get( offset ) + 1 : 1 ); + + nbUpdatePageIOs.incrementAndGet(); + } + } + /** * Compute the page in which we will store data given an offset, when @@ -2661,7 +2727,7 @@ public class RecordManager extends Abstr * @param pageIos The pageIOs we have to store the data in * @return The new offset */ - private long store( long position, byte[] bytes, PageIO... pageIos ) + /* no qualifier */ long store( long position, byte[] bytes, PageIO... pageIos ) { if ( bytes != null ) { @@ -2802,7 +2868,7 @@ public class RecordManager extends Abstr * @param pageIos The pageIOs we have to store the data in * @return The new offset */ - private long store( long position, int value, PageIO... pageIos ) + /* no qualifier */ long store( long position, int value, PageIO... pageIos ) { // Compute the page in which we will store the data given the // current position @@ -2877,7 +2943,7 @@ public class RecordManager extends Abstr * @param pageIos The pageIOs we have to store the data in * @return The new offset */ - private long store( long position, long value, PageIO... pageIos ) + /* no qualifier */ long store( long position, long value, PageIO... pageIos ) { // Compute the page in which we will store the data given the // current position @@ -3120,7 +3186,7 @@ public class RecordManager extends Abstr * @param dataSize The data size * @return An array of pages, enough to store the full data */ - private PageIO[] getFreePageIOs( int dataSize ) throws IOException + /* No qualifier */ PageIO[] getFreePageIOs( int dataSize ) throws IOException { if ( dataSize == 0 ) { @@ -3163,9 +3229,9 @@ public class RecordManager extends Abstr // We don't have any free page. Reclaim some new page at the end // of the file - PageIO newPage = new PageIO( endOfFileOffset ); + PageIO newPage = new PageIO( context.getLastOffset() ); - endOfFileOffset += pageSize; + context.addLastOffset( pageSize ); ByteBuffer data = ByteBuffer.allocateDirect( pageSize ); @@ -3186,10 +3252,10 @@ public class RecordManager extends Abstr // We have some existing free page. Fetch it from disk PageIO pageIo = fetchPage( firstFreePage ); - // Update the firstFreePage pointer - firstFreePage = pageIo.getNextPage(); + // Update the firstFreePage pointer + firstFreePage = pageIo.getNextPage(); - freePageLock.unlock(); + freePageLock.unlock(); // overwrite the data of old page ByteBuffer data = ByteBuffer.allocateDirect( pageSize ); @@ -3921,7 +3987,6 @@ public class RecordManager extends Abstr config.setName( name ); config.setKeySerializer( keySerializer ); config.setValueSerializer( valueSerializer ); - config.setAllowDuplicates( allowDuplicates ); BTree btree = new PersistedBTree( config ); manage( btree ); @@ -4027,33 +4092,6 @@ public class RecordManager extends Abstr } - /** - * Loads a B-tree holding the values of a duplicate key - * This tree is also called as dups tree or sub tree - * - * @param offset the offset of the B-tree header - * @return the deserialized B-tree - */ - /* No qualifier */ BTree loadDupsBtree( long btreeHeaderOffset, BTree parentBtree ) - { - PageIO[] pageIos = null; - try - { - pageIos = readPageIOs( btreeHeaderOffset, Long.MAX_VALUE ); - - BTree subBtree = BTreeFactory. createPersistedBTree( BTreeTypeEnum.PERSISTED_SUB ); - loadBtree( pageIos, subBtree, parentBtree ); - - return subBtree; - } - catch ( Exception e ) - { - // should not happen - throw new BTreeCreationException( e ); - } - } - - private void checkFreePages() throws EndOfFileExceededException, IOException { //System.out.println( "Checking the free pages, starting from " + Long.toHexString( firstFreePage ) ); Added: directory/mavibot/branches/single-value/mavibot/src/main/java/org/apache/directory/mavibot/btree/TransactionContext.java URL: http://svn.apache.org/viewvc/directory/mavibot/branches/single-value/mavibot/src/main/java/org/apache/directory/mavibot/btree/TransactionContext.java?rev=1711861&view=auto ============================================================================== --- directory/mavibot/branches/single-value/mavibot/src/main/java/org/apache/directory/mavibot/btree/TransactionContext.java (added) +++ directory/mavibot/branches/single-value/mavibot/src/main/java/org/apache/directory/mavibot/btree/TransactionContext.java Sun Nov 1 23:01:00 2015 @@ -0,0 +1,125 @@ +/* + * 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.directory.mavibot.btree; + +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; + +/** + * The TransactionContext class holds all the modified pages in memory, up to the + * moment we have to flush them on disk, when a cmmit is applied, or discard them, + * if a rallback is called. + * + * @author Apache Directory Project + */ +public class TransactionContext +{ + /** The map containing all the modified pages, using their offset as a key */ + private Map pageMap = new HashMap(); + + /** The incremental counter used to identify pages */ + private long pageId; + + /** The last offset on disk */ + private long lastOffset; + + /** + * A constructor for the TransactionContext, which initialize the last offset to + * the file size. + * + * @param lastOffset The last offset fo the associated file + */ + public TransactionContext( long lastOffset ) + { + this.lastOffset = lastOffset; + pageId = RecordManager.NO_PAGE; + } + + + /** + * Retrieve a Page if it has been stored in the context + * @param offset the offset of the Page we are looking for + * @return The found Page, or null if it does not exist + */ + public WALObject getPage( Long offset ) + { + return pageMap.get( offset ); + } + + + /** + * Add a page into the TransactionContext + * + * @param offset The Page's offset + * @param pageIo The Page to add + */ + public void addPage( Long offset, WALObject page ) + { + pageMap.put( offset, page ); + } + + + /** + * @return The list of stored Pages + */ + public Collection getPages() + { + return pageMap.values(); + } + + + /** + * @return the lastOffset + */ + public long getLastOffset() + { + return lastOffset; + } + + + /** + * @param lastOffset the lastOffset to set + */ + public void setLastOffset( long lastOffset ) + { + this.lastOffset = lastOffset; + } + + + /** + * @param addedSize the size to add + */ + public void addLastOffset( long addedSize ) + { + this.lastOffset += addedSize; + } + + + /** + * @return The unique page ID + */ + public long getPageId() + { + pageId--; + + return pageId; + } +} Modified: directory/mavibot/branches/single-value/mavibot/src/main/java/org/apache/directory/mavibot/btree/TupleCursor.java URL: http://svn.apache.org/viewvc/directory/mavibot/branches/single-value/mavibot/src/main/java/org/apache/directory/mavibot/btree/TupleCursor.java?rev=1711861&r1=1711860&r2=1711861&view=diff ============================================================================== --- directory/mavibot/branches/single-value/mavibot/src/main/java/org/apache/directory/mavibot/btree/TupleCursor.java (original) +++ directory/mavibot/branches/single-value/mavibot/src/main/java/org/apache/directory/mavibot/btree/TupleCursor.java Sun Nov 1 23:01:00 2015 @@ -23,21 +23,26 @@ package org.apache.directory.mavibot.btr import java.io.IOException; import java.util.NoSuchElementException; +import org.apache.directory.mavibot.btree.exception.CursorException; import org.apache.directory.mavibot.btree.exception.EndOfFileExceededException; /** * A Cursor is used to fetch elements in a BTree and is returned by the - * @see BTree#browse method. The cursor must be closed + * @see BTree#browse method. The cursor must be closed * when the user is done with it. *

+ * We keep a track of the current position at each level of the B-tree, so + * we can navigate in this B-tree forward and backward. Two special positions + * are defined : BEFORE_FIRST and AFTER_LAST which are befoe the leftmost and + * after the rightmost elements in the B-tree * * @param The type for the Key * @param The type for the stored value * * @author Apache Directory Project */ -public class TupleCursor +public class TupleCursor //implements Iterator> { /** A marker to tell that we are before the first element */ private static final int BEFORE_FIRST = -1; @@ -78,59 +83,95 @@ public class TupleCursor /** - * Change the position in the current cursor to set it after the last key + * Positions this Cursor after the last element. This will set the path to the + * rightmost page for each level, and the position to the rightmost element + * of each page. + * + * @throws CursorException if there are problems positioning this Cursor or if + * this Cursor is closed */ - public void afterLast() throws IOException + public void afterLast() throws CursorException { // First check that we have elements in the BTree if ( ( stack == null ) || ( stack.length == 0 ) ) { return; } + + // Update the parent page. + ParentPos parentPos = stack[0]; + parentPos.pos = parentPos.page.getNbElems(); + Page childPage = null; - Page child = null; + if ( parentPos.page instanceof PersistedNode ) + { + childPage = ( ( AbstractPage ) parentPos.page ).getPage( parentPos.pos ); + } - for ( int i = 0; i < depth; i++ ) + // Go down the Tree, selecting the rightmost element in each Node + for ( int i = 1; i < depth; i++ ) { - ParentPos parentPos = stack[i]; + parentPos = stack[i]; - if ( child != null ) - { - parentPos.page = child; - parentPos.pos = child.getNbElems(); - } - else - { - // We have N+1 children if the page is a Node, so we don't decrement the nbElems field - parentPos.pos = parentPos.page.getNbElems(); - } + // We are in the middle of the tree, change the parentPos to be + // the one we have selected previously + // Set the parentPos to be at the rightmost position for this level. + parentPos.page = childPage; + parentPos.pos = childPage.getNbElems(); - child = ( ( AbstractPage ) parentPos.page ).getPage( parentPos.pos ); + // Get the child page, and iterate + childPage = ( ( AbstractPage ) childPage ).getPage( parentPos.pos ); } - // and leaf - ParentPos parentPos = stack[depth]; + // Now, we should handle the leaf + parentPos = stack[depth]; - if ( child == null ) + if ( childPage != null ) { - parentPos.pos = parentPos.page.getNbElems() - 1; + // The tree had more than one level, so we make the current parentPos + // point on the previously selected leaf. + parentPos.page = childPage; } - else + + // Finally, set the position after the rightmost element + parentPos.pos = AFTER_LAST; + } + + + /** + * Determines whether or not a call to get() will succeed. + * + * @return true if a call to the get() method will succeed, false otherwise + */ + public boolean available() + { + // First check that we have elements in the BTree + if ( ( stack == null ) || ( stack.length == 0 ) ) { - parentPos.page = child; - parentPos.pos = child.getNbElems() - 1; + return false; } - parentPos.valueCursor = ( ( AbstractPage ) parentPos.page ).getValue( parentPos.pos ).getCursor(); - parentPos.valueCursor.afterLast(); - parentPos.pos = AFTER_LAST; + // Take the leaf and check if we have no mare values + ParentPos parentPos = stack[depth]; + + if ( parentPos.page == null ) + { + // Empty BTree, get out + return false; + } + + // We must not be AFTER_LAST or BEFORE_FIRST + return ( parentPos.pos != BEFORE_FIRST ) && ( parentPos.pos != AFTER_LAST ); } /** - * Change the position in the current cursor before the first key + * Positions this Cursor before the first element. + * + * @throws Exception if there are problems positioning this cursor or if + * this Cursor is closed */ - public void beforeFirst() throws IOException + public void beforeFirst() throws CursorException { // First check that we have elements in the BTree if ( ( stack == null ) || ( stack.length == 0 ) ) @@ -138,35 +179,32 @@ public class TupleCursor return; } + ParentPos parentPos = stack[0]; + parentPos.pos = 0; Page child = null; + + if ( parentPos.page instanceof PersistedNode ) + { + child = ( ( AbstractPage ) parentPos.page ).getPage( 0 ); + } - for ( int i = 0; i < depth; i++ ) + for ( int i = 1; i < depth; i++ ) { - ParentPos parentPos = stack[i]; + parentPos = stack[i]; parentPos.pos = 0; - - if ( child != null ) - { - parentPos.page = child; - } + parentPos.page = child; child = ( ( AbstractPage ) parentPos.page ).getPage( 0 ); } // and leaf - ParentPos parentPos = stack[depth]; + parentPos = stack[depth]; parentPos.pos = BEFORE_FIRST; if ( child != null ) { parentPos.page = child; } - - if ( parentPos.valueCursor != null ) - { - parentPos.valueCursor = ( ( AbstractPage ) parentPos.page ).getValue( 0 ).getCursor(); - parentPos.valueCursor.beforeFirst(); - } } @@ -225,13 +263,6 @@ public class TupleCursor } else { - // Check if we have some more value - if ( ( parentPos.valueCursor != null ) && parentPos.valueCursor.hasNext() ) - { - // No problem, we still have some values to read - return true; - } - // Ok, here, we have reached the last value in the leaf. We have to go up and // see if we have some remaining values int currentDepth = depth - 1; @@ -258,13 +289,15 @@ public class TupleCursor /** - * Find the next key/value + * Find the next Tuple, from the current position. If we have no more new element, + * a NoSuchElementException will be thrown. * * @return A Tuple containing the found key and value * @throws IOException - * @throws EndOfFileExceededException + * @throws NoSuchElementException When we have reached the end of the B-tree, or if + * the B-tree is empty */ - public Tuple next() throws EndOfFileExceededException, IOException + public Tuple next() throws NoSuchElementException { // First check that we have elements in the BTree if ( ( stack == null ) || ( stack.length == 0 ) ) @@ -274,46 +307,17 @@ public class TupleCursor ParentPos parentPos = stack[depth]; - if ( ( parentPos.page == null ) || ( parentPos.pos == AFTER_LAST ) ) - { - // This is the end : no more value - throw new NoSuchElementException( "No more tuples present" ); - } - - if ( parentPos.pos == parentPos.page.getNbElems() ) + try { - // End of the leaf. We have to go back into the stack up to the - // parent, and down to the leaf - parentPos = findNextParentPos(); - - // we also need to check for the type of page cause - // findNextParentPos will never return a null ParentPos - if ( ( parentPos == null ) || ( parentPos.page == null ) ) - { - // This is the end : no more value - throw new NoSuchElementException( "No more tuples present" ); - } - } - - V value = null; - - if ( parentPos.valueCursor.hasNext() ) - { - // Deal with the BeforeFirst case - if ( parentPos.pos == BEFORE_FIRST ) - { - parentPos.pos++; - } - - value = parentPos.valueCursor.next(); - } - else - { - if ( parentPos.pos == parentPos.page.getNbElems() - 1 ) + if ( parentPos.pos == parentPos.page.getNbElems() ) { + // End of the leaf. We have to go back into the stack up to the + // parent, and down to the leaf parentPos = findNextParentPos(); - - if ( ( parentPos == null ) || ( parentPos.page == null ) ) + + // we also need to check for the type of page cause + // findNextParentPos will never return a null ParentPos + if ( parentPos == null ) { // This is the end : no more value throw new NoSuchElementException( "No more tuples present" ); @@ -323,146 +327,29 @@ public class TupleCursor { parentPos.pos++; } - - try - { - ValueHolder valueHolder = ( ( AbstractPage ) parentPos.page ).getValue( parentPos.pos ); - - parentPos.valueCursor = valueHolder.getCursor(); - - value = parentPos.valueCursor.next(); - } - catch ( IllegalArgumentException e ) - { - e.printStackTrace(); - } - } - - AbstractPage leaf = ( AbstractPage ) ( parentPos.page ); - Tuple tuple = new Tuple( leaf.getKey( parentPos.pos ), value ); - - return tuple; - } - - - /** - * Get the next non-duplicate key. - * If the BTree contains : - * - *

    - *
  • <1,0>
  • - *
  • <1,1>
  • - *
  • <1,2>
  • - *
  • <2,0>
  • - *
  • <2,1>
  • - *
- * - * and cursor is present at <1,1> then the returned tuple will be <2,0> (not <1,2>) - * - * @return A Tuple containing the found key and value - * @throws EndOfFileExceededException - * @throws IOException - */ - public Tuple nextKey() throws EndOfFileExceededException, IOException - { - // First check that we have elements in the BTree - if ( ( stack == null ) || ( stack.length == 0 ) ) - { - // This is the end : no more value - throw new NoSuchElementException( "No more tuples present" ); } - - ParentPos parentPos = stack[depth]; - - if ( parentPos.page == null ) + catch ( IOException ioe ) { - // This is the end : no more value - throw new NoSuchElementException( "No more tuples present" ); + throw new NoSuchElementException( ioe.getMessage()); } - if ( parentPos.pos == ( parentPos.page.getNbElems() - 1 ) ) - { - // End of the leaf. We have to go back into the stack up to the - // parent, and down to the next leaf - ParentPos newParentPos = findNextParentPos(); - - // we also need to check the result of the call to - // findNextParentPos as it will return a null ParentPos - if ( ( newParentPos == null ) || ( newParentPos.page == null ) ) - { - // This is the end : no more value - AbstractPage leaf = ( AbstractPage ) ( parentPos.page ); - ValueHolder valueHolder = leaf.getValue( parentPos.pos ); - parentPos.pos = AFTER_LAST; - parentPos.valueCursor = valueHolder.getCursor(); - parentPos.valueCursor.afterLast(); + // Get the value + ValueHolder valueHolder = ( ( AbstractPage ) parentPos.page ).getValue( parentPos.pos ); - return null; - } - else - { - parentPos = newParentPos; - } - } - else - { - // Get the next key - parentPos.pos++; - } + V value = valueHolder.get(); - // The key + // Get the key AbstractPage leaf = ( AbstractPage ) ( parentPos.page ); - Tuple tuple = new Tuple(); - tuple.setKey( leaf.getKey( parentPos.pos ) ); - - // The value - ValueHolder valueHolder = leaf.getValue( parentPos.pos ); - parentPos.valueCursor = valueHolder.getCursor(); - V value = parentPos.valueCursor.next(); - tuple.setValue( value ); + K key = leaf.getKey( parentPos.pos ); + + // Build the Tuple + Tuple tuple = new Tuple( key, value ); return tuple; } /** - * Tells if the cursor can return a next key - * - * @return true if there are some more keys - * @throws IOException - * @throws EndOfFileExceededException - */ - public boolean hasNextKey() throws EndOfFileExceededException, IOException - { - // First check that we have elements in the BTree - if ( ( stack == null ) || ( stack.length == 0 ) ) - { - // This is the end : no more key - return false; - } - - ParentPos parentPos = stack[depth]; - - if ( parentPos.page == null ) - { - // This is the end : no more key - return false; - } - - if ( parentPos.pos == ( parentPos.page.getNbElems() - 1 ) ) - { - // End of the leaf. We have to go back into the stack up to the - // parent, and down to the next leaf - return hasNextParentPos(); - } - else - { - return true; - } - } - - - /** * Tells if the cursor can return a previous element * * @return true if there are some more elements @@ -499,12 +386,6 @@ public class TupleCursor return false; } - // Check if we have some more value - if ( parentPos.valueCursor.hasPrev() ) - { - return true; - } - // Ok, here, we have reached the first value in the leaf. We have to go up and // see if we have some remaining values int currentDepth = depth - 1; @@ -530,11 +411,13 @@ public class TupleCursor /** - * Find the previous key/value + * Get the previous Tuple, from the current position. If we have no more new element, + * a NoMoreElementException will be thrown. * * @return A Tuple containing the found key and value * @throws IOException - * @throws EndOfFileExceededException + * @throws NoSuchElementException When we have reached the beginning of the B-tree, or if + * the B-tree is empty */ public Tuple prev() throws EndOfFileExceededException, IOException { @@ -546,197 +429,58 @@ public class TupleCursor ParentPos parentPos = stack[depth]; - if ( ( parentPos.page == null ) || ( parentPos.pos == BEFORE_FIRST ) ) + switch( parentPos.pos ) { - // This is the end : no more value - throw new NoSuchElementException( "No more tuples present" ); - } - - if ( ( parentPos.pos == 0 ) && ( !parentPos.valueCursor.hasPrev() ) ) - { - // End of the leaf. We have to go back into the stack up to the - // parent, and down to the leaf - parentPos = findPrevParentPos(); - - // we also need to check for the type of page cause - // findPrevParentPos will never return a null ParentPos - if ( ( parentPos == null ) || ( parentPos.page == null ) ) - { + case BEFORE_FIRST : // This is the end : no more value throw new NoSuchElementException( "No more tuples present" ); - } - } - V value = null; - - if ( parentPos.valueCursor.hasPrev() ) - { - // Deal with the AfterLast case - if ( parentPos.pos == AFTER_LAST ) - { + case AFTER_LAST : + // Move the the last element parentPos.pos = parentPos.page.getNbElems() - 1; - } - - value = parentPos.valueCursor.prev(); - } - else - { - if ( parentPos.pos == 0 ) - { + break; + + case 0 : + // beginning of the leaf. We have to go back into the stack up to the + // parent, and down to the leaf on the left, if possible parentPos = findPrevParentPos(); - if ( ( parentPos == null ) || ( parentPos.page == null ) ) + // we also need to check for the type of page cause + // findPrevParentPos will never return a null ParentPos + if ( parentPos == null ) { // This is the end : no more value throw new NoSuchElementException( "No more tuples present" ); } - } - else - { - parentPos.pos--; - - try - { - ValueHolder valueHolder = ( ( AbstractPage ) parentPos.page ).getValue( parentPos.pos ); - - parentPos.valueCursor = valueHolder.getCursor(); - parentPos.valueCursor.afterLast(); - - value = parentPos.valueCursor.prev(); - } - catch ( IllegalArgumentException e ) + else { - e.printStackTrace(); + parentPos.pos--; } - } - } - - AbstractPage leaf = ( AbstractPage ) ( parentPos.page ); - Tuple tuple = new Tuple( leaf.getKey( parentPos.pos ), value ); - - return tuple; - } - - - /** - * Get the previous non-duplicate key. - * If the BTree contains : - * - *
    - *
  • <1,0>
  • - *
  • <1,1>
  • - *
  • <1,2>
  • - *
  • <2,0>
  • - *
  • <2,1>
  • - *
- * - * and cursor is present at <2,1> then the returned tuple will be <1,0> (not <2,0>) - * - * @return A Tuple containing the found key and value - * @throws EndOfFileExceededException - * @throws IOException - */ - public Tuple prevKey() throws EndOfFileExceededException, IOException - { - // First check that we have elements in the BTree - if ( ( stack == null ) || ( stack.length == 0 ) ) - { - // This is the end : no more value - throw new NoSuchElementException( "No more tuples present" ); - } - - ParentPos parentPos = stack[depth]; - - if ( parentPos.page == null ) - { - // This is the end : no more value - throw new NoSuchElementException( "No more tuples present" ); - } - - if ( parentPos.pos == 0 ) - { - // Beginning of the leaf. We have to go back into the stack up to the - // parent, and down to the leaf - parentPos = findPrevParentPos(); - - if ( ( parentPos == null ) || ( parentPos.page == null ) ) - { - // This is the end : no more value - throw new NoSuchElementException( "No more tuples present" ); - } - } - else - { - if ( parentPos.pos == AFTER_LAST ) - { - parentPos.pos = parentPos.page.getNbElems() - 1; - } - else - { + + break; + + default : + // Simply decrement the position parentPos.pos--; - } + break; } - // Update the Tuple - AbstractPage leaf = ( AbstractPage ) ( parentPos.page ); + // Get the value + ValueHolder valueHolder = ( ( AbstractPage ) parentPos.page ).getValue( parentPos.pos ); + V value = valueHolder.get(); - // The key - Tuple tuple = new Tuple(); - tuple.setKey( leaf.getKey( parentPos.pos ) ); - - // The value - ValueHolder valueHolder = leaf.getValue( parentPos.pos ); - parentPos.valueCursor = valueHolder.getCursor(); - V value = parentPos.valueCursor.next(); - tuple.setValue( value ); + // Get the key + AbstractPage leaf = ( AbstractPage ) ( parentPos.page ); + K key = leaf.getKey( parentPos.pos ); + + // Construct the Tuple + Tuple tuple = new Tuple( key, value ); return tuple; } /** - * Tells if the cursor can return a previous key - * - * @return true if there are some more keys - * @throws IOException - * @throws EndOfFileExceededException - */ - public boolean hasPrevKey() throws EndOfFileExceededException, IOException - { - // First check that we have elements in the BTree - if ( ( stack == null ) || ( stack.length == 0 ) ) - { - // This is the end : no more key - return false; - } - - ParentPos parentPos = stack[depth]; - - if ( parentPos.page == null ) - { - // This is the end : no more key - return false; - } - - switch ( parentPos.pos ) - { - case 0: - // Beginning of the leaf. We have to go back into the stack up to the - // parent, and down to the leaf - return hasPrevParentPos(); - - case -1: - // no previous key - return false; - - default: - // we have a previous key - return true; - } - } - - - /** * Tells if there is a next ParentPos * * @return the new ParentPos instance, or null if we have no following leaf @@ -836,7 +580,6 @@ public class TupleCursor parentPos = stack[depth]; parentPos.page = child; parentPos.pos = 0; - parentPos.valueCursor = ( ( AbstractPage ) child ).getValue( 0 ).getCursor(); return parentPos; } @@ -847,7 +590,33 @@ public class TupleCursor /** - * Find the leaf containing the previous elements. + * Find the leaf containing the previous elements. We are in + * + * if the B-tree content is like : + *
+     *                    .
+     *                   |
+     *                   v
+     *           +---+---+---+---+
+     *           |///| X | Y |///|               Level N-1
+     *           +---+---+---+---+
+     *           |   |   |   |   |
+     *   <-...---+   |   |   |   +---...-> 
+     *               |   |   |
+     *       <-...---+   |   |
+     *                   |   |
+     *         +---------+   +-------+
+     *         |                     | 
+     *         v                     v
+     * +---+---+---+---+     +---+---+---+---+
+     * |///|///| T |###|     | Y |///|///|///|   Level N
+     * +---+---+---+---+     +---+---+---+---+
+     *          pos           pos 
+     *   New ParentPos       Current ParentPos
+     * 
+ * + * and we are on Y, then the previous ParentPos instance will contain the page + * on the left, teh position beoing on the last element of this page, T * * @return the new ParentPos instance, or null if we have no previous leaf * @throws IOException @@ -861,6 +630,7 @@ public class TupleCursor return null; } + // Go up one step int currentDepth = depth - 1; Page child = null; @@ -868,21 +638,21 @@ public class TupleCursor while ( currentDepth >= 0 ) { // We first go up the tree, until we reach a page whose current position - // is not the last one + // is not the first one ParentPos parentPos = stack[currentDepth]; if ( parentPos.pos == 0 ) { - // No more element on the right : go up + // No more element on the left : go up currentDepth--; } else { - // We can pick the next element at this level + // We can pick the previous element at this level parentPos.pos--; child = ( ( AbstractPage ) parentPos.page ).getPage( parentPos.pos ); - // and go down the tree through the nodes + // and go down the tree through the nodes, positioning on the rightmost element while ( currentDepth < depth - 1 ) { currentDepth++; @@ -896,9 +666,6 @@ public class TupleCursor parentPos = stack[depth]; parentPos.pos = child.getNbElems() - 1; parentPos.page = child; - ValueHolder valueHolder = ( ( AbstractPage ) parentPos.page ).getValue( parentPos.pos ); - parentPos.valueCursor = valueHolder.getCursor(); - parentPos.valueCursor.afterLast(); return parentPos; } @@ -959,7 +726,21 @@ public class TupleCursor /** - * {@inheritDoc} + * Checks if this Cursor is closed. Calls to this operation should not + * fail with exceptions if and only if the cursor is in the closed state. + * + * @return true if this Cursor is closed, false otherwise + */ + public boolean isClosed() + { + return transaction.isClosed(); + } + + + /** + * Closes this Cursor and frees any resources it my have allocated. + * Repeated calls to this method after this Cursor has already been + * called should not fail with exceptions. */ public void close() { @@ -967,6 +748,62 @@ public class TupleCursor } + /** + * Closes this Cursor and frees any resources it my have allocated. + * Repeated calls to this method after this Cursor has already been + * called should not fail with exceptions. The reason argument is + * the Exception instance thrown instead of the standard + * CursorClosedException. + * + * @param reason exception thrown when this Cursor is accessed after close + */ + public void close( Exception reason ) + { + transaction.close(); + } + + + /** + * Gets the object at the current position. Cursor implementations may + * choose to reuse element objects by re-populating them on advances + * instead of creating new objects on each advance. + * + * @return the object at the current position + * @throws NoSuchElementException if the object at this Cursor's current position + * cannot be retrieved, or if this Cursor is closed + */ + public Tuple get() throws NoSuchElementException + { + // First check that we have elements in the BTree + if ( ( stack == null ) || ( stack.length == 0 ) ) + { + throw new NoSuchElementException( "No tuple present" ); + } + + ParentPos parentPos = stack[depth]; + + if ( ( parentPos.pos != BEFORE_FIRST ) && ( parentPos.pos != AFTER_LAST ) ) + { + // We have some element, build the Tuple + // Get the value + ValueHolder valueHolder = ( ( AbstractPage ) parentPos.page ).getValue( parentPos.pos ); + + V value = valueHolder.get(); + + // Get the key + AbstractPage leaf = ( AbstractPage ) ( parentPos.page ); + K key = leaf.getKey( parentPos.pos ); + + // Build the Tuple + Tuple tuple = new Tuple( key, value ); + + return tuple; + } + + throw new NoSuchElementException( "No element at this position : " + parentPos.pos ); + } + + /** * Get the creation date * @return The creation date for this cursor Modified: directory/mavibot/branches/single-value/mavibot/src/main/java/org/apache/directory/mavibot/btree/ValueHolder.java URL: http://svn.apache.org/viewvc/directory/mavibot/branches/single-value/mavibot/src/main/java/org/apache/directory/mavibot/btree/ValueHolder.java?rev=1711861&r1=1711860&r2=1711861&view=diff ============================================================================== --- directory/mavibot/branches/single-value/mavibot/src/main/java/org/apache/directory/mavibot/btree/ValueHolder.java (original) +++ directory/mavibot/branches/single-value/mavibot/src/main/java/org/apache/directory/mavibot/btree/ValueHolder.java Sun Nov 1 23:01:00 2015 @@ -37,29 +37,17 @@ package org.apache.directory.mavibot.btr /** - * @return the number of stored values + * @return the value stored in the ValueHolder */ - int size(); + V get(); /** - * @return a cursor on top of the values - */ - ValueCursor getCursor(); - - - /** - * @return true if we store the values in a sub btree - */ - boolean isSubBtree(); - - - /** - * Add a new value in the ValueHolder + * Set a new value in the ValueHolder * * @param newValue The added value */ - void add( V newValue ); + void set( V newValue ); /** @@ -68,18 +56,6 @@ package org.apache.directory.mavibot.btr * @param removedValue The value to remove */ V remove( V removedValue ); - - - /** - * Replaces the single value present in the array. - * - * This is only applicable for B-Trees that don't - * support duplicate values. - * - * @param newValue the new value - * @return the value that was replaced - */ - V replaceValueArray( V newValue ); /** Added: directory/mavibot/branches/single-value/mavibot/src/main/java/org/apache/directory/mavibot/btree/WALObject.java URL: http://svn.apache.org/viewvc/directory/mavibot/branches/single-value/mavibot/src/main/java/org/apache/directory/mavibot/btree/WALObject.java?rev=1711861&view=auto ============================================================================== --- directory/mavibot/branches/single-value/mavibot/src/main/java/org/apache/directory/mavibot/btree/WALObject.java (added) +++ directory/mavibot/branches/single-value/mavibot/src/main/java/org/apache/directory/mavibot/btree/WALObject.java Sun Nov 1 23:01:00 2015 @@ -0,0 +1,47 @@ +/* + * 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.directory.mavibot.btree; + +import java.io.IOException; + +/** + * A WALObject is an object stored in the TransactionContext before weing written on disk. + * + * @author Apache Directory Project + */ +public interface WALObject +{ + /** + * @return The ID associated with the Object + */ + long getId(); + + + /** + * @param id Set an ID to this Object + */ + void setId( long id ); + + + /** + * @return Serialize the Object into PageIOs + */ + PageIO[] serialize() throws IOException; +} Added: directory/mavibot/branches/single-value/mavibot/src/main/java/org/apache/directory/mavibot/btree/exception/CursorException.java URL: http://svn.apache.org/viewvc/directory/mavibot/branches/single-value/mavibot/src/main/java/org/apache/directory/mavibot/btree/exception/CursorException.java?rev=1711861&view=auto ============================================================================== --- directory/mavibot/branches/single-value/mavibot/src/main/java/org/apache/directory/mavibot/btree/exception/CursorException.java (added) +++ directory/mavibot/branches/single-value/mavibot/src/main/java/org/apache/directory/mavibot/btree/exception/CursorException.java Sun Nov 1 23:01:00 2015 @@ -0,0 +1,72 @@ +/* + * 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.directory.mavibot.btree.exception; + +/** + * An class for exceptions which add Cursor specific information to + * Exceptions. + * + * @author Apache Directory Project + */ +public class CursorException extends Exception +{ + /** The serial version UUID */ + private static final long serialVersionUID = 1L; + + + /** + * Creates a new instance of CursorException. + */ + public CursorException() + { + } + + + /** + * Creates a new instance of CursorException. + * + * @param explanation The message associated with the exception + */ + public CursorException( String explanation ) + { + super( explanation ); + } + + + /** + * Creates a new instance of LdapException. + */ + public CursorException( Throwable cause ) + { + super( cause ); + } + + + /** + * Creates a new instance of CursorException. + * + * @param explanation The message associated with the exception + * @param cause The root cause for this exception + */ + public CursorException( String explanation, Throwable cause ) + { + super( explanation, cause ); + } +} Modified: directory/mavibot/branches/single-value/mavibot/src/test/java/org/apache/directory/mavibot/btree/BulkLoaderTest.java URL: http://svn.apache.org/viewvc/directory/mavibot/branches/single-value/mavibot/src/test/java/org/apache/directory/mavibot/btree/BulkLoaderTest.java?rev=1711861&r1=1711860&r2=1711861&view=diff ============================================================================== --- directory/mavibot/branches/single-value/mavibot/src/test/java/org/apache/directory/mavibot/btree/BulkLoaderTest.java (original) +++ directory/mavibot/branches/single-value/mavibot/src/test/java/org/apache/directory/mavibot/btree/BulkLoaderTest.java Sun Nov 1 23:01:00 2015 @@ -39,6 +39,7 @@ import java.util.TreeSet; import org.apache.directory.mavibot.btree.BulkLoader.LevelEnum; import org.apache.directory.mavibot.btree.exception.BTreeAlreadyManagedException; +import org.apache.directory.mavibot.btree.exception.CursorException; import org.apache.directory.mavibot.btree.exception.EndOfFileExceededException; import org.apache.directory.mavibot.btree.exception.KeyNotFoundException; import org.apache.directory.mavibot.btree.serializer.LongSerializer; @@ -55,7 +56,7 @@ import org.junit.Test; public class BulkLoaderTest { private void checkBtree( BTree oldBtree, BTree newBtree ) - throws EndOfFileExceededException, IOException, KeyNotFoundException + throws EndOfFileExceededException, IOException, KeyNotFoundException, CursorException { assertEquals( oldBtree.getNbElems(), newBtree.getNbElems() ); @@ -76,79 +77,12 @@ public class BulkLoaderTest /** - * Test that we can compact a btree which has no element - */ - @Test - public void testInMemoryBulkLoadNoElement() throws IOException, KeyNotFoundException - { - BTree btree = BTreeFactory.createInMemoryBTree( "test", LongSerializer.INSTANCE, - StringSerializer.INSTANCE ); - btree.setPageSize( 4 ); - - BTree newBtree = ( BTree ) BulkLoader.compact( btree ); - - checkBtree( btree, newBtree ); - TupleCursor cursorOld = btree.browse(); - TupleCursor cursorNew = btree.browse(); - - assertFalse( cursorOld.hasNext() ); - assertFalse( cursorNew.hasNext() ); - } - - - /** - * Test that we can compact a btree which has a partially full leaf only - */ - @Ignore - @Test - public void testInMemoryBulkLoad3Elements() throws IOException, KeyNotFoundException - { - BTree btree = BTreeFactory.createInMemoryBTree( "test", LongSerializer.INSTANCE, - StringSerializer.INSTANCE ); - btree.setPageSize( 4 ); - - for ( Long i = 0L; i < 3L; i++ ) - { - String value = "V" + i; - btree.insert( i, value ); - } - - BTree newBtree = ( BTree ) BulkLoader.compact( btree ); - - checkBtree( btree, newBtree ); - } - - - /** - * Test that we can compact a btree which has a 2 full leaves - */ - @Ignore - @Test - public void testInMemoryBulkLoad8Elements() throws IOException, KeyNotFoundException - { - BTree btree = BTreeFactory.createInMemoryBTree( "test", LongSerializer.INSTANCE, - StringSerializer.INSTANCE ); - btree.setPageSize( 4 ); - - for ( Long i = 0L; i < 8L; i++ ) - { - String value = "V" + i; - btree.insert( i, value ); - } - - BTree newBtree = ( BTree ) BulkLoader.compact( btree ); - - checkBtree( btree, newBtree ); - } - - - /** * Test that we can load 100 BTrees with 0 to 1000 elements * @throws BTreeAlreadyManagedException */ @Test public void testPersistedBulkLoad1000Elements() throws IOException, KeyNotFoundException, - BTreeAlreadyManagedException + BTreeAlreadyManagedException, CursorException { for ( int i = 1000000; i < 1000001; i++ ) { @@ -266,146 +200,6 @@ public class BulkLoaderTest /** - * Test that we can compact a btree which has a full parent node, with all the leaves full. - */ - @Test - public void testInMemoryBulkLoad20Elements() throws IOException, KeyNotFoundException - { - BTree btree = BTreeFactory.createInMemoryBTree( "test", LongSerializer.INSTANCE, - StringSerializer.INSTANCE ); - btree.setPageSize( 4 ); - - for ( Long i = 0L; i < 20L; i++ ) - { - String value = "V" + i; - btree.insert( i, value ); - } - - BTree newBtree = ( BTree ) BulkLoader.compact( btree ); - - checkBtree( btree, newBtree ); - } - - - /** - * Test that we can compact a btree which has two full parent nodes, with all the leaves full. - * That means we have an upper node with one element. - */ - @Ignore - @Test - public void testInMemoryBulkLoad40Elements() throws IOException, KeyNotFoundException - { - BTree btree = BTreeFactory.createInMemoryBTree( "test", LongSerializer.INSTANCE, - StringSerializer.INSTANCE ); - btree.setPageSize( 4 ); - - for ( Long i = 0L; i < 40L; i++ ) - { - String value = "V" + i; - btree.insert( i, value ); - } - - BTree newBtree = ( BTree ) BulkLoader.compact( btree ); - - checkBtree( btree, newBtree ); - } - - - /** - * Test that we can compact a btree which has two full parent nodes, with all the leaves full. - * That means we have an upper node with one element. - */ - @Test - public void testInMemoryBulkLoad100Elements() throws IOException, KeyNotFoundException - { - BTree btree = BTreeFactory.createInMemoryBTree( "test", LongSerializer.INSTANCE, - StringSerializer.INSTANCE ); - btree.setPageSize( 4 ); - - for ( Long i = 0L; i < 100L; i++ ) - { - String value = "V" + i; - btree.insert( i, value ); - } - - BTree newBtree = ( BTree ) BulkLoader.compact( btree ); - - checkBtree( btree, newBtree ); - } - - - @Ignore - @Test - public void testInMemoryBulkLoadN() throws IOException, KeyNotFoundException - { - Random random = new Random( System.nanoTime() ); - long t0 = System.currentTimeMillis(); - - for ( long n = 0L; n < 2500L; n++ ) - { - BTree btree = BTreeFactory.createInMemoryBTree( "test", LongSerializer.INSTANCE, - StringSerializer.INSTANCE ); - btree.setPageSize( 4 ); - - for ( Long i = 0L; i < n; i++ ) - { - String value = "V" + i; - btree.insert( i, value ); - } - - //long t1 = System.currentTimeMillis(); - - //System.out.println( "Delta initial load = " + ( t1 - t0 ) ); - - //long t2 = System.currentTimeMillis(); - - BTree newBtree = ( BTree ) BulkLoader.compact( btree ); - - //long t3 = System.currentTimeMillis(); - - //System.out.println( "Delta initial load = " + ( t3 - t2 ) ); - - //System.out.println( "Checking for N = " + n ); - checkBtree( btree, newBtree ); - } - } - - - @Ignore - @Test - public void testInMemoryBulkLoad21() throws IOException, KeyNotFoundException - { - Random random = new Random( System.nanoTime() ); - long t0 = System.currentTimeMillis(); - - BTree btree = BTreeFactory.createInMemoryBTree( "test", LongSerializer.INSTANCE, - StringSerializer.INSTANCE ); - btree.setPageSize( 4 ); - - for ( Long i = 0L; i < 21; i++ ) - { - String value = "V" + i; - btree.insert( i, value ); - } - - //long t1 = System.currentTimeMillis(); - - //System.out.println( "Delta initial load = " + ( t1 - t0 ) ); - - //long t2 = System.currentTimeMillis(); - - BTree newBtree = ( BTree ) BulkLoader.compact( btree ); - - //long t3 = System.currentTimeMillis(); - - //System.out.println( "Delta initial load = " + ( t3 - t2 ) ); - - //System.out.println( "Checking for N = " + 21 ); - checkBtree( btree, newBtree ); - } - - - /** * test the computeLeafLevel method */ @Test @@ -575,7 +369,7 @@ public class BulkLoaderTest //@Ignore("The test is failing atm due to the sub-btree construction which is not working correctly when we have too many elements") @Test public void testPersistedBulkLoad1000ElementsMultipleValues() throws IOException, KeyNotFoundException, - BTreeAlreadyManagedException + BTreeAlreadyManagedException, CursorException { for ( int i = 1; i < 1001; i++ ) { @@ -709,7 +503,7 @@ public class BulkLoaderTest */ @Test public void testPersistedBulkLoad1000ElementsMultipleValuesDebug() throws IOException, KeyNotFoundException, - BTreeAlreadyManagedException + BTreeAlreadyManagedException, CursorException { Random random = new Random( System.currentTimeMillis() ); File file = File.createTempFile( "managedbtreebuilder", ".data" ); Modified: directory/mavibot/branches/single-value/mavibot/src/test/java/org/apache/directory/mavibot/btree/PageReclaimerTest.java URL: http://svn.apache.org/viewvc/directory/mavibot/branches/single-value/mavibot/src/test/java/org/apache/directory/mavibot/btree/PageReclaimerTest.java?rev=1711861&r1=1711860&r2=1711861&view=diff ============================================================================== --- directory/mavibot/branches/single-value/mavibot/src/test/java/org/apache/directory/mavibot/btree/PageReclaimerTest.java (original) +++ directory/mavibot/branches/single-value/mavibot/src/test/java/org/apache/directory/mavibot/btree/PageReclaimerTest.java Sun Nov 1 23:01:00 2015 @@ -263,7 +263,6 @@ public class PageReclaimerTest config.setName( "dump-tree" ); config.setKeySerializer( IntSerializer.INSTANCE ); config.setValueSerializer( StringSerializer.INSTANCE ); - config.setAllowDuplicates( false ); config.setPageSize( 4 ); BTree btree = new PersistedBTree( config );