You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@directory.apache.org by el...@apache.org on 2014/05/16 19:28:23 UTC
svn commit: r1595272 - in /directory/mavibot/branches/with-txns/mavibot/src:
main/java/org/apache/directory/mavibot/btree/
test/java/org/apache/directory/mavibot/btree/
Author: elecharny
Date: Fri May 16 17:28:23 2014
New Revision: 1595272
URL: http://svn.apache.org/r1595272
Log:
Added the code that allows us to gather all the updates made on many BTrees within one data structure globally validated when we commit a transaction.
o We now have a Map containing the current revisions of all the btrees, and a Map containing the new revisions
o Added some check to protect the user against operations done on a BTree without recordManager
o Committing the transaction for a delete operation (this was missing)
o We don't anymore start a transaction for subBtrees : it's useless
o Added a helper method to get the btreeHeader
o Removed useless imports
o Injected the BTree into InMemory BtreeHeaders
o Fixed the way we were updating the subBtrees
o Fixed a failing test
o Added some comment and javadoc
Modified:
directory/mavibot/branches/with-txns/mavibot/src/main/java/org/apache/directory/mavibot/btree/AbstractBTree.java
directory/mavibot/branches/with-txns/mavibot/src/main/java/org/apache/directory/mavibot/btree/AbstractTransactionManager.java
directory/mavibot/branches/with-txns/mavibot/src/main/java/org/apache/directory/mavibot/btree/BTreeFactory.java
directory/mavibot/branches/with-txns/mavibot/src/main/java/org/apache/directory/mavibot/btree/InMemoryBTree.java
directory/mavibot/branches/with-txns/mavibot/src/main/java/org/apache/directory/mavibot/btree/InMemoryTransactionManager.java
directory/mavibot/branches/with-txns/mavibot/src/main/java/org/apache/directory/mavibot/btree/PersistedBTree.java
directory/mavibot/branches/with-txns/mavibot/src/main/java/org/apache/directory/mavibot/btree/PersistedValueHolder.java
directory/mavibot/branches/with-txns/mavibot/src/main/java/org/apache/directory/mavibot/btree/RecordManager.java
directory/mavibot/branches/with-txns/mavibot/src/main/java/org/apache/directory/mavibot/btree/TransactionManager.java
directory/mavibot/branches/with-txns/mavibot/src/test/java/org/apache/directory/mavibot/btree/PersistedBTreeDuplicateKeyTest.java
Modified: directory/mavibot/branches/with-txns/mavibot/src/main/java/org/apache/directory/mavibot/btree/AbstractBTree.java
URL: http://svn.apache.org/viewvc/directory/mavibot/branches/with-txns/mavibot/src/main/java/org/apache/directory/mavibot/btree/AbstractBTree.java?rev=1595272&r1=1595271&r2=1595272&view=diff
==============================================================================
--- directory/mavibot/branches/with-txns/mavibot/src/main/java/org/apache/directory/mavibot/btree/AbstractBTree.java (original)
+++ directory/mavibot/branches/with-txns/mavibot/src/main/java/org/apache/directory/mavibot/btree/AbstractBTree.java Fri May 16 17:28:23 2014
@@ -29,6 +29,7 @@ import java.util.concurrent.ConcurrentLi
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicLong;
+import org.apache.directory.mavibot.btree.exception.BTreeCreationException;
import org.apache.directory.mavibot.btree.exception.KeyNotFoundException;
import org.apache.directory.mavibot.btree.serializer.ElementSerializer;
@@ -47,8 +48,8 @@ import org.apache.directory.mavibot.btre
/** The read transaction timeout */
protected long readTimeOut = DEFAULT_READ_TIMEOUT;
- /** The copied Header for a managed BTree */
- //protected BTreeHeader<K, V> newBtreeHeader = new BTreeHeader<K, V>();
+ /** The current Header for a managed BTree */
+ protected BTreeHeader<K, V> currentBtreeHeader;
/** The Key serializer used for this tree.*/
protected ElementSerializer<K> keySerializer;
@@ -118,6 +119,12 @@ import org.apache.directory.mavibot.btre
*/
public TupleCursor<K, V> browse() throws IOException, KeyNotFoundException
{
+ // Check that we have a TransactionManager
+ if ( transactionManager == null )
+ {
+ throw new BTreeCreationException( "We don't have a transactionLManager" );
+ }
+
ReadTransaction<K, V> transaction = beginReadTransaction();
if ( transaction == null )
@@ -272,9 +279,25 @@ import org.apache.directory.mavibot.btre
throw new IllegalArgumentException( "Key must not be null" );
}
- Tuple<K, V> deleted = delete( key, currentRevision.get() + 1 );
+ // Take the lock if it's not already taken by another thread
+ transactionManager.beginTransaction();
+
+ try
+ {
+ Tuple<K, V> deleted = delete( key, currentRevision.get() + 1 );
+
+ // Commit now
+ transactionManager.commit();
- return deleted;
+ return deleted;
+ }
+ catch ( IOException ioe )
+ {
+ // We have had an exception, we must rollback the transaction
+ transactionManager.rollback();
+
+ return null;
+ }
}
@@ -340,8 +363,12 @@ import org.apache.directory.mavibot.btre
throw new IllegalArgumentException( "Key must not be null" );
}
- // Take the lock if it's not already taken by another thread
- transactionManager.beginTransaction();
+ // Take the lock if it's not already taken by another thread and if we
+ // aren't on a sub-btree
+ if ( btreeType != BTreeTypeEnum.PERSISTED_SUB )
+ {
+ transactionManager.beginTransaction();
+ }
try
{
@@ -352,15 +379,22 @@ import org.apache.directory.mavibot.btre
existingValue = ( ( ModifyResult<K, V> ) result ).getModifiedValue();
}
- // Commit now
- transactionManager.commit();
+ // Commit now if it's not a sub-btree
+ if ( btreeType != BTreeTypeEnum.PERSISTED_SUB )
+ {
+ transactionManager.commit();
+ }
return existingValue;
}
catch ( IOException ioe )
{
// We have had an exception, we must rollback the transaction
- transactionManager.rollback();
+ // if it's not a sub-btree
+ if ( btreeType != BTreeTypeEnum.PERSISTED_SUB )
+ {
+ transactionManager.rollback();
+ }
return null;
}
@@ -615,7 +649,33 @@ import org.apache.directory.mavibot.btre
*/
/* no qualifier */void setRevision( long revision )
{
- getBtreeHeader().setRevision( revision );
+ transactionManager.getBTreeHeader( getName() ).setRevision( revision );
+ }
+
+
+ /**
+ * Store the new revision in the map of btrees, increment the current revision
+ */
+ protected void storeRevision( BTreeHeader<K, V> btreeHeader, boolean keepRevisions )
+ {
+ long revision = btreeHeader.getRevision();
+
+ if ( keepRevisions )
+ {
+ synchronized ( btreeRevisions )
+ {
+ btreeRevisions.put( revision, btreeHeader );
+ }
+ }
+
+ currentRevision.set( revision );
+ currentBtreeHeader = btreeHeader;
+
+ // And update the newBTreeHeaders map
+ if ( btreeHeader.getBtree().getType() != BTreeTypeEnum.PERSISTED_SUB )
+ {
+ transactionManager.updateNewBTreeHeaders( btreeHeader );
+ }
}
@@ -632,6 +692,13 @@ import org.apache.directory.mavibot.btre
}
currentRevision.set( revision );
+ currentBtreeHeader = btreeHeader;
+
+ // And update the newBTreeHeaders map
+ if ( btreeHeader.getBtree().getType() != BTreeTypeEnum.PERSISTED_SUB )
+ {
+ transactionManager.updateNewBTreeHeaders( btreeHeader );
+ }
}
@@ -683,7 +750,7 @@ import org.apache.directory.mavibot.btre
*/
/* no qualifier */void setNbElems( long nbElems )
{
- getBtreeHeader().setNbElems( nbElems );
+ transactionManager.getBTreeHeader( getName() ).setNbElems( nbElems );
}
@@ -815,13 +882,7 @@ import org.apache.directory.mavibot.btre
*/
protected BTreeHeader<K, V> getBtreeHeader()
{
- synchronized ( btreeRevisions )
- {
- long revision = currentRevision.get();
- BTreeHeader<K, V> btreeHeader = btreeRevisions.get( revision );
-
- return btreeHeader;
- }
+ return currentBtreeHeader;
}
Modified: directory/mavibot/branches/with-txns/mavibot/src/main/java/org/apache/directory/mavibot/btree/AbstractTransactionManager.java
URL: http://svn.apache.org/viewvc/directory/mavibot/branches/with-txns/mavibot/src/main/java/org/apache/directory/mavibot/btree/AbstractTransactionManager.java?rev=1595272&r1=1595271&r2=1595272&view=diff
==============================================================================
--- directory/mavibot/branches/with-txns/mavibot/src/main/java/org/apache/directory/mavibot/btree/AbstractTransactionManager.java (original)
+++ directory/mavibot/branches/with-txns/mavibot/src/main/java/org/apache/directory/mavibot/btree/AbstractTransactionManager.java Fri May 16 17:28:23 2014
@@ -31,5 +31,4 @@ public abstract class AbstractTransactio
{
/** A lock to protect the transaction handling */
private ReadWriteLock transactionLock = new ReentrantReadWriteLock();
-
}
Modified: directory/mavibot/branches/with-txns/mavibot/src/main/java/org/apache/directory/mavibot/btree/BTreeFactory.java
URL: http://svn.apache.org/viewvc/directory/mavibot/branches/with-txns/mavibot/src/main/java/org/apache/directory/mavibot/btree/BTreeFactory.java?rev=1595272&r1=1595271&r2=1595272&view=diff
==============================================================================
--- directory/mavibot/branches/with-txns/mavibot/src/main/java/org/apache/directory/mavibot/btree/BTreeFactory.java (original)
+++ directory/mavibot/branches/with-txns/mavibot/src/main/java/org/apache/directory/mavibot/btree/BTreeFactory.java Fri May 16 17:28:23 2014
@@ -20,7 +20,6 @@
package org.apache.directory.mavibot.btree;
-import java.lang.reflect.Field;
import java.util.LinkedList;
import org.apache.directory.mavibot.btree.serializer.ElementSerializer;
Modified: directory/mavibot/branches/with-txns/mavibot/src/main/java/org/apache/directory/mavibot/btree/InMemoryBTree.java
URL: http://svn.apache.org/viewvc/directory/mavibot/branches/with-txns/mavibot/src/main/java/org/apache/directory/mavibot/btree/InMemoryBTree.java?rev=1595272&r1=1595271&r2=1595272&view=diff
==============================================================================
--- directory/mavibot/branches/with-txns/mavibot/src/main/java/org/apache/directory/mavibot/btree/InMemoryBTree.java (original)
+++ directory/mavibot/branches/with-txns/mavibot/src/main/java/org/apache/directory/mavibot/btree/InMemoryBTree.java Fri May 16 17:28:23 2014
@@ -138,6 +138,7 @@ import org.slf4j.LoggerFactory;
newBtreeHeader.setRootPageOffset( 0L );
btreeRevisions.put( 0L, newBtreeHeader );
+ currentBtreeHeader = newBtreeHeader;
// Now, initialize the BTree
try
@@ -212,6 +213,7 @@ import org.slf4j.LoggerFactory;
// This is a new Btree, we have to store the BtreeHeader
BTreeHeader<K, V> btreeHeader = new BTreeHeader<K, V>();
btreeHeader.setRootPage( new InMemoryLeaf<K, V>( this ) );
+ btreeHeader.setBtree( this );
storeRevision( btreeHeader );
}
@@ -297,6 +299,7 @@ import org.slf4j.LoggerFactory;
BTreeHeader<K, V> oldBtreeHeader = getBtreeHeader();
BTreeHeader<K, V> newBtreeHeader = createNewBtreeHeader( oldBtreeHeader, revision );
+ newBtreeHeader.setBtree( this );
// If the key exists, the existing value will be replaced. We store it
// to return it to the caller.
@@ -375,6 +378,7 @@ import org.slf4j.LoggerFactory;
BTreeHeader<K, V> oldBtreeHeader = getBtreeHeader();
BTreeHeader<K, V> newBtreeHeader = createNewBtreeHeader( oldBtreeHeader, revision );
+ newBtreeHeader.setBtree( this );
// If the key exists, the existing value will be replaced. We store it
// to return it to the caller.
Modified: directory/mavibot/branches/with-txns/mavibot/src/main/java/org/apache/directory/mavibot/btree/InMemoryTransactionManager.java
URL: http://svn.apache.org/viewvc/directory/mavibot/branches/with-txns/mavibot/src/main/java/org/apache/directory/mavibot/btree/InMemoryTransactionManager.java?rev=1595272&r1=1595271&r2=1595272&view=diff
==============================================================================
--- directory/mavibot/branches/with-txns/mavibot/src/main/java/org/apache/directory/mavibot/btree/InMemoryTransactionManager.java (original)
+++ directory/mavibot/branches/with-txns/mavibot/src/main/java/org/apache/directory/mavibot/btree/InMemoryTransactionManager.java Fri May 16 17:28:23 2014
@@ -19,11 +19,12 @@
*/
package org.apache.directory.mavibot.btree;
-import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantLock;
-
-import org.apache.directory.mavibot.btree.exception.RecordManagerException;
+import java.util.concurrent.locks.ReentrantReadWriteLock;
/**
* An implementation of a TransactionManager for in-memory B-trees
@@ -37,6 +38,15 @@ public class InMemoryTransactionManager
/** A ThreadLocalStorage used to store the current transaction */
private static final ThreadLocal<Integer> context = new ThreadLocal<Integer>();
+
+ /** A Map keeping the latest revisions for each managed BTree */
+ private Map<String, BTreeHeader<?, ?>> currentBTreeHeaders = new HashMap<String, BTreeHeader<?, ?>>();
+
+ /** A Map storing the new revisions when some change have been made in some BTrees */
+ private Map<String, BTreeHeader<?, ?>> newBTreeHeaders = new HashMap<String, BTreeHeader<?, ?>>();
+
+ /** A lock to protect the BtreeHeader maps */
+ private ReadWriteLock btreeHeadersLock = new ReentrantReadWriteLock();
/**
* {@inheritDoc}
@@ -101,4 +111,33 @@ public class InMemoryTransactionManager
// Finally, release the global lock
transactionLock.unlock();
}
+
+
+ /**
+ * Get the current BTreeHeader for a given Btree. It might not exist
+ */
+ public BTreeHeader getBTreeHeader( String name )
+ {
+ // Get a lock
+ btreeHeadersLock.readLock().lock();
+
+ // get the current BTree Header for this BTree and revision
+ BTreeHeader<?, ?> btreeHeader = currentBTreeHeaders.get( name );
+
+ // And unlock
+ btreeHeadersLock.readLock().unlock();
+
+ return btreeHeader;
+ }
+
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ public void updateNewBTreeHeaders( BTreeHeader btreeHeader )
+ {
+ newBTreeHeaders.put( btreeHeader.getBtree().getName(), btreeHeader );
+ }
}
Modified: directory/mavibot/branches/with-txns/mavibot/src/main/java/org/apache/directory/mavibot/btree/PersistedBTree.java
URL: http://svn.apache.org/viewvc/directory/mavibot/branches/with-txns/mavibot/src/main/java/org/apache/directory/mavibot/btree/PersistedBTree.java?rev=1595272&r1=1595271&r2=1595272&view=diff
==============================================================================
--- directory/mavibot/branches/with-txns/mavibot/src/main/java/org/apache/directory/mavibot/btree/PersistedBTree.java (original)
+++ directory/mavibot/branches/with-txns/mavibot/src/main/java/org/apache/directory/mavibot/btree/PersistedBTree.java Fri May 16 17:28:23 2014
@@ -125,19 +125,28 @@ public class PersistedBTree<K, V> extend
btreeHeader.setRootPage( rootPage );
btreeHeader.setBtree( this );
- if ( btreeType == BTreeTypeEnum.PERSISTED_SUB )
- {
- // The subBTree inherits its cache and readTransactions from its parent BTree
- init( ( PersistedBTree<K, V> ) configuration.getParentBTree() );
- }
- else
+ switch ( btreeType )
{
- // We will create a new cache and a new readTransactions map
- init( null );
- }
+ case BTREE_OF_BTREES :
+ case COPIED_PAGES_BTREE :
+ // We will create a new cache and a new readTransactions map
+ init( null );
+ currentBtreeHeader = btreeHeader;
+ break;
- // Add the B-tree header into the revisions
- btreeRevisions.put( 0L, btreeHeader );
+ case PERSISTED_SUB :
+ init( ( PersistedBTree<K, V> ) configuration.getParentBTree() );
+ btreeRevisions.put( 0L, btreeHeader );
+ currentBtreeHeader = btreeHeader;
+ break;
+
+ default :
+ // We will create a new cache and a new readTransactions map
+ init( null );
+ btreeRevisions.put( 0L, btreeHeader );
+ currentBtreeHeader = btreeHeader;
+ break;
+ }
}
@@ -221,7 +230,7 @@ public class PersistedBTree<K, V> extend
*/
/* No qualifier*/long getBtreeOffset()
{
- return getBtreeHeader().getBTreeHeaderOffset();
+ return getBTreeHeader( getName() ).getBTreeHeaderOffset();
}
@@ -230,7 +239,7 @@ public class PersistedBTree<K, V> extend
*/
/* No qualifier*/void setBtreeHeaderOffset( long btreeHeaderOffset )
{
- getBtreeHeader().setBTreeHeaderOffset( btreeHeaderOffset );
+ getBTreeHeader( getName() ).setBTreeHeaderOffset( btreeHeaderOffset );
}
@@ -239,7 +248,7 @@ public class PersistedBTree<K, V> extend
*/
/* No qualifier*/long getRootPageOffset()
{
- return getBtreeHeader().getRootPageOffset();
+ return getBTreeHeader( getName() ).getRootPageOffset();
}
@@ -328,7 +337,7 @@ public class PersistedBTree<K, V> extend
private DeleteResult<K, V> processDelete( K key, V value, long revision ) throws IOException
{
// Get the current B-tree header, and delete the value from it
- BTreeHeader<K, V> btreeHeader = getBtreeHeader();
+ BTreeHeader<K, V> btreeHeader = getBTreeHeader( getName() );
// Try to delete the entry starting from the root page. Here, the root
// page may be either a Node or a Leaf
@@ -385,7 +394,18 @@ public class PersistedBTree<K, V> extend
recordManager.addInCopiedPagesBtree( getName(), revision, result.getCopiedPages() );
// Store the new revision
- storeRevision( newBtreeHeader );
+ storeRevision( newBtreeHeader, recordManager.isKeepRevisions() );
+
+ break;
+
+ case PERSISTED_SUB :
+ // Sub-B-trees are only updating the CopiedPage B-tree
+ recordManager.addInCopiedPagesBtree( getName(), revision, result.getCopiedPages() );
+
+ //btreeRevisions.put( revision, newBtreeHeader );
+
+ currentRevision.set( revision );
+
break;
@@ -397,7 +417,7 @@ public class PersistedBTree<K, V> extend
recordManager.freePages( this, revision, result.getCopiedPages() );
// Store the new revision
- storeRevision( newBtreeHeader );
+ storeRevision( newBtreeHeader, recordManager.isKeepRevisions() );
break;
@@ -409,7 +429,7 @@ public class PersistedBTree<K, V> extend
recordManager.freePages( this, revision, result.getCopiedPages() );
// Store the new revision
- storeRevision( newBtreeHeader );
+ storeRevision( newBtreeHeader, recordManager.isKeepRevisions() );
break;
@@ -461,6 +481,18 @@ public class PersistedBTree<K, V> extend
}
}
+
+ private BTreeHeader<K, V> getBTreeHeader( String name )
+ {
+ if ( btreeType == BTreeTypeEnum.PERSISTED_SUB )
+ {
+ return getBtreeHeader();
+ }
+
+ BTreeHeader<K, V> btreeHeader = recordManager.getBTreeHeader( getName() );
+
+ return btreeHeader;
+ }
/**
* Insert the tuple into the B-tree rootPage, get back the new rootPage
@@ -468,7 +500,7 @@ public class PersistedBTree<K, V> extend
private InsertResult<K, V> processInsert( K key, V value, long revision ) throws IOException
{
// Get the current B-tree header, and insert the value into it
- BTreeHeader<K, V> btreeHeader = getBtreeHeader();
+ BTreeHeader<K, V> btreeHeader = getBTreeHeader( getName() );
InsertResult<K, V> result = btreeHeader.getRootPage().insert( key, value, revision );
// Create a new BTreeHeader
@@ -544,7 +576,7 @@ public class PersistedBTree<K, V> extend
recordManager.addInCopiedPagesBtree( getName(), revision, result.getCopiedPages() );
// Store the new revision
- storeRevision( newBtreeHeader );
+ storeRevision( newBtreeHeader, recordManager.isKeepRevisions() );
break;
@@ -552,12 +584,12 @@ public class PersistedBTree<K, V> extend
// Sub-B-trees are only updating the CopiedPage B-tree
recordManager.addInCopiedPagesBtree( getName(), revision, result.getCopiedPages() );
- //btreeRevisions.clear();
-
- btreeRevisions.put( revision, newBtreeHeader );
+ //btreeRevisions.put( revision, newBtreeHeader );
- currentRevision.set( revision );
+ // Store the new revision
+ storeRevision( newBtreeHeader, recordManager.isKeepRevisions() );
+ currentRevision.set( revision );
break;
@@ -569,7 +601,7 @@ public class PersistedBTree<K, V> extend
recordManager.freePages( this, revision, result.getCopiedPages() );
// Store the new revision
- storeRevision( newBtreeHeader );
+ storeRevision( newBtreeHeader, recordManager.isKeepRevisions() );
break;
@@ -581,7 +613,7 @@ public class PersistedBTree<K, V> extend
recordManager.freePages( this, revision, result.getCopiedPages() );
// Store the new revision
- storeRevision( newBtreeHeader );
+ storeRevision( newBtreeHeader, recordManager.isKeepRevisions() );
break;
@@ -667,13 +699,13 @@ public class PersistedBTree<K, V> extend
*/
public Page<K, V> getRootPage()
{
- return getBtreeHeader().getRootPage();
+ return getBTreeHeader( getName() ).getRootPage();
}
/* no qualifier */void setRootPage( Page<K, V> root )
{
- getBtreeHeader().setRootPage( root );
+ getBTreeHeader( getName() ).setRootPage( root );
}
@@ -700,7 +732,7 @@ public class PersistedBTree<K, V> extend
*/
protected ReadTransaction<K, V> beginReadTransaction()
{
- BTreeHeader<K, V> btreeHeader = getBtreeHeader();
+ BTreeHeader<K, V> btreeHeader = getBTreeHeader( getName() );
ReadTransaction<K, V> readTransaction = new ReadTransaction<K, V>( recordManager, btreeHeader, readTransactions );
@@ -743,9 +775,9 @@ public class PersistedBTree<K, V> extend
sb.append( "[" ).append( getName() ).append( "]" );
sb.append( "( pageSize:" ).append( getPageSize() );
- if ( getBtreeHeader().getRootPage() != null )
+ if ( getBTreeHeader( getName() ).getRootPage() != null )
{
- sb.append( ", nbEntries:" ).append( getBtreeHeader().getNbElems() );
+ sb.append( ", nbEntries:" ).append( getBTreeHeader( getName() ).getNbElems() );
}
else
{
@@ -766,7 +798,7 @@ public class PersistedBTree<K, V> extend
sb.append( ", DuplicatesAllowed: " ).append( isAllowDuplicates() );
sb.append( ") : \n" );
- sb.append( getBtreeHeader().getRootPage().dumpPage( "" ) );
+ sb.append( getBTreeHeader( getName() ).getRootPage().dumpPage( "" ) );
return sb.toString();
}
Modified: directory/mavibot/branches/with-txns/mavibot/src/main/java/org/apache/directory/mavibot/btree/PersistedValueHolder.java
URL: http://svn.apache.org/viewvc/directory/mavibot/branches/with-txns/mavibot/src/main/java/org/apache/directory/mavibot/btree/PersistedValueHolder.java?rev=1595272&r1=1595271&r2=1595272&view=diff
==============================================================================
--- directory/mavibot/branches/with-txns/mavibot/src/main/java/org/apache/directory/mavibot/btree/PersistedValueHolder.java (original)
+++ directory/mavibot/branches/with-txns/mavibot/src/main/java/org/apache/directory/mavibot/btree/PersistedValueHolder.java Fri May 16 17:28:23 2014
@@ -255,6 +255,7 @@ import org.apache.directory.mavibot.btre
try
{
+ // The sub-btree will not be added into the BOB.
parentBtree.getRecordManager().manage( valueBtree, RecordManager.INTERNAL_BTREE );
raw = null;
}
Modified: directory/mavibot/branches/with-txns/mavibot/src/main/java/org/apache/directory/mavibot/btree/RecordManager.java
URL: http://svn.apache.org/viewvc/directory/mavibot/branches/with-txns/mavibot/src/main/java/org/apache/directory/mavibot/btree/RecordManager.java?rev=1595272&r1=1595271&r2=1595272&view=diff
==============================================================================
--- directory/mavibot/branches/with-txns/mavibot/src/main/java/org/apache/directory/mavibot/btree/RecordManager.java (original)
+++ directory/mavibot/branches/with-txns/mavibot/src/main/java/org/apache/directory/mavibot/btree/RecordManager.java Fri May 16 17:28:23 2014
@@ -36,7 +36,9 @@ import java.util.Set;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantLock;
+import java.util.concurrent.locks.ReentrantReadWriteLock;
import org.apache.directory.mavibot.btree.exception.BTreeAlreadyManagedException;
import org.apache.directory.mavibot.btree.exception.BTreeCreationException;
@@ -192,7 +194,16 @@ public class RecordManager extends Abstr
/** The list of PageIO that can be freed after a roolback */
private List<PageIO> allocatedPages = new ArrayList<PageIO>();
+
+ /** A Map keeping the latest revisions for each managed BTree */
+ private Map<String, BTreeHeader<?, ?>> currentBTreeHeaders = new HashMap<String, BTreeHeader<?, ?>>();
+ /** A Map storing the new revisions when some change have been made in some BTrees */
+ private Map<String, BTreeHeader<?, ?>> newBTreeHeaders = new HashMap<String, BTreeHeader<?, ?>>();
+
+ /** A lock to protect the BtreeHeader maps */
+ private ReadWriteLock btreeHeadersLock = new ReentrantReadWriteLock();
+
/**
* Create a Record manager which will either create the underlying file
* or load an existing one. If a folder is provided, then we will create
@@ -351,12 +362,20 @@ public class RecordManager extends Abstr
currentBtreeOfBtreesOffset = ((PersistedBTree<NameRevision, Long>)btreeOfBtrees).getBtreeHeader().getBTreeHeaderOffset();
updateRecordManagerHeader();
+
+ // Inject the BtreeOfBtrees into the currentBtreeHeaders map
+ currentBTreeHeaders.put( BTREE_OF_BTREES_NAME, ((PersistedBTree<NameRevision, Long>)btreeOfBtrees).getBtreeHeader() );
+ newBTreeHeaders.put( BTREE_OF_BTREES_NAME, ((PersistedBTree<NameRevision, Long>)btreeOfBtrees).getBtreeHeader() );
// The FreePage B-tree
manage( copiedPageBtree, INTERNAL_BTREE );
currentCopiedPagesBtreeOffset = ((PersistedBTree<RevisionName, long[]>)copiedPageBtree).getBtreeHeader().getBTreeHeaderOffset();
updateRecordManagerHeader();
+
+ // Inject the CopiedPagesBTree into the currentBtreeHeaders map
+ currentBTreeHeaders.put( COPIED_PAGE_BTREE_NAME, ((PersistedBTree<RevisionName, long[]>)copiedPageBtree).getBtreeHeader() );
+ newBTreeHeaders.put( COPIED_PAGE_BTREE_NAME, ((PersistedBTree<RevisionName, long[]>)copiedPageBtree).getBtreeHeader() );
}
catch ( BTreeAlreadyManagedException btame )
{
@@ -560,55 +579,96 @@ public class RecordManager extends Abstr
*/
public void commit()
{
- int nbTxnStarted = context.get();
-
- if ( nbTxnStarted == 0 )
+ if ( !fileChannel.isOpen() )
{
- // The transaction was rollbacked, quit immediatelly
+ // The file has been closed, nothing remains to commit, let's get out
transactionLock.unlock();
-
return;
}
- else
+
+ int nbTxnStarted = context.get();
+
+ switch ( nbTxnStarted )
{
- if ( !fileChannel.isOpen() )
- {
- // The file has been closed, nothing remains to commit, let's get out
+ case 0 :
+ // The transaction was rollbacked, quit immediatelly
transactionLock.unlock();
+
return;
- }
-
- // We are done with the transaction
- // First update the RMHeader to be sure that we have a way to restore from a crash
- updateRecordManagerHeader();
-
- // We can now free pages
- for ( PageIO pageIo : freedPages )
- {
- try
+
+ case 1 :
+ // 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();
+
+ // Swap the BtreeHeaders maps
+ swapCurrentBtreeHeaders();
+
+ // We can now free pages
+ for ( PageIO pageIo : freedPages )
{
- free( pageIo );
+ try
+ {
+ free( pageIo );
+ }
+ catch ( IOException ioe )
+ {
+ throw new RecordManagerException( ioe.getMessage() );
+ }
}
- catch ( IOException ioe )
+
+ // Release the allocated and freed pages list
+ freedPages.clear();
+ allocatedPages.clear();
+
+ // 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();
+
+ // And decrement the number of started transactions
+ context.set( nbTxnStarted - 1 );
+
+ // Finally, release the global lock
+ transactionLock.unlock();
+
+ return;
+
+ default :
+ // We are inner an existing transaction. Just update the necessary elements
+ // Update the RMHeader to be sure that we have a way to restore from a crash
+ updateRecordManagerHeader();
+
+ // Swap the BtreeHeaders maps
+ swapCurrentBtreeHeaders();
+
+ // We can now free pages
+ for ( PageIO pageIo : freedPages )
{
- throw new RecordManagerException( ioe.getMessage() );
+ try
+ {
+ free( pageIo );
+ }
+ catch ( IOException ioe )
+ {
+ throw new RecordManagerException( ioe.getMessage() );
+ }
}
- }
-
- // Release the allocated and freed pages list
- freedPages.clear();
- allocatedPages.clear();
-
- // 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();
-
- // And decrement the number of started transactions
- context.set( nbTxnStarted - 1 );
- }
+
+ // Release the allocated and freed pages list
+ freedPages.clear();
+ allocatedPages.clear();
+
+ // 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();
+
+ // And decrement the number of started transactions
+ context.set( nbTxnStarted - 1 );
- // Finally, release the global lock
- transactionLock.unlock();
+ // Finally, release the global lock
+ transactionLock.unlock();
+ return;
+ }
}
@@ -639,6 +699,9 @@ public class RecordManager extends Abstr
// And update the RMHeader
updateRecordManagerHeader();
+
+ // And restore the BTreeHeaders new Map to the current state
+ revertBtreeHeaders();
transactionLock.unlock();
}
@@ -824,12 +887,20 @@ public class RecordManager extends Abstr
( ( PersistedBTree<K, V> ) btree ).setAllowDuplicates( allowDuplicates != 0 );
dataPos += INT_SIZE;
+ // Set the recordManager in the btree
+ ( ( PersistedBTree<K, V> ) btree ).setRecordManager( this );
+
// Set the current revision to the one stored in the B-tree header
- ((PersistedBTree<K, V>)btree).storeRevision( btreeHeader );
+ // Here, we have to tell the BTree to keep this revision in the
+ // btreeRevisions Map, thus the 'true' parameter at the end.
+ ((PersistedBTree<K, V>)btree).storeRevision( btreeHeader, true );
// Now, init the B-tree
- ( ( PersistedBTree<K, V> ) btree ).setRecordManager( this );
( ( PersistedBTree<K, V> ) btree ).init( parentBTree );
+
+ // Update the BtreeHeaders Maps
+ currentBTreeHeaders.put( btree.getName(), ( ( PersistedBTree<K, V> ) btree ).getBtreeHeader() );
+ newBTreeHeaders.put( btree.getName(), ( ( PersistedBTree<K, V> ) btree ).getBtreeHeader() );
// Read the rootPage pages on disk
PageIO[] rootPageIos = readPageIOs( rootPageOffset, Long.MAX_VALUE );
@@ -1341,6 +1412,10 @@ public class RecordManager extends Abstr
{
// Add the btree into the map of managed B-trees
managedBtrees.put( name, ( BTree<Object, Object> ) btree );
+
+ // And in the Map of currentBtreeHeaders and newBtreeHeaders
+ currentBTreeHeaders.put( name, btreeHeader );
+ newBTreeHeaders.put( name, btreeHeader );
// We can safely increment the number of managed B-trees
nbBtree++;
@@ -1859,7 +1934,7 @@ public class RecordManager extends Abstr
btreeOfBtrees.insert( nameRevision, btreeHeaderOffset );
// Update the B-tree of B-trees
- currentBtreeOfBtreesOffset = ((AbstractBTree<NameRevision, Long>)btreeOfBtrees).getBtreeHeader().getBTreeHeaderOffset();
+ currentBtreeOfBtreesOffset = getBTreeHeader( BTREE_OF_BTREES_NAME ).getBTreeHeaderOffset();
}
@@ -3527,11 +3602,79 @@ public class RecordManager extends Abstr
RevisionName revisionName = new RevisionName(
readTransaction.getRevision(),
readTransaction.getBtreeHeader().getBtree().getName() );
- closedTransactionsQueue.add( revisionName );
+ //closedTransactionsQueue.add( revisionName );
+ }
+
+
+ /**
+ * Get the current BTreeHeader for a given Btree. It might not exist
+ */
+ public BTreeHeader getBTreeHeader( String name )
+ {
+ // Get a lock
+ btreeHeadersLock.readLock().lock();
+
+ // get the current BTree Header for this BTree and revision
+ BTreeHeader<?, ?> btreeHeader = currentBTreeHeaders.get( name );
+
+ // And unlock
+ btreeHeadersLock.readLock().unlock();
+
+ return btreeHeader;
+ }
+
+
+ /**
+ * {@inheritDoc}
+ */
+ public void updateNewBTreeHeaders( BTreeHeader btreeHeader )
+ {
+ newBTreeHeaders.put( btreeHeader.getBtree().getName(), btreeHeader );
+ }
+
+
+ /**
+ * Swap the current BtreeHeader map with the new one. This method will only
+ * be called in a single trhead, when the current transaction will be committed.
+ */
+ private void swapCurrentBtreeHeaders()
+ {
+ // Copy the reference to the current BtreeHeader Map
+ Map<String, BTreeHeader<?, ?>> tmp = currentBTreeHeaders;
+
+ // Get a write lock
+ btreeHeadersLock.writeLock().lock();
+
+ // Swap the new BTreeHeader Map
+ currentBTreeHeaders = newBTreeHeaders;
+
+ // And unlock
+ btreeHeadersLock.writeLock().unlock();
+
+ // Last, not least, clear the Map and reinject the latest revision in it
+ tmp.clear();
+ tmp.putAll( currentBTreeHeaders );
+
+ // And update the new BTreeHeader map
+ newBTreeHeaders = tmp;
}
/**
+ * revert the new BTreeHeaders Map to the current BTreeHeader Map. This method
+ * is called when we have to rollback a transaction.
+ */
+ private void revertBtreeHeaders()
+ {
+ // Clean up teh new BTreeHeaders Map
+ newBTreeHeaders.clear();
+
+ // Reinject the latest revision in it
+ newBTreeHeaders.putAll( currentBTreeHeaders );
+ }
+
+
+ /**
* Loads a B-tree holding the values of a duplicate key
* This tree is also called as dups tree or sub tree
*
Modified: directory/mavibot/branches/with-txns/mavibot/src/main/java/org/apache/directory/mavibot/btree/TransactionManager.java
URL: http://svn.apache.org/viewvc/directory/mavibot/branches/with-txns/mavibot/src/main/java/org/apache/directory/mavibot/btree/TransactionManager.java?rev=1595272&r1=1595271&r2=1595272&view=diff
==============================================================================
--- directory/mavibot/branches/with-txns/mavibot/src/main/java/org/apache/directory/mavibot/btree/TransactionManager.java (original)
+++ directory/mavibot/branches/with-txns/mavibot/src/main/java/org/apache/directory/mavibot/btree/TransactionManager.java Fri May 16 17:28:23 2014
@@ -43,4 +43,21 @@ public interface TransactionManager
* Rollback a transaction
*/
void rollback();
+
+
+ /**
+ * Gets the current BtreeHeader for a given BTree.
+ *
+ * @param btreeName The Btree name we are looking the BtreeHeader for
+ * @return the current BTreeHeader
+ */
+ BTreeHeader<?, ?> getBTreeHeader( String btreeName );
+
+
+ /**
+ * Updates the map of new BTreeHeaders
+ *
+ * @param btreeHeader The new BtreeHeader
+ */
+ void updateNewBTreeHeaders( BTreeHeader<?, ?> btreeHeader );
}
Modified: directory/mavibot/branches/with-txns/mavibot/src/test/java/org/apache/directory/mavibot/btree/PersistedBTreeDuplicateKeyTest.java
URL: http://svn.apache.org/viewvc/directory/mavibot/branches/with-txns/mavibot/src/test/java/org/apache/directory/mavibot/btree/PersistedBTreeDuplicateKeyTest.java?rev=1595272&r1=1595271&r2=1595272&view=diff
==============================================================================
--- directory/mavibot/branches/with-txns/mavibot/src/test/java/org/apache/directory/mavibot/btree/PersistedBTreeDuplicateKeyTest.java (original)
+++ directory/mavibot/branches/with-txns/mavibot/src/test/java/org/apache/directory/mavibot/btree/PersistedBTreeDuplicateKeyTest.java Fri May 16 17:28:23 2014
@@ -142,11 +142,14 @@ public class PersistedBTreeDuplicateKeyT
@Test
- public void testBrowseEmptyTree() throws IOException, KeyNotFoundException
+ public void testBrowseEmptyTree() throws IOException, KeyNotFoundException, BTreeAlreadyManagedException
{
IntSerializer serializer = IntSerializer.INSTANCE;
BTree<Integer, Integer> btree = BTreeFactory.createPersistedBTree( "master", serializer, serializer );
+
+ // Inject the newly created BTree into teh recordManager
+ recordManager1.manage( btree );
TupleCursor<Integer, Integer> cursor = btree.browse();
assertFalse( cursor.hasNext() );