📄 transaction.java
字号:
// You can redistribute this software and/or modify it under the terms of
// the Ozone Core License version 1 published by ozone-db.org.
//
// The original code and portions created by SMB are
// Copyright (C) 1997-@year@ by SMB GmbH. All rights reserved.
//
// $Id: Transaction.java,v 1.30 2004/03/08 19:20:17 wieslawf Exp $
package org.ozoneDB.core;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import org.ozoneDB.*;
import org.ozoneDB.DxLib.DxIterator;
import org.ozoneDB.DxLib.DxSet;
import org.ozoneDB.core.DbRemote.DbCommand;
import org.ozoneDB.core.dr.Lockable;
import org.ozoneDB.core.dr.Locker;
import org.ozoneDB.data.SimpleArrayList;
import org.ozoneDB.util.LogWriter;
/**
* This class represents an internal transaction.<p>
*
* Most methods of this class are synchronized. In fact, this is not strictly
* needed because a transaction is invoked by one thread (associated with this
* transaction) only.<p>
*
* All public methods are wrapped into try/catch statements to convert thrown
* exception into OzoneInternalException. So the client gets OzoneRemoteException, if an
* object could not be found or something; OzoneInternalException, if there was a
* critical internal error; any other exceptions were thrown by the user code.
*
*
* @author <a href="http://www.softwarebuero.de/">SMB</a>
* @author <A HREF="http://www.medium.net/">Medium.net</A>
* @version $Revision: 1.30 $Date: 2004/03/08 19:20:17 $
*/
public abstract class Transaction implements Locker {
/** Status of a transaction: transaction is not active. */
public final static int STATUS_NONE = 1;
/** Status of a transaction: transaction has been started. */
public final static int STATUS_STARTED = 2;
/** Status of a transaction: transaction is about to prepare. */
public final static int STATUS_PREPARING = 3;
/** Status of a transaction: transaction has been successfully prepared. */
public final static int STATUS_PREPARED = 4;
/** Status of a transaction: transaction is about to commit.*/
public final static int STATUS_COMMITING = 5;
/** Status of a transaction: transaction has been successfully committed. */
public final static int STATUS_COMMITED = 6;
/** Status of a transaction: transaction is about to abort. */
public final static int STATUS_ABORTING = 7;
/** Status of a transaction: transaction has been aborted. */
public final static int STATUS_ABORTED = 8;
public final static int HASHTABLE_INIT_SIZE = 100;
/**
* The environment of this object.
*/
protected transient Env env;
protected TransactionID taID;
protected String ownerName;
protected User owner;
protected int status;
protected boolean rollbackOnly;
protected int maxLockLevel;
protected int commandCount;
/**
* The ID of the object (container) that blocks this transaction.
*/
protected ObjectID blocker;
protected long blockTimeout;
protected long startTime;
protected int acquireCount;
protected boolean stopped;
/**
Are we deadlocked?
*/
protected boolean deadlocked;
/**
The minimum deadlockWaitTimeMaximum can have. (default: 1 second)
*/
protected final static long deadlockWaitTimeMaximumMinimum = 1 * 1000;
/**
The maximum deadlockWaitTimeMaximum can have. (default: 30 minutes)
*/
protected final static long deadlockWaitTimeMaximumMaximum = 30 * 60 * 1000;
/**
The maximum time (in milliseconds) to wait after a deadlock.
*/
protected long deadlockWaitTimeMaximum;
/**
Is this thread sleeping?
*/
protected boolean sleeping;
/**
The list of {@link ObjectContainer}s which are called by this transactions but where the call
is not completed. The last object called is represented by the {@link ObjectContainer} with
the greatest index in the list.
*/
protected SimpleArrayList callStack;
/**
* Construct a new transaction.
*
*
* @param env Environment of this transaction.
* @param owner User that has started this transaction.
*/
protected Transaction(Env env, User owner) {
this.env = env;
taID = new TransactionID(env.keyGenerator.nextID());
this.owner = owner;
callStack = new SimpleArrayList(40);
reset();
}
/**
* Construct a new transaction. THIS TRANSACTION CAN BE USED FOR TESTING
* ONLY!
*/
protected Transaction(TransactionID _taID) {
taID = _taID;
reset();
}
public synchronized void stop() {
stopped = true;
}
public void reset() {
startTime = System.currentTimeMillis();
status = STATUS_STARTED;
commandCount = 0;
callStack.clear();
deadlocked = false;
if (deadlockWaitTimeMaximum == 0) {
deadlockWaitTimeMaximum = deadlockWaitTimeMaximumMinimum;
}
}
protected void setDeadlockWaitTimeMaximum(long to) {
deadlockWaitTimeMaximum = to;
}
protected long getDeadlockWaitTimeMaximum() {
return deadlockWaitTimeMaximum;
}
protected long increaseDeadlockWaitTimeMaximum() {
long newDeadlockWaitTimeMaximum = (long) (getDeadlockWaitTimeMaximum() * 1.5);
if (newDeadlockWaitTimeMaximum > deadlockWaitTimeMaximumMaximum) {
newDeadlockWaitTimeMaximum = deadlockWaitTimeMaximumMaximum;
}
setDeadlockWaitTimeMaximum(newDeadlockWaitTimeMaximum);
return newDeadlockWaitTimeMaximum;
}
public void setDeadlocked(boolean to) {
// env.logWriter.newEntry(this,toString()+".setDeadlocked("+to+").", LogWriter.DEBUG2);
deadlocked = to;
}
public boolean isDeadlocked() {
return deadlocked;
}
public int status() {
return status;
}
public User owner() {
return owner;
}
public int maxLockLevel() {
return maxLockLevel;
}
/**
The corresponding method to {@link #acquireObject}.
<DIV>
It calls on passivate and unpins the container
</DIV>
*/
public void releaseObject(ObjectContainer objectContainer) {
if (objectContainer.isPinned()) {
callOnPassivateIfNeeded(objectContainer);
objectContainer.unpin();
} else {
if (env.logWriter.hasTarget(LogWriter.DEBUG)) {
env.logWriter.newEntry(this, toString() + " debris from aborted cluster, " + objectContainer, LogWriter.DEBUG);
}
}
}
protected void callOnPassivateIfNeeded(ObjectContainer container) {
if (container.shouldOnPassivateBeCalled()) {
container.invokeOnPassivate();
}
}
/**
* Set a lock on the container specified by the given object ID and join
* the container to this transaction.
* If a container is returned, it is pinned. Thus, it has to be unpinned by the caller.
*
*
* @param id ObjectID of the container which we try to join to this transaction.
* @param lockLevel The lock level we need on this object (container).
* @return The container for the specified id, if all was ok.
* @throws ObjectNotFoundException If there is no such object.
*/
public ObjectContainer acquireObject(ObjectID id, int lockLevel) throws ObjectNotFoundException, IOException, ClassNotFoundException, TransactionException, TransactionError {
// this is not good style but this method is a hotspot and we should
// do all we can to make it fast
if (env.transactionManager.exclusiveThread != null &&
env.transactionManager.exclusiveThread != Thread.currentThread()) {
env.transactionManager.checkExclusion();
}
ObjectContainer container = env.storeManager.containerForID(this, id);
if (container == null) {
throw new ObjectNotFoundException("No such object ID: " + id);
}
boolean allright = false;
try {
container = acquireContainer(container, lockLevel);
callOnActivateIfNeeded(container);
allright = true;
return container;
} catch (Exception e) {
throw new TransactionException(e.getMessage(), e);
} finally {
if (!allright) {
container.unpin();
}
}
}
protected void callOnActivateIfNeeded(ObjectContainer container) {
if (container.shouldOnActivateBeCalled()) {
// We should intercept invocations here, if we had arguments and return values. But we don't.
// env.getGarbageCollector().interceptInvocationPre(this, container, args);
// try {
container.invokeOnActivate();
// } finally {
// env.getGarbageCollector().interceptInvocationPost(this, container, result);
// }
}
}
protected ObjectContainer acquireContainer(ObjectContainer container, int lockLevel) throws PermissionError, TransactionException, TransactionError, IOException, ObjectNotFoundException, ClassNotFoundException {
if (stopped == true) {
throw new TransactionException("Stopped.", TransactionException.STOPPED);
}
maxLockLevel = lockLevel > maxLockLevel ? lockLevel : maxLockLevel;
acquireCount++;
// this should help to let the following code execute without
// interrupt and so ensure that the container that we retrieve from
// the store is not deactivated while this method is running
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -