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}