/* This file is part of the db4o object database http://www.db4o.com
Copyright (C) 2004 - 2011 Versant Corporation http://www.versant.com
db4o is free software; you can redistribute it and/or modify it under
the terms of version 3 of the GNU General Public License as published
by the Free Software Foundation.
db4o is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License along
with this program. If not, see http://www.gnu.org/licenses/. */
package com.db4o.cs.internal;
import com.db4o.*;
import com.db4o.cs.internal.ShutdownMode.*;
import com.db4o.foundation.*;
import com.db4o.internal.*;
public class ClientTransactionPool {
private final Hashtable4 _transaction2Container; // Transaction -> ContainerCount
private final Hashtable4 _fileName2Container; // String -> ContainerCount
private final LocalObjectContainer _mainContainer;
private boolean _closed;
public ClientTransactionPool(LocalObjectContainer mainContainer) {
ContainerCount mainEntry = new ContainerCount(mainContainer, 1);
_transaction2Container = new Hashtable4();
_fileName2Container = new Hashtable4();
_fileName2Container.put(mainContainer.fileName(), mainEntry);
_mainContainer = mainContainer;
}
public Transaction acquireMain() {
return acquire(_mainContainer.fileName());
}
public Transaction acquire(String fileName) {
synchronized(_mainContainer.lock()) {
ContainerCount entry = (ContainerCount) _fileName2Container.get(fileName);
if (entry == null) {
LocalObjectContainer container = (LocalObjectContainer) Db4oEmbedded.openFile(Db4oEmbedded.newConfiguration(), fileName);
container.configImpl().setMessageRecipient(_mainContainer.configImpl().messageRecipient());
entry = new ContainerCount(container);
_fileName2Container.put(fileName, entry);
}
Transaction transaction = entry.newTransaction();
ObjectContainerSession objectContainerSession = new ObjectContainerSession(entry.container(), transaction);
transaction.setOutSideRepresentation(objectContainerSession);
_transaction2Container.put(transaction, entry);
return transaction;
}
}
public void release(ShutdownMode mode, Transaction transaction, boolean rollbackOnClose) {
synchronized(_mainContainer.lock()) {
ContainerCount entry = (ContainerCount) _transaction2Container.get(transaction);
entry.container().closeTransaction(transaction, false, mode.isFatal() ? false : rollbackOnClose);
_transaction2Container.remove(transaction);
entry.release();
if(entry.isEmpty()) {
_fileName2Container.remove(entry.fileName());
try{
entry.close(mode);
}catch(Throwable t){
// If we are in fatal ShutdownMode close will
// throw but we want to continue shutting down
// all entries.
t.printStackTrace();
}
}
}
}
public void close() {
close(ShutdownMode.NORMAL);
}
public void close(ShutdownMode mode) {
synchronized(_mainContainer.lock()) {
Iterator4 entryIter = _fileName2Container.iterator();
while(entryIter.moveNext()) {
Entry4 hashEntry = (Entry4) entryIter.current();
ContainerCount containerCount = (ContainerCount)hashEntry.value();
try{
containerCount.close(mode);
} catch(Throwable t){
// If we are in fatal ShutdownMode close will
// throw but we want to continue shutting down
// all entries.
t.printStackTrace();
}
}
_closed = true;
}
}
public int openTransactionCount(){
return isClosed() ? 0 : _transaction2Container.size();
}
public int openFileCount() {
return isClosed() ? 0 : _fileName2Container.size();
}
public boolean isClosed() {
return _closed == true || _mainContainer.isClosed();
}
public static class ContainerCount {
private LocalObjectContainer _container;
private int _count;
public ContainerCount(LocalObjectContainer container) {
this(container, 0);
}
public LocalObjectContainer container() {
return _container;
}
public ContainerCount(LocalObjectContainer container, int count) {
_container = container;
_count = count;
}
public boolean isEmpty() {
return _count <= 0;
}
public Transaction newTransaction() {
_count++;
return _container.newUserTransaction();
}
public void release() {
if(_count == 0) {
throw new IllegalStateException();
}
_count--;
}
public String fileName() {
return _container.fileName();
}
public void close(ShutdownMode mode) {
if(!mode.isFatal()) {
_container.close();
_container = null;
return;
}
_container.fatalShutdown(((FatalMode)mode).exc());
}
public int hashCode() {
return fileName().hashCode();
}
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null || getClass() != obj.getClass())
return false;
final ContainerCount other = (ContainerCount) obj;
return fileName().equals(other.fileName());
}
}
}