KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > ozoneDB > core > Transaction


1 // You can redistribute this software and/or modify it under the terms of
2
// the Ozone Core License version 1 published by ozone-db.org.
3
//
4
// The original code and portions created by SMB are
5
// Copyright (C) 1997-@year@ by SMB GmbH. All rights reserved.
6
//
7
// $Id: Transaction.java,v 1.30 2004/03/08 19:20:17 wieslawf Exp $
8
package org.ozoneDB.core;
9
10 import java.io.IOException JavaDoc;
11 import java.lang.reflect.InvocationTargetException JavaDoc;
12
13 import org.ozoneDB.*;
14 import org.ozoneDB.DxLib.DxIterator;
15 import org.ozoneDB.DxLib.DxSet;
16 import org.ozoneDB.core.DbRemote.DbCommand;
17 import org.ozoneDB.core.dr.Lockable;
18 import org.ozoneDB.core.dr.Locker;
19 import org.ozoneDB.data.SimpleArrayList;
20 import org.ozoneDB.util.LogWriter;
21
22 /**
23  * This class represents an internal transaction.<p>
24  *
25  * Most methods of this class are synchronized. In fact, this is not strictly
26  * needed because a transaction is invoked by one thread (associated with this
27  * transaction) only.<p>
28  *
29  * All public methods are wrapped into try/catch statements to convert thrown
30  * exception into OzoneInternalException. So the client gets OzoneRemoteException, if an
31  * object could not be found or something; OzoneInternalException, if there was a
32  * critical internal error; any other exceptions were thrown by the user code.
33  *
34  *
35  * @author <a HREF="http://www.softwarebuero.de/">SMB</a>
36  * @author <A HREF="http://www.medium.net/">Medium.net</A>
37  * @version $Revision: 1.30 $Date: 2004/03/08 19:20:17 $
38  */

39 public abstract class Transaction implements Locker {
40
41     /** Status of a transaction: transaction is not active. */
42     public final static int STATUS_NONE = 1;
43
44     /** Status of a transaction: transaction has been started. */
45     public final static int STATUS_STARTED = 2;
46
47     /** Status of a transaction: transaction is about to prepare. */
48     public final static int STATUS_PREPARING = 3;
49
50     /** Status of a transaction: transaction has been successfully prepared. */
51     public final static int STATUS_PREPARED = 4;
52
53     /** Status of a transaction: transaction is about to commit.*/
54     public final static int STATUS_COMMITING = 5;
55
56     /** Status of a transaction: transaction has been successfully committed. */
57     public final static int STATUS_COMMITED = 6;
58
59     /** Status of a transaction: transaction is about to abort. */
60     public final static int STATUS_ABORTING = 7;
61
62     /** Status of a transaction: transaction has been aborted. */
63     public final static int STATUS_ABORTED = 8;
64
65     public final static int HASHTABLE_INIT_SIZE = 100;
66
67     /**
68      * The environment of this object.
69      */

70     protected transient Env env;
71
72     protected TransactionID taID;
73
74     protected String JavaDoc ownerName;
75
76     protected User owner;
77
78     protected int status;
79
80     protected boolean rollbackOnly;
81
82     protected int maxLockLevel;
83
84     protected int commandCount;
85
86     /**
87      * The ID of the object (container) that blocks this transaction.
88      */

89     protected ObjectID blocker;
90     
91     protected long blockTimeout;
92
93     protected long startTime;
94
95     protected int acquireCount;
96
97     protected boolean stopped;
98
99     /**
100      Are we deadlocked?
101      */

102     protected boolean deadlocked;
103
104     /**
105      The minimum deadlockWaitTimeMaximum can have. (default: 1 second)
106      */

107     protected final static long deadlockWaitTimeMaximumMinimum = 1 * 1000;
108
109     /**
110      The maximum deadlockWaitTimeMaximum can have. (default: 30 minutes)
111      */

112     protected final static long deadlockWaitTimeMaximumMaximum = 30 * 60 * 1000;
113
114     /**
115      The maximum time (in milliseconds) to wait after a deadlock.
116      */

117     protected long deadlockWaitTimeMaximum;
118
119     /**
120      Is this thread sleeping?
121      */

122     protected boolean sleeping;
123
124     /**
125      The list of {@link ObjectContainer}s which are called by this transactions but where the call
126      is not completed. The last object called is represented by the {@link ObjectContainer} with
127      the greatest index in the list.
128      */

129     protected SimpleArrayList callStack;
130
131
132     /**
133      * Construct a new transaction.
134      *
135      *
136      * @param env Environment of this transaction.
137      * @param owner User that has started this transaction.
138      */

139     protected Transaction(Env env, User owner) {
140         this.env = env;
141         taID = new TransactionID(env.keyGenerator.nextID());
142         this.owner = owner;
143
144         callStack = new SimpleArrayList(40);
145         reset();
146     }
147
148
149     /**
150      * Construct a new transaction. THIS TRANSACTION CAN BE USED FOR TESTING
151      * ONLY!
152      */

153     protected Transaction(TransactionID _taID) {
154         taID = _taID;
155         reset();
156     }
157
158
159     public synchronized void stop() {
160         stopped = true;
161     }
162
163
164     public void reset() {
165         startTime = System.currentTimeMillis();
166         status = STATUS_STARTED;
167         commandCount = 0;
168         callStack.clear();
169         deadlocked = false;
170         if (deadlockWaitTimeMaximum == 0) {
171             deadlockWaitTimeMaximum = deadlockWaitTimeMaximumMinimum;
172         }
173     }
174
175     protected void setDeadlockWaitTimeMaximum(long to) {
176         deadlockWaitTimeMaximum = to;
177     }
178
179     protected long getDeadlockWaitTimeMaximum() {
180         return deadlockWaitTimeMaximum;
181     }
182
183     protected long increaseDeadlockWaitTimeMaximum() {
184         long newDeadlockWaitTimeMaximum = (long) (getDeadlockWaitTimeMaximum() * 1.5);
185
186         if (newDeadlockWaitTimeMaximum > deadlockWaitTimeMaximumMaximum) {
187             newDeadlockWaitTimeMaximum = deadlockWaitTimeMaximumMaximum;
188         }
189
190         setDeadlockWaitTimeMaximum(newDeadlockWaitTimeMaximum);
191
192         return newDeadlockWaitTimeMaximum;
193     }
194
195     public void setDeadlocked(boolean to) {
196 // env.logWriter.newEntry(this,toString()+".setDeadlocked("+to+").", LogWriter.DEBUG2);
197
deadlocked = to;
198     }
199
200     public boolean isDeadlocked() {
201         return deadlocked;
202     }
203
204     public int status() {
205         return status;
206     }
207
208
209     public User owner() {
210         return owner;
211     }
212
213
214     public int maxLockLevel() {
215         return maxLockLevel;
216     }
217
218     /**
219      The corresponding method to {@link #acquireObject}.
220      <DIV>
221      It calls on passivate and unpins the container
222      </DIV>
223      */

224     public void releaseObject(ObjectContainer objectContainer) {
225         if (objectContainer.isPinned()) {
226             callOnPassivateIfNeeded(objectContainer);
227             objectContainer.unpin();
228         } else {
229             if (env.logWriter.hasTarget(LogWriter.DEBUG)) {
230                 env.logWriter.newEntry(this, toString() + " debris from aborted cluster, " + objectContainer, LogWriter.DEBUG);
231             }
232         }
233     }
234
235     protected void callOnPassivateIfNeeded(ObjectContainer container) {
236         if (container.shouldOnPassivateBeCalled()) {
237                 container.invokeOnPassivate();
238         }
239     }
240
241
242     /**
243      * Set a lock on the container specified by the given object ID and join
244      * the container to this transaction.
245      * If a container is returned, it is pinned. Thus, it has to be unpinned by the caller.
246      *
247      *
248      * @param id ObjectID of the container which we try to join to this transaction.
249      * @param lockLevel The lock level we need on this object (container).
250      * @return The container for the specified id, if all was ok.
251      * @throws ObjectNotFoundException If there is no such object.
252      */

253     public ObjectContainer acquireObject(ObjectID id, int lockLevel) throws ObjectNotFoundException, IOException JavaDoc, ClassNotFoundException JavaDoc, TransactionException, TransactionError {
254
255         // this is not good style but this method is a hotspot and we should
256
// do all we can to make it fast
257
if (env.transactionManager.exclusiveThread != null &&
258                 env.transactionManager.exclusiveThread != Thread.currentThread()) {
259             env.transactionManager.checkExclusion();
260         }
261
262         ObjectContainer container = env.storeManager.containerForID(this, id);
263
264         if (container == null) {
265             throw new ObjectNotFoundException("No such object ID: " + id);
266         }
267
268         boolean allright = false;
269
270         try {
271             container = acquireContainer(container, lockLevel);
272
273             callOnActivateIfNeeded(container);
274
275             allright = true;
276             return container;
277         } catch (Exception JavaDoc e) {
278             throw new TransactionException(e.getMessage(), e);
279         } finally {
280             if (!allright) {
281                 container.unpin();
282             }
283         }
284     }
285
286     protected void callOnActivateIfNeeded(ObjectContainer container) {
287         if (container.shouldOnActivateBeCalled()) {
288
289             // We should intercept invocations here, if we had arguments and return values. But we don't.
290
// env.getGarbageCollector().interceptInvocationPre(this, container, args);
291

292             // try {
293
container.invokeOnActivate();
294             // } finally {
295
// env.getGarbageCollector().interceptInvocationPost(this, container, result);
296
// }
297
}
298     }
299
300
301     protected ObjectContainer acquireContainer(ObjectContainer container, int lockLevel) throws PermissionError, TransactionException, TransactionError, IOException JavaDoc, ObjectNotFoundException, ClassNotFoundException JavaDoc {
302
303         if (stopped == true) {
304             throw new TransactionException("Stopped.", TransactionException.STOPPED);
305         }
306
307         maxLockLevel = lockLevel > maxLockLevel ? lockLevel : maxLockLevel;
308
309         acquireCount++;
310
311         // this should help to let the following code execute without
312
// interrupt and so ensure that the container that we retrieve from
313
// the store is not deactivated while this method is running
314
// Thread.currentThread().yield();
315

316         // transaktion als blockiert markieren (kante in lock-graphen einfuegen);
317
// vor deadlock-erkennung: es werden auch deadlocks mit
318
// transaktionen erkannt, die selber erstmal auf deadlock checken
319
// aber auf keinem fall zuwenige (race-cond. zwischen deadlock-pruefung
320
// und lock setzen)
321
blocker = container.id();
322         blockTimeout = System.currentTimeMillis() + 100;
323
324         // this may happen when the container was deactivated between
325
// acquireObject() and this point; I'm not sure what to do here
326

327         // But I (Xuân Baldauf, Medium.net) am (partly):
328
// If our caller is acquireContainer(), the container is pinned and thus may not be deactived inbetween.
329
// If our caller is createObject(), the container is pinned and thus may not be deactived inbetween.
330
if (container.lock() == null) {
331             throw new IllegalStateException JavaDoc("Container was wrongly deactivated. Increasing heap memory of the JVM may help.");
332         }
333
334         // try to aquire the lock of the container; wait until the locks is
335
// successfully aquired
336
int prevLevel = container.lock().tryAcquire(this, lockLevel);
337
338
339         // TODO: FIXME: HACK: prevents strange seldom occuring hang; somewhere
340
// it is possible that a tx ends, but is still listed as locking a
341
// cluster. This tx would then wait() to be notified by that other tx
342
// once it gives up its lock on that container, but since that other tx
343
// has already stopped there is no way this tx will ever be notify()ed.
344
// This hack is repairing the damage done by unlocking a cluster locked
345
// by 'ghost' tx-es. We should find out where the real cause is...
346
if (prevLevel == Lock.NOT_ACQUIRED) {
347             DxIterator i = container.lock().lockerIDs().iterator();
348             TransactionID txID;
349             while ((txID = (TransactionID) i.next()) != null) {
350                 Transaction tx = env.transactionManager.taForID(txID);
351                 if (tx == null) {
352                     env.logWriter.newEntry(this, " lock " + container.lock() + " locked by txID "
353                             + txID + ", but that tx does not exist anymore; compensating... Please report this error to the ozone developers list", LogWriter.ERROR);
354                     
355                     // locks only use the transactions id, so this should work
356
Transaction hack = new FixHack(txID);
357                     container.lock().release(hack);
358                 }
359             }
360             prevLevel = container.lock().tryAcquire(this, lockLevel);
361         }
362         // end of HACK,
363

364
365         if (prevLevel == Lock.NOT_ACQUIRED) {
366             synchronized (this) {
367                 while (prevLevel == Lock.NOT_ACQUIRED) {
368                     try {
369                         if (env.logWriter.hasTarget(LogWriter.DEBUG2)) {
370                             env.logWriter.newEntry(this, toString() + " blocked by lock " + container.lock() + "...", LogWriter.DEBUG2);
371                         }
372
373                         wait();
374
375                         if (env.logWriter.hasTarget(LogWriter.DEBUG2)) {
376                             env.logWriter.newEntry(this, toString() + " checking lock again...", LogWriter.DEBUG2);
377                         }
378                     } catch (Exception JavaDoc e) {
379                         // do nothing; just proceed...
380
}
381
382                     /*
383                         We have two cases:
384                         (1) We are called by acquireObject()
385                         (2) We are not called by acquireObject()
386
387                         In case (1), we do not need to reload, because the object is pinned.
388                         In case (2), we never come to this code location, because in this case, the objects are freshly created and thus never locked.
389
390                         Thus, we never need to reload.
391
392                         Oh, the reasoning above does not work out. If a cluster is pinned,
393                         it still may be aborted and thus need to reload. But maybe then the
394                         "pinned" concept is mood. Maybe pinned clusters which are arborted
395                         should be reloaded immediately.
396                     */

397
398                     // since the container was maybe deactivated while waiting we
399
// reload it here again
400
ObjectContainer newContainer = env.storeManager.containerForID(this, blocker);
401
402                     if (container == null) {
403                         throw new ObjectNotFoundException("No such object.");
404                     }
405
406                     if (container != newContainer ) {
407                         // the container has been deactivated
408
if (container.isPinned()) {
409                             // pinCount moving
410
while (container.isPinned()) {
411                                 newContainer.pin();
412                                 container.unpin();
413                             }
414                             // remove additional pin which is set during container reloading
415
newContainer.unpin();
416                             // remove additional pin which is set during loadCluster() just after unloadCluster()
417
// see: ClusterStore.abortCluster();
418
newContainer.unpin();
419                         }
420                         container = newContainer;
421                     }
422                     // remove additional pin which was set during container reloading
423
// it occurs while container reloading if the "newContainer" is a same as the "container"
424
container.unpin();
425
426                     // throw an exception if we are forced to abort because of a deadlock
427
container.lock().checkDeadlock(this);
428
429                     prevLevel = container.lock().tryAcquire(this, lockLevel);
430                 }
431             }
432         }
433
434         if (env.logWriter.hasTarget(LogWriter.DEBUG1)) {
435             env.logWriter.newEntry(this, toString() + ".acquireContainer(" + blocker + "): successful.", LogWriter.DEBUG1);
436         }
437
438         // transaction is no longer blocked
439
blocker = null;
440
441         // after acquiring the lock we update the lock level of the container
442
if (prevLevel < lockLevel) {
443             if (owner == null) {
444                 throw new PermissionError("No such user.");
445             }
446             if (!env.userManager.checkPermission(owner, container, lockLevel)) {
447                 throw new PermissionError("User does not have proper access rights.");
448             }
449
450             env.storeManager.updateLockLevel(this, container);
451         }
452         container.touch();
453
454         return container;
455     }
456
457     /**
458         A user calls {@link OzoneObject#requireWriteLocking}.
459
460         This means that no user-visible declaed exceptions can be thrown. Thus,
461         the same measures regarding catching and wrapping exceptions have to be taken as in {@link #invokeObject}.
462     */

463     public void requireWriteLockingCallByUser(ObjectContainer container) {
464         try {
465             ObjectContainer result = acquireContainer(container,Lock.LEVEL_WRITE);
466
467             /*
468                 Note that we ignore the result from acquireContainer.
469                 But this should be safe, as acquireContainer should not be able to reload our container,
470                 because our container is the container which calls us. If acquireContainer did reload,
471                 we would be in trouble, and this would be a bug.
472             */

473
474             assert result==container;
475         } catch (OzoneObjectException e) {
476             throw e;
477         } catch (OzoneRemoteException e) {
478             env.logWriter.newEntry(this, "invokeObject()", e, LogWriter.WARN);
479             throw e;
480         } catch (Exception JavaDoc e) {
481             // since we throw away stack trace of the original exception we
482
// create a new log message here
483
env.logWriter.newEntry(this, "invokeObject()", e, LogWriter.WARN);
484             throw new OzoneInternalException(e.toString(), e);
485         }
486     }
487
488
489     public boolean performCommand(DbCommand command) {
490         if (env.logWriter.hasTarget(LogWriter.DEBUG)) {
491             env.logWriter.newEntry(this, "performCommand(): " + toString() + ", " + command.toString(), LogWriter.DEBUG);
492         }
493
494         commandCount++;
495
496         boolean result = true;
497         try {
498             // result goes in command.result
499
command.perform(this);
500         } catch (TransactionError e) {
501             throw e;
502         } catch (Throwable JavaDoc e) {
503             Throwable JavaDoc resultingException = e;
504
505             if (e instanceof OzoneObjectException) {
506                 // 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.
507
Throwable JavaDoc cause = e.getCause();
508
509                 env.logWriter.newEntry(this, toString() + ": exception in ozone object: (" + e + "): ", e, LogWriter.DEBUG1);
510                 env.logWriter.newEntry(this, toString() + ": cause:", cause, LogWriter.DEBUG1);
511
512 // resultingException = cause;
513
} else {
514                 env.logWriter.newEntry(this, toString() + ": uncaught exception: (" + e + ")", e, LogWriter.WARN);
515             }
516
517             if (e instanceof PermissionError) {
518                 e = new PermissionDeniedException(e.toString());
519             }
520
521             rollbackOnly = true;
522             command.result = resultingException;
523             result = false;
524         }
525         return result;
526     }
527
528
529     public synchronized void prepareCommit() throws IOException JavaDoc, ClassNotFoundException JavaDoc {
530         if (env.logWriter.hasTarget(LogWriter.DEBUG3)) {
531             env.logWriter.newEntry(this, "==> PREPARECOMMIT() ", LogWriter.DEBUG3);
532         }
533         status = STATUS_PREPARING;
534         env.storeManager.prepareCommitTransaction(this);
535         status = STATUS_PREPARED;
536     }
537
538
539     /**
540      * Commit this transaction. The transaction has to be in PREPARED state.
541      * Ones this method is called it MUST commit the entire transaction
542      * stuff without any exception.
543      */

544     public synchronized void commit() throws IOException JavaDoc, ClassNotFoundException JavaDoc {
545         if (env.logWriter.hasTarget(LogWriter.DEBUG1)) {
546             env.logWriter.newEntry(this, "==> COMMIT() ", LogWriter.DEBUG1);
547         }
548
549         status = STATUS_COMMITING;
550         try {
551             env.storeManager.commitTransaction(this);
552         } finally {
553             blocker = null;
554         }
555         status = STATUS_COMMITED;
556     }
557
558     /**
559      * Once this method is called it MUST cleanup the entire transaction
560      * stuff without exception. An exception signals an internal server error.
561      * <p>
562      * Note: This may be called after/from prepareCommit() !
563      */

564     public synchronized void abort(DbCommand command) throws IOException JavaDoc, ClassNotFoundException JavaDoc {
565         if (env.logWriter.hasTarget(LogWriter.DEBUG1)) {
566             env.logWriter.newEntry(this, "==> ABORT() ", LogWriter.DEBUG1);
567         }
568
569         status = STATUS_ABORTING;
570         try {
571             env.storeManager.abortTransaction(this);
572         } finally {
573             // FIXME: We better do not delete the data now. Somewhere it is used again. (Maybe in case of deadlock retry?)
574
blocker = null;
575         }
576         status = STATUS_ABORTED;
577     }
578
579
580     /**
581      * Helper method to implement the Locker interface to support deadlock
582      * recognition via core.dr package
583      */

584     public Lockable blockedBy() {
585         try {
586             return blocker != null ? (Lockable) env.storeManager.containerForID(this, blocker) : null;
587         } catch (NullPointerException JavaDoc e) {
588             env.logWriter.newEntry(this, "blockedBy(): Our blocker is invalidated. We are not blocked anymore?", e, LogWriter.ERROR);
589
590             blocker = null;
591
592             return null;
593         } catch (Exception JavaDoc e) {
594             env.logWriter.newEntry(this, "blockedBy() ", e, LogWriter.ERROR);
595             throw new RuntimeException JavaDoc("blockedBy() FAILED!");
596         }
597     }
598
599     /**
600      Returns wether this locker is blocked.
601      */

602     public boolean isBlocked() {
603         return (blocker != null && System.currentTimeMillis() > blockTimeout);
604     }
605
606     /**
607      * Create a new database object. If the className is null, an empty container
608      * is created.
609      *
610      * @param className
611      * @param access
612      * @param name
613      * @param id The ID of the new container or null.
614      * @exception PermissionDeniedException If user in invalid, name is already in
615      * use, target is not OzoneCompatible...
616      */

617     public ObjectContainer createObject(String JavaDoc className, int access, String JavaDoc name, String JavaDoc sig, Object JavaDoc[] args, ObjectID id) throws Exception JavaDoc, org.ozoneDB.OzoneObjectException {
618         if (env.logWriter.hasTarget(LogWriter.DEBUG3)) {
619             env.logWriter.newEntry(this, "createObject() ", LogWriter.DEBUG3);
620         }
621
622         // check (and wait) if a thread runs exclusively;
623
env.transactionManager.checkExclusion();
624
625         try {
626             Class JavaDoc cl = null;
627             if (className != null) {
628                 cl = env.classManager.classForName(className);
629             }
630
631             Permissions perms = new Permissions(owner, access);
632
633             if (id == null) {
634                 id = new ObjectID(env.keyGenerator.nextID());
635             }
636
637             ObjectContainer container = env.storeManager.newContainerAndLock(this, null, id, perms, Lock.LEVEL_WRITE);
638
639             boolean alright = false;
640             boolean containerAcquired = false;
641
642             try {
643                 container = acquireContainer(container, Lock.LEVEL_WRITE);
644                 containerAcquired = true;
645
646                 if (cl != null) {
647                     container.setShouldCallOnActivate(false);
648                     container.createTarget(env, cl, sig, args);
649                     container.target().onCreate();
650                 }
651
652                 if (name != null) {
653                     nameObject(container.id(), name);
654                 }
655
656                 alright = true;
657
658                 return container;
659             } finally {
660                 if (!containerAcquired) {
661                     /*
662                         We have had acquired a lock but somehow did not manage to acquire the corresponding container.
663                         Thus, the cluster would not be added to this transaction and thus it would not be unlocked
664                         when the transaction is finished. Thus we have to unlock it now.
665                     */

666                     container./*getCluster().getLock().*/lock().release(this);
667                     /*
668                         But is this the right behaviour? What if acquireContainer() fails for some reason (e.g. PermissionError)
669                         after it locked the cluster itself. Then we would unlock it while it should remain locked? Should it
670                         if it fails with an exception?
671                     */

672                 }
673                 if (!alright) {
674                     container.unpin();
675                 }
676             }
677         } catch (InvocationTargetException JavaDoc e) {
678             Throwable JavaDoc ee = e.getTargetException();
679
680             if (ee instanceof org.ozoneDB.core.TransactionError) {
681                 throw (org.ozoneDB.core.TransactionError) ee;
682             }
683
684             if (ee instanceof OzoneObjectException)
685                 throw (OzoneObjectException) ee;
686
687             throw new org.ozoneDB.OzoneObjectException("caught", ee);
688             /*
689             if (ee instanceof RuntimeException) {
690                 throw (RuntimeException)ee;
691             } else if (ee instanceof Exception) {
692                 throw (Exception)ee;
693             } else if (ee instanceof Error) {
694                 throw (Error)ee;
695             } else {
696                 throw new Exception( "Unknown exception type " + ee.getClass().getName() );
697             }
698             */

699         } catch (OzoneObjectException e) {
700             throw e;
701         } catch (OzoneRemoteException e) {
702             throw e;
703         } catch (Exception JavaDoc e) {
704             env.logWriter.newEntry(this, "createObject()", e, LogWriter.WARN);
705             throw new OzoneInternalException(e.toString(), e);
706         }
707     }
708
709
710     public ObjectContainer copyObject(ObjectID id) throws Exception JavaDoc {
711         if (env.logWriter.hasTarget(LogWriter.DEBUG3)) {
712             env.logWriter.newEntry(this, "copyObject() ", LogWriter.DEBUG3);
713         }
714
715         // check (and wait) if a thread runs exclusively;
716
env.transactionManager.checkExclusion();
717
718         try {
719             if (env.logWriter.hasTarget(LogWriter.DEBUG3)) {
720                 env.logWriter.newEntry(this, "copyObject(): " + id.toString(), LogWriter.DEBUG3);
721             }
722
723             ObjectContainer container = acquireObject(id, Lock.LEVEL_WRITE);
724
725             try {
726                 Object JavaDoc target = container.targetClone();
727                 Permissions perms = (Permissions) container.permissions().clone();
728                 ObjectContainer copyContainer = env.storeManager.newContainerAndLock(this, (OzoneCompatible) target, new ObjectID(env.keyGenerator.nextID()), perms, Lock.LEVEL_WRITE);
729                 boolean alright = false;
730
731                 try {
732                     copyContainer = acquireContainer(copyContainer, Lock.LEVEL_WRITE);
733                     alright = true;
734                     return copyContainer;
735                 } finally {
736                     if (!alright) {
737                         copyContainer.unpin();
738                     }
739                 }
740             } finally {
741                 releaseObject(container);
742             }
743         } catch (OzoneRemoteException e) {
744             throw e;
745         } catch (Exception JavaDoc e) {
746             env.logWriter.newEntry(this, "copyObject()", e, LogWriter.WARN);
747             throw new OzoneInternalException(e.toString(), e);
748         }
749     }
750
751
752     public void deleteObject(ObjectID id) throws ObjectNotFoundException, IOException JavaDoc, ClassNotFoundException JavaDoc, TransactionException, TransactionError, OzoneRemoteException, OzoneInternalException, OzoneObjectException {
753         if (env.logWriter.hasTarget(LogWriter.DEBUG3)) {
754             env.logWriter.newEntry(this, "deleteObject(): " + id.toString(), LogWriter.DEBUG3);
755         }
756
757         try {
758
759             ObjectContainer container = acquireObject(id, Lock.LEVEL_WRITE);
760             try {
761                 try {
762                     container.target().onDelete();
763                 } catch (OzoneRemoteException e) {
764                     throw e;
765                 } catch (OzoneObjectException e) {
766                     throw e;
767                 } catch (Throwable JavaDoc e) {
768                     env.logWriter.newEntry(this, "deleteObject()", e, LogWriter.WARN);
769 // throw new OzoneInternalException( e.toString() );
770
throw new OzoneObjectException("caught onDelete()", e);
771                 }
772                 // avoid onPassivate() being called
773
container.setShouldCallOnPassivate(false);
774                 container.deleteTarget();
775             } finally {
776                 releaseObject(container);
777             }
778         } catch (OzoneRemoteException e) {
779             throw e;
780         } catch (Exception JavaDoc e) {
781             env.logWriter.newEntry(this, "deleteObject()", e, LogWriter.WARN);
782             throw new OzoneInternalException(e.toString(), e);
783         }
784     }
785
786
787     /**
788      * @param id
789      * @param methodName
790      * @param sig
791      * @param lockLevel
792      * @return the result of the invocation
793      */

794     public Object JavaDoc invokeObject(ObjectID id, String JavaDoc methodName, String JavaDoc sig, Object JavaDoc[] args, int lockLevel) throws Exception JavaDoc, org.ozoneDB.OzoneObjectException {
795         if (env.logWriter.hasTarget(LogWriter.DEBUG3)) {
796             env.logWriter.newEntry(this, "invokeObject(): " + methodName, LogWriter.DEBUG3);
797         }
798
799         try {
800             ObjectContainer container = acquireObject(id, lockLevel);
801
802             try {
803                 env.getGarbageCollector().interceptInvocationPre(this, container, args);
804
805                 Object JavaDoc result = null;
806
807                 try {
808                     result = container.invokeTarget(env, methodName, sig, args);
809                 } finally {
810                     env.getGarbageCollector().interceptInvocationPost(this, container, result);
811                 }
812
813                 return result;
814             } finally {
815                 releaseObject(container);
816             }
817             // using the container after the invoke is dangerous because
818
// it's possibly deactivated meanwhile
819
} catch (InvocationTargetException JavaDoc e) {
820             Throwable JavaDoc ee = e.getTargetException();
821
822             if (ee instanceof org.ozoneDB.core.TransactionError) {
823                 throw (org.ozoneDB.core.TransactionError) ee;
824             }
825
826             if (ee instanceof OzoneObjectException)
827                 throw (OzoneObjectException) ee;
828
829             throw new org.ozoneDB.OzoneObjectException("caught", ee);
830
831             /*
832             if (ee instanceof RuntimeException) {
833                 throw (RuntimeException)ee;
834             } else if (ee instanceof Exception) {
835                 throw (Exception)ee;
836             } else if (ee instanceof Error) {
837                 throw (Error)ee;
838             } else {
839                 throw new Exception( "Unknown exception type " + ee.getClass().getName() );
840             }
841             */

842         } catch (OzoneObjectException e) {
843             throw e;
844         } catch (OzoneRemoteException e) {
845             env.logWriter.newEntry(this, "invokeObject()", e, LogWriter.WARN);
846             throw e;
847         } catch (Exception JavaDoc e) {
848             // since we throw away stack trace of the original exception we
849
// create a new log message here
850
env.logWriter.newEntry(this, "invokeObject()", e, LogWriter.WARN);
851             throw new OzoneInternalException(e.toString(), e);
852         }
853     }
854
855
856     public Object JavaDoc invokeObject(ObjectID id, int methodIndex, Object JavaDoc[] args, int lockLevel) throws Exception JavaDoc, org.ozoneDB.OzoneObjectException {
857         if (env.logWriter.hasTarget(LogWriter.DEBUG3)) {
858             env.logWriter.newEntry(this, "invokeObject(," + methodIndex + "): start.", LogWriter.DEBUG3);
859         }
860
861         try {
862             try {
863                 ObjectContainer container = acquireObject(id, lockLevel);
864
865                 if (container == null) {
866                     env.logWriter.newEntry(this, "container is null!.", LogWriter.WARN);
867                 }
868
869                 try {
870                     env.getGarbageCollector().interceptInvocationPre(this, container, args);
871
872                     Object JavaDoc result = null;
873
874                     try {
875                         result = container.invokeTarget(env, methodIndex, args);
876                     } finally {
877                         env.getGarbageCollector().interceptInvocationPost(this, container, result);
878                     }
879
880                     return result;
881                 } finally {
882                     releaseObject(container);
883                 }
884
885                 // using the container after the invoke is dangerous because
886
// it's possibly deactivated meanwhile
887
} catch (InvocationTargetException JavaDoc e) {
888                 Throwable JavaDoc ee = e.getTargetException();
889
890                 if (ee instanceof org.ozoneDB.core.TransactionError) {
891                     throw (org.ozoneDB.core.TransactionError) ee;
892                 }
893
894                 if (ee instanceof OzoneObjectException)
895                     throw (OzoneObjectException) ee;
896
897                 throw new OzoneObjectException("caught", ee);
898                 /*
899                 if (ee instanceof RuntimeException) {
900                     throw (RuntimeException)ee;
901                 }
902                 else if (ee instanceof Exception) {
903                     throw (Exception)ee;
904                 }
905                 else if (ee instanceof Error) {
906                     throw (Error)ee;
907                 }
908                 else {
909                     throw new Exception( "Unknown exception type " + ee.getClass().getName() );
910                 }
911                 */

912             } catch (OzoneObjectException e) {
913                 throw e;
914             } catch (OzoneRemoteException e) {
915                 env.logWriter.newEntry(this, "invokeObject()", e, LogWriter.WARN);
916                 throw e;
917             } catch (Exception JavaDoc e) {
918                 // since we throw away stack trace of the original exception we
919
// create a new log message here
920
env.logWriter.newEntry(this, "invokeObject()", e, LogWriter.WARN);
921                 throw new OzoneInternalException(e.toString(), e);
922             }
923         } finally {
924             if (env.logWriter.hasTarget(LogWriter.DEBUG3)) {
925                 env.logWriter.newEntry(this, "invokeObject(," + methodIndex + "): end.", LogWriter.DEBUG3);
926             }
927         }
928     }
929
930
931     public void nameObject(ObjectID id, String JavaDoc name) throws Exception JavaDoc {
932         if (env.logWriter.hasTarget(LogWriter.DEBUG3)) {
933             env.logWriter.newEntry(this, "nameObject()", LogWriter.DEBUG3);
934         }
935
936         try {
937             ObjectContainer container = acquireObject(id, Lock.LEVEL_WRITE);
938
939             try {
940                 ObjectContainer oldContainerWithThatName = env.storeManager.containerForName(this, name);
941
942                 if (oldContainerWithThatName != null) {
943                     oldContainerWithThatName.unpin();
944                     throw new PermissionDeniedException("Root object name '" + name + "' already exists.");
945                 }
946
947                 env.storeManager.nameContainer(this, container, name);
948             } finally {
949                 releaseObject(container);
950             }
951         } catch (OzoneRemoteException e) {
952             throw e;
953         } catch (Exception JavaDoc e) {
954             env.logWriter.newEntry(this, "nameObject()", e, LogWriter.WARN);
955             throw new OzoneInternalException(e.toString(), e);
956         }
957     }
958
959     public DxSet objectNames() throws Exception JavaDoc {
960         if (env.logWriter.hasTarget(LogWriter.DEBUG3)) {
961             env.logWriter.newEntry(this, "objectNames()", LogWriter.DEBUG3);
962         }
963
964         // check (and wait) if a thread runs exclusively;
965
env.transactionManager.checkExclusion();
966
967         try {
968             return env.storeManager.objectNames(this);
969
970         } catch (OzoneRemoteException e) {
971             throw e;
972         } catch (Exception JavaDoc e) {
973             env.logWriter.newEntry(this, "objectNames()", e, LogWriter.WARN);
974             throw new OzoneInternalException(e.toString(), e);
975         }
976     }
977
978     public OzoneProxy objectForName(String JavaDoc name) throws Exception JavaDoc {
979         if (env.logWriter.hasTarget(LogWriter.DEBUG3)) {
980             env.logWriter.newEntry(this, "objectForName()", LogWriter.DEBUG3);
981         }
982
983         // check (and wait) if a thread runs exclusively;
984
env.transactionManager.checkExclusion();
985
986         try {
987             ObjectContainer container = env.storeManager.containerForName(this, name);
988             if (container != null) {
989                 try {
990                     return container.ozoneProxy();
991                 } finally {
992                     container.unpin();
993                 }
994             } else {
995                 return null;
996             }
997         } catch (OzoneRemoteException e) {
998             throw e;
999         } catch (Exception JavaDoc e) {
1000            env.logWriter.newEntry(this, "objectForName()", e, LogWriter.WARN);
1001            throw new OzoneInternalException(e.toString(), e);
1002        }
1003    }
1004
1005    public OzoneProxy objectForID(ObjectID id) throws Exception JavaDoc {
1006        if (env.logWriter.hasTarget(LogWriter.DEBUG3)) {
1007            env.logWriter.newEntry(this, "objectForID()", LogWriter.DEBUG3);
1008        }
1009
1010        // check (and wait) if a thread runs exclusively;
1011
env.transactionManager.checkExclusion();
1012
1013        try {
1014            /*
1015            ObjectContainer container = env.storeManager.containerForID( this, id );
1016            if (container != null) {
1017                return container.ozoneProxy();
1018            } else {
1019                return null;
1020            }
1021            */

1022            ObjectContainer container = env.storeManager.containerForID(this, id);
1023            if (container != null) {
1024                try {
1025                    return container.ozoneProxy();
1026                } finally {
1027                    container.unpin();
1028                }
1029            } else {
1030                return null;
1031            }
1032        } catch (OzoneRemoteException e) {
1033            throw e;
1034        } catch (Exception JavaDoc e) {
1035            env.logWriter.newEntry(this, "objectForID()", e, LogWriter.WARN);
1036            throw new OzoneInternalException(e.toString());
1037        }
1038    }
1039
1040    public void sleep(long millis) {
1041        try {
1042            sleeping = true;
1043
1044            if (false) {
1045                Thread.currentThread().sleep(millis);
1046            } else {
1047                synchronized (this) {
1048                    this.wait(millis);
1049                }
1050            }
1051        } catch (Exception JavaDoc e) {
1052            env.logWriter.newEntry(this, "caught while sleeping", e, LogWriter.ERROR);
1053        } finally {
1054            sleeping = false;
1055        }
1056    }
1057
1058    protected boolean isSleeping() {
1059        return sleeping;
1060    }
1061
1062
1063    public TransactionID taID() {
1064        return taID;
1065    }
1066
1067
1068    public boolean equals(Object JavaDoc obj) {
1069        return hashCode() == obj.hashCode();
1070    }
1071
1072
1073    public String JavaDoc toString() {
1074// return "ta[" + (byte)taID.value() + "]";
1075
return "ta[id=" + taID + ",blocker=" + blocker + "]";
1076    }
1077
1078
1079    public void finalize() throws Throwable JavaDoc {
1080        env.logWriter.newEntry(this, this + ".finalize()", LogWriter.DEBUG3);
1081    }
1082
1083    public SimpleArrayList getCallStack() {
1084        return callStack;
1085    }
1086
1087    public TransactionManager getManager() {
1088        return env.transactionManager;
1089    }
1090}
1091
1092
1093class FixHack extends Transaction {
1094
1095    FixHack(TransactionID taID) {
1096        super(taID);
1097    }
1098
1099    public synchronized void stop() {
1100        throw new RuntimeException JavaDoc("should not be called here");
1101    }
1102
1103    public void reset() {
1104        // do nothing
1105
}
1106
1107    protected void setDeadlockWaitTimeMaximum(long to) {
1108        throw new RuntimeException JavaDoc("should not be called here");
1109    }
1110
1111    protected long getDeadlockWaitTimeMaximum() {
1112        throw new RuntimeException JavaDoc("should not be called here");
1113    }
1114
1115    protected long increaseDeadlockWaitTimeMaximum() {
1116        throw new RuntimeException JavaDoc("should not be called here");
1117    }
1118
1119    public void setDeadlocked(boolean to) {
1120        throw new RuntimeException JavaDoc("should not be called here");
1121    }
1122
1123    public boolean isDeadlocked() {
1124        throw new RuntimeException JavaDoc("should not be called here");
1125    }
1126
1127    public int status() {
1128        throw new RuntimeException JavaDoc("should not be called here");
1129    }
1130
1131    public User owner() {
1132        throw new RuntimeException JavaDoc("should not be called here");
1133    }
1134
1135    public int maxLockLevel() {
1136        throw new RuntimeException JavaDoc("should not be called here");
1137    }
1138
1139    public void releaseObject(ObjectContainer objectContainer) {
1140        throw new RuntimeException JavaDoc("should not be called here");
1141    }
1142
1143    protected void callOnPassivateIfNeeded(ObjectContainer container) {
1144        throw new RuntimeException JavaDoc("should not be called here");
1145    }
1146
1147    public ObjectContainer acquireObject(ObjectID id, int lockLevel) throws ObjectNotFoundException, IOException JavaDoc, ClassNotFoundException JavaDoc, TransactionException, TransactionError {
1148        throw new RuntimeException JavaDoc("should not be called here");
1149    }
1150
1151    protected void callOnActivateIfNeeded(ObjectContainer container) {
1152        throw new RuntimeException JavaDoc("should not be called here");
1153    }
1154
1155    protected ObjectContainer acquireContainer(ObjectContainer container, int lockLevel) throws PermissionError, TransactionException, TransactionError, IOException JavaDoc, ObjectNotFoundException, ClassNotFoundException JavaDoc {
1156        throw new RuntimeException JavaDoc("should not be called here");
1157    }
1158
1159    public void requireWriteLockingCallByUser(ObjectContainer container) {
1160        throw new RuntimeException JavaDoc("should not be called here");
1161    }
1162
1163    public boolean performCommand(DbCommand command) {
1164        throw new RuntimeException JavaDoc("should not be called here");
1165    }
1166
1167    public synchronized void prepareCommit() throws IOException JavaDoc, ClassNotFoundException JavaDoc {
1168        throw new RuntimeException JavaDoc("should not be called here");
1169    }
1170
1171    public synchronized void commit() throws IOException JavaDoc, ClassNotFoundException JavaDoc {
1172        throw new RuntimeException JavaDoc("should not be called here");
1173    }
1174
1175    public synchronized void abort(DbCommand command) throws IOException JavaDoc, ClassNotFoundException JavaDoc {
1176        throw new RuntimeException JavaDoc("should not be called here");
1177    }
1178
1179    public Lockable blockedBy() {
1180        throw new RuntimeException JavaDoc("should not be called here");
1181    }
1182
1183    public boolean isBlocked() {
1184        throw new RuntimeException JavaDoc("should not be called here");
1185    }
1186
1187    public ObjectContainer createObject(String JavaDoc className, int access, String JavaDoc name, String JavaDoc sig, Object JavaDoc[] args, ObjectID id) throws Exception JavaDoc, org.ozoneDB.OzoneObjectException {
1188        throw new RuntimeException JavaDoc("should not be called here");
1189    }
1190
1191    public ObjectContainer copyObject(ObjectID id) throws Exception JavaDoc {
1192        throw new RuntimeException JavaDoc("should not be called here");
1193    }
1194
1195    public void deleteObject(ObjectID id) throws ObjectNotFoundException, IOException JavaDoc, ClassNotFoundException JavaDoc, TransactionException, TransactionError, OzoneRemoteException, OzoneInternalException, OzoneObjectException {
1196        throw new RuntimeException JavaDoc("should not be called here");
1197    }
1198
1199    public Object JavaDoc invokeObject(ObjectID id, String JavaDoc methodName, String JavaDoc sig, Object JavaDoc[] args, int lockLevel) throws Exception JavaDoc, org.ozoneDB.OzoneObjectException {
1200        throw new RuntimeException JavaDoc("should not be called here");
1201    }
1202
1203    public Object JavaDoc invokeObject(ObjectID id, int methodIndex, Object JavaDoc[] args, int lockLevel) throws Exception JavaDoc, org.ozoneDB.OzoneObjectException {
1204        throw new RuntimeException JavaDoc("should not be called here");
1205    }
1206
1207    public void nameObject(ObjectID id, String JavaDoc name) throws Exception JavaDoc {
1208        throw new RuntimeException JavaDoc("should not be called here");
1209    }
1210
1211    public DxSet objectNames() throws Exception JavaDoc {
1212        throw new RuntimeException JavaDoc("should not be called here");
1213    }
1214
1215    public OzoneProxy objectForName(String JavaDoc name) throws Exception JavaDoc {
1216        throw new RuntimeException JavaDoc("should not be called here");
1217    }
1218
1219    public OzoneProxy objectForID(ObjectID id) throws Exception JavaDoc {
1220        throw new RuntimeException JavaDoc("should not be called here");
1221    }
1222
1223    public void sleep(long millis) {
1224        throw new RuntimeException JavaDoc("should not be called here");
1225    }
1226
1227    protected boolean isSleeping() {
1228        throw new RuntimeException JavaDoc("should not be called here");
1229    }
1230
1231    public TransactionID taID() {
1232        return taID;
1233    }
1234
1235    public boolean equals(Object JavaDoc obj) {
1236        throw new RuntimeException JavaDoc("should not be called here");
1237    }
1238
1239    public SimpleArrayList getCallStack() {
1240        throw new RuntimeException JavaDoc("should not be called here");
1241    }
1242
1243    public TransactionManager getManager() {
1244        throw new RuntimeException JavaDoc("should not be called here");
1245    }
1246}
1247
1248// :indentSize=4:tabSize=4:noTabs=true:
1249
Popular Tags