001/*
002 *  Licensed to the Apache Software Foundation (ASF) under one
003 *  or more contributor license agreements.  See the NOTICE file
004 *  distributed with this work for additional information
005 *  regarding copyright ownership.  The ASF licenses this file
006 *  to you under the Apache License, Version 2.0 (the
007 *  "License"); you may not use this file except in compliance
008 *  with the License.  You may obtain a copy of the License at
009 *
010 *    http://www.apache.org/licenses/LICENSE-2.0
011 *
012 *  Unless required by applicable law or agreed to in writing,
013 *  software distributed under the License is distributed on an
014 *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015 *  KIND, either express or implied.  See the License for the
016 *  specific language governing permissions and limitations
017 *  under the License.
018 *
019 */
020package org.apache.directory.mavibot.btree;
021
022import java.util.HashMap;
023import java.util.Map;
024import java.util.concurrent.locks.Lock;
025import java.util.concurrent.locks.ReadWriteLock;
026import java.util.concurrent.locks.ReentrantLock;
027import java.util.concurrent.locks.ReentrantReadWriteLock;
028
029/**
030 * An implementation of a TransactionManager for in-memory B-trees
031 *
032 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
033 */
034public class InMemoryTransactionManager extends AbstractTransactionManager
035{
036    /** A lock to protect the transaction handling */
037    private Lock transactionLock = new ReentrantLock();
038    
039    /** A ThreadLocalStorage used to store the current transaction */
040    private static final ThreadLocal<Integer> context = new ThreadLocal<Integer>();
041    
042    /** A Map keeping the latest revisions for each managed BTree */
043    private Map<String, BTreeHeader<?, ?>> currentBTreeHeaders = new HashMap<String, BTreeHeader<?, ?>>();
044
045    /** A Map storing the new revisions when some change have been made in some BTrees */
046    private Map<String, BTreeHeader<?, ?>> newBTreeHeaders = new HashMap<String, BTreeHeader<?, ?>>();
047    
048    /** A lock to protect the BtreeHeader maps */
049    private ReadWriteLock btreeHeadersLock = new ReentrantReadWriteLock();
050
051    /**
052     * {@inheritDoc}
053     */
054    @Override
055    public void beginTransaction()
056    {
057        // First, take the lock
058        transactionLock.lock();
059        
060        // Now, check the TLS state
061        Integer nbTxnLevel = context.get();
062        
063        if ( nbTxnLevel == null )
064        {
065            context.set( 1 );
066        }
067        else
068        {
069            // And increment the counter of inner txn.
070            context.set( nbTxnLevel + 1 );
071        }
072    }
073
074
075    /**
076     * {@inheritDoc}
077     */
078    @Override
079    public void commit()
080    {
081        int nbTxnStarted = context.get();
082        
083        if ( nbTxnStarted == 0 )
084        {
085            // The transaction was rollbacked, quit immediatelly
086            transactionLock.unlock();
087            
088            return;
089        }
090        else
091        {
092            
093            // And decrement the number of started transactions
094            context.set( nbTxnStarted - 1 );
095        }
096
097        // Finally, release the global lock
098        transactionLock.unlock();
099    }
100
101
102    /**
103     * {@inheritDoc}
104     */
105    @Override
106    public void rollback()
107    {
108        // Reset the counter
109        context.set( 0 );
110
111        // Finally, release the global lock
112        transactionLock.unlock();
113    }
114    
115    
116    /**
117     * Get the current BTreeHeader for a given Btree. It might not exist
118     */
119    public BTreeHeader getBTreeHeader( String name )
120    {
121        // Get a lock
122        btreeHeadersLock.readLock().lock();
123        
124        // get the current BTree Header for this BTree and revision
125        BTreeHeader<?, ?> btreeHeader = currentBTreeHeaders.get( name );
126        
127        // And unlock 
128        btreeHeadersLock.readLock().unlock();
129
130        return btreeHeader;
131    }
132
133
134    
135    
136    /**
137     * {@inheritDoc}
138     */
139    public void updateNewBTreeHeaders( BTreeHeader btreeHeader )
140    {
141        newBTreeHeaders.put( btreeHeader.getBtree().getName(), btreeHeader );
142    }
143}