0001: // You can redistribute this software and/or modify it under the terms of
0002: // the Ozone Core License version 1 published by ozone-db.org.
0003: //
0004: // The original code and portions created by SMB are
0005: // Copyright (C) 1997-@year@ by SMB GmbH. All rights reserved.
0006: //
0007: // $Id: Transaction.java,v 1.4 2002/07/26 12:29:22 per_nyfelt Exp $
0008:
0009: package org.ozoneDB.core;
0010:
0011: import java.io.*;
0012: import java.util.*;
0013: import java.lang.reflect.*;
0014: import org.ozoneDB.DxLib.*;
0015: import org.ozoneDB.*;
0016: import org.ozoneDB.core.DbRemote.*;
0017: import org.ozoneDB.core.dr.*;
0018: import org.ozoneDB.util.*;
0019:
0020: import org.ozoneDB.data.SimpleArrayList;
0021:
0022: /**
0023: * This class represents an internal transaction.<p>
0024: *
0025: * Most methods of this class are synchronized. In fact, this is not strictly
0026: * needed because a transaction is invoked by one thread (associated with this
0027: * transaction) only.<p>
0028: *
0029: * All public methods are wrapped into try/catch statements to convert thrown
0030: * exception into OzoneInternalExc. So the client gets OzoneRemoteExc, if an
0031: * object could not be found or something; OzoneInternalExc, if there was a
0032: * critical internal error; any other exceptions were thrown by the user code.
0033: *
0034: *
0035: * @author <a href="http://www.softwarebuero.de/">SMB</a>
0036: * @author <A HREF="http://www.medium.net/">Medium.net</A>
0037: * @version $Revision: 1.4 $Date: 2002/07/26 12:29:22 $
0038: */
0039: public final class Transaction implements Locker {
0040:
0041: /** Status of a transaction: transaction is not active. */
0042: public final static int STATUS_NONE = 1;
0043:
0044: /** Status of a transaction: transaction has been started. */
0045: public final static int STATUS_STARTED = 2;
0046:
0047: /** Status of a transaction: transaction is about to prepare. */
0048: public final static int STATUS_PREPARING = 3;
0049:
0050: /** Status of a transaction: transaction has been successfully prepared. */
0051: public final static int STATUS_PREPARED = 4;
0052:
0053: /** Status of a transaction: transaction is about to commit.*/
0054: public final static int STATUS_COMMITING = 5;
0055:
0056: /** Status of a transaction: transaction has been successfully committed. */
0057: public final static int STATUS_COMMITED = 6;
0058:
0059: /** Status of a transaction: transaction is about to abort. */
0060: public final static int STATUS_ABORTING = 7;
0061:
0062: /** Status of a transaction: transaction has been aborted. */
0063: public final static int STATUS_ABORTED = 8;
0064:
0065: public final static int HASHTABLE_INIT_SIZE = 100;
0066:
0067: /**
0068: * The environment of this object.
0069: */
0070: protected transient Env env;
0071:
0072: protected TransactionID taID;
0073:
0074: protected String ownerName;
0075:
0076: protected User owner;
0077:
0078: protected int status;
0079:
0080: protected boolean rollbackOnly;
0081:
0082: protected int maxLockLevel;
0083:
0084: /**
0085: * Data that the StoreManager implementation uses to hold data that is associated
0086: * with this transaction. Usually this is a table of all containers that are
0087: * currently joined to this transaction.
0088: */
0089: private Object data;
0090:
0091: protected int commandCount;
0092:
0093: /**
0094: * The ID of the object (container) that blocks this transaction.
0095: */
0096: protected ObjectID blocker;
0097:
0098: protected long startTime;
0099:
0100: protected int acquireCount;
0101:
0102: protected boolean stopped;
0103:
0104: /**
0105: Are we deadlocked?
0106: */
0107: protected boolean deadlocked;
0108:
0109: /**
0110: The minimum deadlockWaitTimeMaximum can have. (default: 1 second)
0111: */
0112: protected final static long deadlockWaitTimeMaximumMinimum = 1 * 1000;
0113:
0114: /**
0115: The maximum deadlockWaitTimeMaximum can have. (default: 30 minutes)
0116: */
0117: protected final static long deadlockWaitTimeMaximumMaximum = 30 * 60 * 1000;
0118:
0119: /**
0120: The maximum time (in milliseconds) to wait after a deadlock.
0121: */
0122: protected long deadlockWaitTimeMaximum;
0123:
0124: /**
0125: Is this thread sleeping?
0126: */
0127: protected boolean sleeping;
0128:
0129: /**
0130: The list of {@link ObjectContainer}s which are called by this transactions but where the call
0131: is not completed. The last object called is represented by the {@link ObjectContainer} with
0132: the greatest index in the list.
0133: */
0134: protected SimpleArrayList callStack;
0135:
0136: /**
0137: * Construct a new transaction.
0138: *
0139: *
0140: * @param _env Environment of this transaction.
0141: * @param _command Command that will be performed by run().
0142: * @param _owner User that has started this transaction.
0143: */
0144: public Transaction(Env _env, User _owner) {
0145: env = _env;
0146: taID = new TransactionID(env.keyGenerator.nextID());
0147: owner = _owner;
0148:
0149: callStack = new SimpleArrayList(40);
0150: reset();
0151: }
0152:
0153: /**
0154: * Construct a new transaction. THIS TRANSACTION CAN BE USED FOR TESTING
0155: * ONLY!
0156: */
0157: public Transaction(TransactionID _taID) {
0158: taID = _taID;
0159: reset();
0160: }
0161:
0162: public synchronized void stop() {
0163: stopped = true;
0164: }
0165:
0166: public void reset() {
0167: startTime = System.currentTimeMillis();
0168: status = STATUS_STARTED;
0169: commandCount = 0;
0170: callStack.clear();
0171: deadlocked = false;
0172: setData(env.storeManager.newTransactionData());
0173: if (deadlockWaitTimeMaximum == 0) {
0174: deadlockWaitTimeMaximum = deadlockWaitTimeMaximumMinimum;
0175: }
0176: }
0177:
0178: protected void setDeadlockWaitTimeMaximum(long to) {
0179: deadlockWaitTimeMaximum = to;
0180: }
0181:
0182: protected long getDeadlockWaitTimeMaximum() {
0183: return deadlockWaitTimeMaximum;
0184: }
0185:
0186: protected long increaseDeadlockWaitTimeMaximum() {
0187: long newDeadlockWaitTimeMaximum = (long) (getDeadlockWaitTimeMaximum() * 1.5);
0188:
0189: if (newDeadlockWaitTimeMaximum > deadlockWaitTimeMaximumMaximum) {
0190: newDeadlockWaitTimeMaximum = deadlockWaitTimeMaximumMaximum;
0191: }
0192:
0193: setDeadlockWaitTimeMaximum(newDeadlockWaitTimeMaximum);
0194:
0195: return newDeadlockWaitTimeMaximum;
0196: }
0197:
0198: public void setDeadlocked(boolean to) {
0199: // env.logWriter.newEntry(this,toString()+".setDeadlocked("+to+").", LogWriter.DEBUG2);
0200: deadlocked = to;
0201: }
0202:
0203: public boolean isDeadlocked() {
0204: return deadlocked;
0205: }
0206:
0207: public int status() {
0208: return status;
0209: }
0210:
0211: public User owner() {
0212: return owner;
0213: }
0214:
0215: public int maxLockLevel() {
0216: return maxLockLevel;
0217: }
0218:
0219: /**
0220: The corresponding method to {@link #acquireObjectAndPin}.
0221: <DIV>
0222: Currently, it just unpins the container.
0223: </DIV>
0224: */
0225: public void releaseObjectAndUnpin(ObjectContainer objectContainer) {
0226: objectContainer.unpin();
0227: }
0228:
0229: /**
0230: * Set a lock on the container specified by the given object ID and join
0231: * the container to this transaction.
0232: * If a container is returned, it is pinned. Thus, it has to be unpinned by the caller.
0233: *
0234: *
0235: * @param id ObjectID of the container which we try to join to this transaction.
0236: * @param lockLevel The lock level we need on this object (container).
0237: * @return The container for the specified id, if all was ok.
0238: * @throws ObjectNotFoundExc If there is no such object.
0239: */
0240: public ObjectContainer acquireObjectAndPin(ObjectID id,
0241: int lockLevel) throws ObjectNotFoundExc, IOException,
0242: ClassNotFoundException, TransactionExc, TransactionError {
0243:
0244: // this is not good style but this method is a hotspot and we should
0245: // do all we can to make it fast
0246: if (env.transactionManager.exclusiveThread != null
0247: && env.transactionManager.exclusiveThread != Thread
0248: .currentThread()) {
0249: env.transactionManager.checkExclusion();
0250: }
0251:
0252: ObjectContainer container = env.storeManager
0253: .containerForIDAndPin(this , id);
0254:
0255: if (container == null) {
0256: throw new ObjectNotFoundExc("No such object ID: " + id);
0257: }
0258:
0259: boolean allright = false;
0260:
0261: try {
0262: container = acquireContainer(container, lockLevel);
0263:
0264: allright = true;
0265:
0266: return container;
0267: } finally {
0268: if (!allright) {
0269: container.unpin();
0270: }
0271: }
0272: }
0273:
0274: protected ObjectContainer acquireContainer(
0275: ObjectContainer container, int lockLevel)
0276: throws PermissionError, TransactionExc, TransactionError,
0277: IOException, ObjectNotFoundExc, ClassNotFoundException {
0278:
0279: if (stopped == true) {
0280: throw new TransactionExc("Stopped.", TransactionExc.STOPPED);
0281: }
0282:
0283: maxLockLevel = lockLevel > maxLockLevel ? lockLevel
0284: : maxLockLevel;
0285:
0286: acquireCount++;
0287:
0288: // this should help to let the following code execute without
0289: // interrupt and so ensure that the container that we retrieve from
0290: // the store is not deactivated while this method is running
0291: // Thread.currentThread().yield();
0292:
0293: // transaktion als blockiert markieren (kante in lock-graphen einfuegen);
0294: // vor deadlock-erkennung: es werden auch deadlocks mit
0295: // transaktionen erkannt, die selber erstmal auf deadlock checken
0296: // aber auf keinem fall zuwenige (race-cond. zwischen deadlock-pruefung
0297: // und lock setzen)
0298: blocker = container.id();
0299:
0300: // this may happen when the container was deactivated between
0301: // acquireObject() and this point; I'm not sure what to do here
0302:
0303: // But I (Xuân Baldauf, Medium.net) am (partly):
0304: // If our caller is acquireContainer(), the container is pinned and thus may not be deactived inbetween.
0305: // If our caller is createObjectAndPin(), the container is pinned and thus may not be deactived inbetween.
0306: if (container.lock() == null) {
0307: throw new IllegalStateException(
0308: "Container was wrongly deactivated. Increasing heap memory of the JVM may help.");
0309: }
0310:
0311: // try to aquire the lock of the container; wait until the locks is
0312: // successfully aquired
0313: int prevLevel = container.lock().tryAcquire(this , lockLevel);
0314:
0315: if (prevLevel == Lock.NOT_ACQUIRED) {
0316: synchronized (this ) {
0317: while (prevLevel == Lock.NOT_ACQUIRED) {
0318: try {
0319: if (false) {
0320: env.logWriter.newEntry(this , toString()
0321: + " blocked by lock "
0322: + container.lock() + "...",
0323: LogWriter.DEBUG);
0324: }
0325:
0326: wait();
0327:
0328: if (false) {
0329: env.logWriter.newEntry(this , toString()
0330: + " checking lock again...",
0331: LogWriter.DEBUG);
0332: }
0333: } catch (Exception e) {
0334: // do nothing; just proceed...
0335: }
0336:
0337: /*
0338: We have two cases:
0339: (1) We are called by acquireObjectAndPin()
0340: (2) We are not called by acquireObjectAndPin()
0341:
0342: In case (1), we do not need to reload, because the object is pinned.
0343: In case (2), we never come to this code location, because in this case, the objects are freshly created and thus never locked.
0344:
0345: Thus, we never need to reload.
0346:
0347: Oh, the reasoning above does not work out. If a cluster is pinned,
0348: it still may be aborted and thus need to reload. But maybe then the
0349: "pinned" concept is mood. Maybe pinned clusters which are arborted
0350: should be reloaded immediately.
0351: */
0352:
0353: // since the container was maybe deactivated while waiting we
0354: // reload it here again
0355: ObjectContainer newContainer = env.storeManager
0356: .containerForIDAndPin(this , blocker);
0357:
0358: if (container == null) {
0359: throw new ObjectNotFoundExc("No such object.");
0360: }
0361:
0362: // HACK!!!
0363: if (!((org.ozoneDB.core.wizardStore.WizardObjectContainer) newContainer)
0364: .hasSameClusterAs((org.ozoneDB.core.wizardStore.WizardObjectContainer) container)) {
0365: if (false) {
0366: // Does this allow a pinning livelock?
0367: while (container.isPinned()) {
0368: newContainer.pin();
0369: container.unpin();
0370: }
0371: newContainer.unpin();
0372: } else {
0373: int oldPinCount = ((org.ozoneDB.core.wizardStore.WizardObjectContainer) container)
0374: .getCluster().clearPinCount();
0375:
0376: ((org.ozoneDB.core.wizardStore.WizardObjectContainer) newContainer)
0377: .getCluster().addPinCount(
0378: oldPinCount);
0379: ((org.ozoneDB.core.wizardStore.WizardObjectContainer) newContainer)
0380: .getCluster().unpin();
0381: }
0382:
0383: container = newContainer;
0384: }
0385:
0386: // throw an exception if we are forced to abort because of a deadlock
0387: container.lock().checkDeadlock(this );
0388:
0389: prevLevel = container.lock().tryAcquire(this ,
0390: lockLevel);
0391: }
0392: }
0393: }
0394:
0395: if (false) {
0396: env.logWriter.newEntry(this ,
0397: toString() + ".acquireContainer(" + blocker
0398: + "): successful.", LogWriter.DEBUG);
0399: }
0400:
0401: // transaction is no longer blocked
0402: blocker = null;
0403:
0404: // after acquiring the lock we update the lock level of the container
0405: if (prevLevel < lockLevel) {
0406: if (owner == null) {
0407: throw new PermissionError("No such user.");
0408: }
0409: if (!env.userManager.checkPermission(owner, container,
0410: lockLevel)) {
0411: throw new PermissionError(
0412: "User does not have proper access rights.");
0413: }
0414:
0415: env.storeManager.updateLockLevel(this , container);
0416: }
0417: container.touch();
0418:
0419: return container;
0420: }
0421:
0422: public boolean performCommand(DbCommand command) {
0423: if (env.logWriter.hasTarget(LogWriter.DEBUG)) {
0424: env.logWriter.newEntry(this , "performCommand(): "
0425: + toString() + ", " + command.toString(),
0426: LogWriter.DEBUG);
0427: }
0428:
0429: commandCount++;
0430:
0431: boolean result = true;
0432: try {
0433: // result goes in command.result
0434: command.perform(this );
0435: } catch (TransactionError e) {
0436: throw e;
0437: } catch (Throwable e) {
0438: Throwable resultingException = e;
0439:
0440: if (e instanceof ExceptionInOzoneObjectException) {
0441: if (false) { // User exceptions do not need to be verbose. It's the responsibility of the user to print or not to print out the stack trace.
0442: Throwable cause = ((ExceptionInOzoneObjectException) e)
0443: .getCause();
0444:
0445: env.logWriter.newEntry(this , toString()
0446: + ": exception in ozone object: (" + e
0447: + "): ", e, LogWriter.WARN);
0448: env.logWriter.newEntry(this , toString()
0449: + ": cause:", cause, LogWriter.WARN);
0450:
0451: // resultingException = cause;
0452: }
0453: } else {
0454: env.logWriter.newEntry(this , toString()
0455: + ": uncaught exception: (" + e + ")", e,
0456: LogWriter.WARN);
0457: }
0458:
0459: if (e instanceof PermissionError) {
0460: e = new PermissionDeniedExc(e.toString());
0461: }
0462:
0463: rollbackOnly = true;
0464: command.result = resultingException;
0465: result = false;
0466: }
0467: return result;
0468: }
0469:
0470: public synchronized void prepareCommit() throws IOException,
0471: ClassNotFoundException {
0472: if (false && env.logWriter.hasTarget(LogWriter.DEBUG)) {
0473: env.logWriter.newEntry(this , "==> PREPARECOMMIT() ",
0474: LogWriter.DEBUG);
0475: }
0476: status = STATUS_PREPARING;
0477: env.storeManager.prepareCommitTransaction(this );
0478: status = STATUS_PREPARED;
0479: }
0480:
0481: /**
0482: * Commit this transaction. The transaction has to be in PREPARED state.
0483: * Ones this method is called it MUST commit the entire transaction
0484: * stuff without any exception.
0485: */
0486: public synchronized void commit() throws IOException,
0487: ClassNotFoundException {
0488: if (false && env.logWriter.hasTarget(LogWriter.DEBUG)) {
0489: env.logWriter.newEntry(this , "==> COMMIT() ",
0490: LogWriter.DEBUG);
0491: }
0492:
0493: status = STATUS_COMMITING;
0494: try {
0495: env.storeManager.commitTransaction(this );
0496: // don't delete data in case of an exception
0497: setData(null);
0498: } finally {
0499: blocker = null;
0500: }
0501: status = STATUS_COMMITED;
0502: }
0503:
0504: protected void setData(Object to) {
0505: data = to;
0506: }
0507:
0508: public Object getData() {
0509: return data;
0510: }
0511:
0512: /**
0513: * Once this method is called it MUST cleanup the entire transaction
0514: * stuff without exception. An exception signals an internal server error.
0515: * <p>
0516: * Note: This may be called after/from prepareCommit() !
0517: */
0518: public synchronized void abort(DbCommand command)
0519: throws IOException, ClassNotFoundException {
0520: if (false && env.logWriter.hasTarget(LogWriter.DEBUG)) {
0521: env.logWriter.newEntry(this , "==> ABORT() ",
0522: LogWriter.DEBUG);
0523: }
0524:
0525: status = STATUS_ABORTING;
0526: try {
0527: env.storeManager.abortTransaction(this );
0528: } finally {
0529: // FIXME: We better do not delete the data now. Somewhere it is used again. (Maybe in case of deadlock retry?)
0530: setData(null);
0531: blocker = null;
0532: }
0533: status = STATUS_ABORTED;
0534: }
0535:
0536: /**
0537: * Helper method to implement the Locker interface to support deadlock
0538: * recognition via core.dr package
0539: */
0540: public Lockable blockedByAndPin() {
0541: try {
0542: return blocker != null ? (Lockable) env.storeManager
0543: .containerForIDAndPin(this , blocker) : null;
0544: } catch (NullPointerException e) {
0545: env.logWriter
0546: .newEntry(
0547: this ,
0548: "blockedBy(): Our blocker is invalidated. We are not blocked anymore?",
0549: e, LogWriter.ERROR);
0550:
0551: blocker = null;
0552:
0553: return null;
0554: } catch (Exception e) {
0555: env.logWriter.newEntry(this , "blockedBy() ", e,
0556: LogWriter.ERROR);
0557: throw new RuntimeException("blockedBy() FAILED!");
0558: }
0559: }
0560:
0561: /**
0562: Returns wether this locker is blocked.
0563: */
0564: public boolean isBlocked() {
0565: return blocker != null;
0566: }
0567:
0568: /**
0569: * Create a new database object. If the className is null, an empty container
0570: * is created.
0571: *
0572: * @param className
0573: * @param access
0574: * @param name
0575: * @param id The ID of the new container or null.
0576: * @exception PermissionDeniedExc If user in invalid, name is already in
0577: * use, target is not OzoneCompatible...
0578: */
0579: public ObjectContainer createObjectAndPin(String className,
0580: int access, String name, String sig, Object[] args,
0581: ObjectID id) throws Exception,
0582: org.ozoneDB.ExceptionInOzoneObjectException {
0583: if (false && env.logWriter.hasTarget(LogWriter.DEBUG3)) {
0584: env.logWriter.newEntry(this , "createObject() ",
0585: LogWriter.DEBUG3);
0586: }
0587:
0588: // check (and wait) if a thread runs exclusively;
0589: env.transactionManager.checkExclusion();
0590:
0591: try {
0592: Class cl = null;
0593: if (className != null) {
0594: cl = env.classManager.classForName(className);
0595: }
0596:
0597: Permissions perms = new Permissions(owner, access);
0598:
0599: if (id == null) {
0600: id = new ObjectID(env.keyGenerator.nextID());
0601: }
0602:
0603: ObjectContainer container = env.storeManager
0604: .newContainerAndPinAndLock(this , null, id, perms,
0605: Lock.LEVEL_WRITE);
0606:
0607: boolean alright = false;
0608: boolean containerAcquired = false;
0609:
0610: try {
0611: container = acquireContainer(container,
0612: Lock.LEVEL_WRITE);
0613: containerAcquired = true;
0614:
0615: if (cl != null) {
0616: container.createTarget(env, cl, sig, args);
0617: container.target().onCreate();
0618: }
0619:
0620: if (name != null) {
0621: nameObject(container.id(), name);
0622: }
0623:
0624: alright = true;
0625:
0626: return container;
0627: } finally {
0628: if (!containerAcquired) {
0629: /*
0630: We have had acquired a lock but somehow did not manage to acquire the corresponding container.
0631: Thus, the cluster would not be added to this transaction and thus it would not be unlocked
0632: when the transaction is finished. Thus we have to unlock it now.
0633: */
0634: container./*getCluster().getLock().*/lock()
0635: .release(this );
0636: /*
0637: But is this the right behaviour? What if acquireContainer() fails for some reason (e.g. PermissionError)
0638: after it locked the cluster itself. Then we would unlock it while it should remain locked? Should it
0639: if it fails with an exception?
0640: */
0641: }
0642: if (!alright) {
0643: container.unpin();
0644: }
0645: }
0646: } catch (InvocationTargetException e) {
0647: Throwable ee = e.getTargetException();
0648:
0649: if (ee instanceof org.ozoneDB.core.TransactionError) {
0650: throw (org.ozoneDB.core.TransactionError) ee;
0651: }
0652:
0653: if (ee instanceof ExceptionInOzoneObjectException)
0654: throw (ExceptionInOzoneObjectException) ee;
0655:
0656: throw new org.ozoneDB.ExceptionInOzoneObjectException(
0657: "caught", ee);
0658: /*
0659: if (ee instanceof RuntimeException) {
0660: throw (RuntimeException)ee;
0661: } else if (ee instanceof Exception) {
0662: throw (Exception)ee;
0663: } else if (ee instanceof Error) {
0664: throw (Error)ee;
0665: } else {
0666: throw new Exception( "Unknown exception type " + ee.getClass().getName() );
0667: }
0668: */
0669: } catch (ExceptionInOzoneObjectException e) {
0670: throw e;
0671: } catch (OzoneRemoteExc e) {
0672: throw e;
0673: } catch (Exception e) {
0674: env.logWriter.newEntry(this , "createObject()", e,
0675: LogWriter.WARN);
0676: throw new OzoneInternalExc(e.toString(), e);
0677: }
0678: }
0679:
0680: public ObjectContainer copyObjectAndPin(ObjectID id)
0681: throws Exception {
0682: if (env.logWriter.hasTarget(LogWriter.DEBUG3)) {
0683: env.logWriter.newEntry(this , "copyObject() ",
0684: LogWriter.DEBUG3);
0685: }
0686:
0687: // check (and wait) if a thread runs exclusively;
0688: env.transactionManager.checkExclusion();
0689:
0690: try {
0691: if (env.logWriter.hasTarget(LogWriter.DEBUG3)) {
0692: env.logWriter.newEntry(this , "copyObject(): "
0693: + id.toString(), LogWriter.DEBUG3);
0694: }
0695:
0696: ObjectContainer container = acquireObjectAndPin(id,
0697: Lock.LEVEL_WRITE);
0698:
0699: try {
0700: Object target = container.targetClone();
0701: Permissions perms = (Permissions) container
0702: .permissions().clone();
0703: ObjectContainer copyContainer = env.storeManager
0704: .newContainerAndPinAndLock(this ,
0705: (OzoneCompatible) target, new ObjectID(
0706: env.keyGenerator.nextID()),
0707: perms, Lock.LEVEL_WRITE);
0708: boolean alright = false;
0709:
0710: try {
0711: copyContainer = acquireContainer(copyContainer,
0712: Lock.LEVEL_WRITE);
0713: alright = true;
0714: return copyContainer;
0715: } finally {
0716: if (!alright) {
0717: copyContainer.unpin();
0718: }
0719: }
0720: } finally {
0721: releaseObjectAndUnpin(container);
0722: }
0723: } catch (OzoneRemoteExc e) {
0724: throw e;
0725: } catch (Exception e) {
0726: env.logWriter.newEntry(this , "copyObject()", e,
0727: LogWriter.WARN);
0728: throw new OzoneInternalExc(e.toString(), e);
0729: }
0730: }
0731:
0732: public void deleteObject(ObjectID id) throws ObjectNotFoundExc,
0733: IOException, ClassNotFoundException, TransactionExc,
0734: TransactionError, OzoneRemoteExc, OzoneInternalExc,
0735: ExceptionInOzoneObjectException {
0736: if (false && env.logWriter.hasTarget(LogWriter.DEBUG3)) {
0737: env.logWriter.newEntry(this , "deleteObject(): "
0738: + id.toString(), LogWriter.DEBUG3);
0739: }
0740:
0741: try {
0742: ObjectContainer container = acquireObjectAndPin(id,
0743: Lock.LEVEL_WRITE);
0744:
0745: try {
0746: try {
0747: container.target().onDelete();
0748: } catch (OzoneRemoteExc e) {
0749: throw e;
0750: } catch (ExceptionInOzoneObjectException e) {
0751: throw e;
0752: } catch (Throwable e) {
0753: env.logWriter.newEntry(this , "deleteObject()", e,
0754: LogWriter.WARN);
0755: // throw new OzoneInternalExc( e.toString() );
0756: throw new ExceptionInOzoneObjectException(
0757: "caught onDelete()", e);
0758: }
0759: container.deleteTarget();
0760: } finally {
0761: releaseObjectAndUnpin(container);
0762: }
0763: } catch (OzoneRemoteExc e) {
0764: throw e;
0765: } catch (Exception e) {
0766: env.logWriter.newEntry(this , "deleteObject()", e,
0767: LogWriter.WARN);
0768: throw new OzoneInternalExc(e.toString(), e);
0769: }
0770: }
0771:
0772: /**
0773: * @param id
0774: * @param methodName
0775: * @param sig
0776: * @param lockLevel
0777: * @return
0778: */
0779: public Object invokeObject(ObjectID id, String methodName,
0780: String sig, Object[] args, int lockLevel) throws Exception,
0781: org.ozoneDB.ExceptionInOzoneObjectException {
0782: if (false && env.logWriter.hasTarget(LogWriter.DEBUG3)) {
0783: env.logWriter.newEntry(this , "invokeObject(): "
0784: + methodName, LogWriter.DEBUG3);
0785: }
0786:
0787: try {
0788: ObjectContainer container = acquireObjectAndPin(id,
0789: lockLevel);
0790:
0791: try {
0792: env.getGarbageCollector().interceptInvocationPre(this ,
0793: container, args);
0794:
0795: Object result = null;
0796:
0797: try {
0798: result = container.invokeTarget(env, methodName,
0799: sig, args);
0800: } finally {
0801: env.getGarbageCollector().interceptInvocationPost(
0802: this , container, result);
0803: }
0804:
0805: return result;
0806: } finally {
0807: releaseObjectAndUnpin(container);
0808: }
0809: // using the container after the invoke is dangerous because
0810: // it's possibly deactivated meanwhile
0811: } catch (InvocationTargetException e) {
0812: Throwable ee = e.getTargetException();
0813:
0814: if (ee instanceof org.ozoneDB.core.TransactionError) {
0815: throw (org.ozoneDB.core.TransactionError) ee;
0816: }
0817:
0818: if (ee instanceof ExceptionInOzoneObjectException)
0819: throw (ExceptionInOzoneObjectException) ee;
0820:
0821: throw new org.ozoneDB.ExceptionInOzoneObjectException(
0822: "caught", ee);
0823:
0824: /*
0825: if (ee instanceof RuntimeException) {
0826: throw (RuntimeException)ee;
0827: } else if (ee instanceof Exception) {
0828: throw (Exception)ee;
0829: } else if (ee instanceof Error) {
0830: throw (Error)ee;
0831: } else {
0832: throw new Exception( "Unknown exception type " + ee.getClass().getName() );
0833: }
0834: */
0835: } catch (ExceptionInOzoneObjectException e) {
0836: throw e;
0837: } catch (OzoneRemoteExc e) {
0838: env.logWriter.newEntry(this , "invokeObject()", e,
0839: LogWriter.WARN);
0840: throw e;
0841: } catch (Exception e) {
0842: // since we throw away stack trace of the original exception we
0843: // create a new log message here
0844: env.logWriter.newEntry(this , "invokeObject()", e,
0845: LogWriter.WARN);
0846: throw new OzoneInternalExc(e.toString(), e);
0847: }
0848: }
0849:
0850: public Object invokeObject(ObjectID id, int methodIndex,
0851: Object[] args, int lockLevel) throws Exception,
0852: org.ozoneDB.ExceptionInOzoneObjectException {
0853: if (env.logWriter.hasTarget(LogWriter.DEBUG3)) {
0854: env.logWriter.newEntry(this , "invokeObject(," + methodIndex
0855: + "): start.", LogWriter.DEBUG3);
0856: }
0857:
0858: try {
0859: try {
0860: ObjectContainer container = acquireObjectAndPin(id,
0861: lockLevel);
0862:
0863: if (container == null) {
0864: System.out.println("***************** Null here!");
0865: }
0866:
0867: try {
0868: env.getGarbageCollector().interceptInvocationPre(
0869: this , container, args);
0870:
0871: Object result = null;
0872:
0873: try {
0874: result = container.invokeTarget(env,
0875: methodIndex, args);
0876: } finally {
0877: env.getGarbageCollector()
0878: .interceptInvocationPost(this ,
0879: container, result);
0880: }
0881:
0882: return result;
0883: } finally {
0884: releaseObjectAndUnpin(container);
0885: }
0886:
0887: // using the container after the invoke is dangerous because
0888: // it's possibly deactivated meanwhile
0889: } catch (InvocationTargetException e) {
0890: Throwable ee = e.getTargetException();
0891:
0892: if (ee instanceof org.ozoneDB.core.TransactionError) {
0893: throw (org.ozoneDB.core.TransactionError) ee;
0894: }
0895:
0896: if (ee instanceof ExceptionInOzoneObjectException)
0897: throw (ExceptionInOzoneObjectException) ee;
0898:
0899: throw new ExceptionInOzoneObjectException("caught", ee);
0900: /*
0901: if (ee instanceof RuntimeException) {
0902: throw (RuntimeException)ee;
0903: }
0904: else if (ee instanceof Exception) {
0905: throw (Exception)ee;
0906: }
0907: else if (ee instanceof Error) {
0908: throw (Error)ee;
0909: }
0910: else {
0911: throw new Exception( "Unknown exception type " + ee.getClass().getName() );
0912: }
0913: */
0914: } catch (ExceptionInOzoneObjectException e) {
0915: throw e;
0916: } catch (OzoneRemoteExc e) {
0917: env.logWriter.newEntry(this , "invokeObject()", e,
0918: LogWriter.WARN);
0919: throw e;
0920: } catch (Exception e) {
0921: // since we throw away stack trace of the original exception we
0922: // create a new log message here
0923: env.logWriter.newEntry(this , "invokeObject()", e,
0924: LogWriter.WARN);
0925: throw new OzoneInternalExc(e.toString(), e);
0926: }
0927: } finally {
0928: if (env.logWriter.hasTarget(LogWriter.DEBUG3)) {
0929: env.logWriter.newEntry(this , "invokeObject(,"
0930: + methodIndex + "): end.", LogWriter.DEBUG3);
0931: }
0932: }
0933: }
0934:
0935: public void nameObject(ObjectID id, String name) throws Exception {
0936: if (false && env.logWriter.hasTarget(LogWriter.DEBUG3)) {
0937: env.logWriter.newEntry(this , "nameObject()",
0938: LogWriter.DEBUG3);
0939: }
0940:
0941: try {
0942: ObjectContainer container = acquireObjectAndPin(id,
0943: Lock.LEVEL_WRITE);
0944:
0945: try {
0946: ObjectContainer oldContainerWithThatName = env.storeManager
0947: .containerForNameAndPin(this , name);
0948:
0949: if (oldContainerWithThatName != null) {
0950: oldContainerWithThatName.unpin();
0951: throw new PermissionDeniedExc("Root object name '"
0952: + name + "' already exists.");
0953: }
0954:
0955: env.storeManager.nameContainer(this , container, name);
0956: } finally {
0957: releaseObjectAndUnpin(container);
0958: }
0959: } catch (OzoneRemoteExc e) {
0960: throw e;
0961: } catch (Exception e) {
0962: env.logWriter.newEntry(this , "nameObject()", e,
0963: LogWriter.WARN);
0964: throw new OzoneInternalExc(e.toString(), e);
0965: }
0966: }
0967:
0968: public OzoneProxy objectForName(String name) throws Exception {
0969: if (env.logWriter.hasTarget(LogWriter.DEBUG3)) {
0970: env.logWriter.newEntry(this , "objectForName()",
0971: LogWriter.DEBUG3);
0972: }
0973:
0974: // check (and wait) if a thread runs exclusively;
0975: env.transactionManager.checkExclusion();
0976:
0977: try {
0978: ObjectContainer container = env.storeManager
0979: .containerForNameAndPin(this , name);
0980: if (container != null) {
0981: try {
0982: return container.ozoneProxy();
0983: } finally {
0984: container.unpin();
0985: }
0986: } else {
0987: return null;
0988: }
0989: } catch (OzoneRemoteExc e) {
0990: throw e;
0991: } catch (Exception e) {
0992: env.logWriter.newEntry(this , "objectForName()", e,
0993: LogWriter.WARN);
0994: throw new OzoneInternalExc(e.toString(), e);
0995: }
0996: }
0997:
0998: public OzoneProxy objectForID(ObjectID id) throws Exception {
0999: if (env.logWriter.hasTarget(LogWriter.DEBUG3)) {
1000: env.logWriter.newEntry(this , "objectForID()",
1001: LogWriter.DEBUG3);
1002: }
1003:
1004: // check (and wait) if a thread runs exclusively;
1005: env.transactionManager.checkExclusion();
1006:
1007: try {
1008: /*
1009: ObjectContainer container = env.storeManager.containerForID( this, id );
1010: if (container != null) {
1011: return container.ozoneProxy();
1012: } else {
1013: return null;
1014: }
1015: */
1016: ObjectContainer container = env.storeManager
1017: .containerForIDAndPin(this , id);
1018: if (container != null) {
1019: try {
1020: return container.ozoneProxy();
1021: } finally {
1022: container.unpin();
1023: }
1024: } else {
1025: return null;
1026: }
1027: } catch (OzoneRemoteExc e) {
1028: throw e;
1029: } catch (Exception e) {
1030: env.logWriter.newEntry(this , "objectForID()", e,
1031: LogWriter.WARN);
1032: throw new OzoneInternalExc(e.toString());
1033: }
1034: }
1035:
1036: public void sleep(long millis) {
1037: try {
1038: sleeping = true;
1039:
1040: if (false) {
1041: Thread.currentThread().sleep(millis);
1042: } else {
1043: synchronized (this ) {
1044: this .wait(millis);
1045: }
1046: }
1047: } catch (Exception e) {
1048: env.logWriter.newEntry(this , "caught while sleeping", e,
1049: LogWriter.ERROR);
1050: } finally {
1051: sleeping = false;
1052: }
1053: }
1054:
1055: protected boolean isSleeping() {
1056: return sleeping;
1057: }
1058:
1059: public TransactionID taID() {
1060: return taID;
1061: }
1062:
1063: public boolean equals(Object obj) {
1064: return hashCode() == obj.hashCode();
1065: }
1066:
1067: public String toString() {
1068: // return "ta[" + (byte)taID.value() + "]";
1069: return "ta[id=" + taID + ",blocker=" + blocker + "]";
1070: }
1071:
1072: public void finalize() throws Throwable {
1073: // env.logWriter.newEntry( this, this+".finalize()", LogWriter.DEBUG );
1074: }
1075:
1076: public SimpleArrayList getCallStack() {
1077: return callStack;
1078: }
1079:
1080: public TransactionManager getManager() {
1081: return env.transactionManager;
1082: }
1083: }
|