|
||||||||||
| PREV CLASS NEXT CLASS | FRAMES NO FRAMES | |||||||||
| SUMMARY: NESTED | FIELD | CONSTR | METHOD | DETAIL: FIELD | CONSTR | METHOD | |||||||||
java.lang.Object | +--arlut.csd.ganymede.DBEditSet
DBEditSet is the basic transactional unit. All changes to the
database during normal operations are made in the context of a
DBEditSet, which may then be committed or rolled back as an atomic
operation. Each DBSession will
have at most one DBEditSet transaction object active at any time.
A DBEditSet tracks several things for the server, including instances of
DBEditObject's that were created
or checked-out from the DBStore,
DBNameSpace values that were reserved
during the course of the transaction, and DBLogEvent
objects to be recorded in the DBLog and/or
mailed out to various interested parties when the transaction is committed.
DBEditSet's transaction logic is based on a two-phase commit
protocol, where all DBEditObject's involved in the transaction are
given an initial opportunity to approve or reject the transaction's
commit before the DBEditSet commit method goes back and 'locks-in'
the changes. DBEditObjects are able to initiate changes external
to the Ganymede database in their
commitPhase2()
methods, if needed.
When a DBEditSet is committed, a DBWriteLock
is established on all DBObjectBase's
involved in the transaction. All objects checked out by that transaction
are then updated in the DBStore, and a summary of changes is recorded to the
DBStore DBJournal. The database as
a whole will not be dumped to disk unless and until the
dumpTask is run, or until the server
undergoes a formal shutdown.
Typically, the commit()
method is called by the
GanymedeSession.commitTransaction()
method, which will induce the server to schedule any commit-time build
tasks registered with the GanymedeScheduler.
If a DBEditSet commit() operation fails catastrophically, or if
abort() is called,
all DBEditObjects created or checked out during the course of the
transaction will be discarded, all DBNameSpace values allocated will
be relinquished, and any logging information for the abandoned transaction
will be forgotten.
As if all that wasn't enough, the DBEditSet class also maintains a stack
of DBCheckPoint objects to enable
users to set checkpoints during the course of a transaction. These objects
are basically a snapshot of the transaction's state at the moment of the
checkpoint, and are used to rollback the transaction to a known state if
a series of linked operations within a transaction cannot all be completed.
Finally, note that the DBEditSet class does not actually track namespace value allocations.. instead, the DBNameSpace class is responsible for recording a list of values allocated by each active DBEditSet. When a DBEditSet commits or releases, all DBNameSpace objects in the server are informed of this, whereupon they do their own cleanup.
| Field Summary | |
private java.util.Hashtable |
basesModified
A record of the DBObjectBase's
touched by this transaction. |
private arlut.csd.Util.NamedStack |
checkpoints
A stack of DBCheckPoint objects
to keep track of check points performed during the course of this transaction. |
private java.lang.Thread |
currentCheckpointThread
We keep track of the thread that is doing checkpointing.. |
(package private) arlut.csd.ganymede.DBStore |
dbStore
Who's our daddy? |
(package private) static boolean |
debug
|
(package private) java.lang.String |
description
A brief description of the client associated with this transaction, used in logging to identify what was done by the main client, what by a password-changing utility, etc. |
private boolean |
interactive
True if this DBEditSet is operating in interactive mode. |
private java.util.Vector |
logEvents
A list of DBLogEvent's
to be written to the Ganymede logfile and/or mailed out when
this transaction commits. |
private boolean |
mustAbort
True if this DBEditSet is operating in non-interactive mode and a rollback was ordered. |
private java.util.Hashtable |
objects
A hashtable mapping Invids to DBEditObjects checked out in
care of this transaction. |
(package private) arlut.csd.ganymede.DBSession |
session
A reference to the DBSession that this transaction is attached to. |
private arlut.csd.ganymede.DBWriteLock |
wLock
The writelock acquired during the course of a commit attempt. |
| Constructor Summary | |
DBEditSet(arlut.csd.ganymede.DBStore dbStore,
arlut.csd.ganymede.DBSession session,
java.lang.String description,
boolean interactive)
Constructor for DBEditSet |
|
| Method Summary | |
boolean |
abort()
This method is intended for use by DBSession's abortTransaction() method, and returns true if the transaction could be aborted, false otherwise. |
boolean |
addObject(arlut.csd.ganymede.DBEditObject object)
Method to associate a DBEditObject with this transaction. |
void |
checkpoint(java.lang.String name)
This method checkpoints the current transaction at its current state. |
private void |
commit_checkObjectMissingFields(arlut.csd.ganymede.DBEditObject eObj)
This private helper method for the commit() method runs a check looking for missing mandatory fields on an object involved with this transaction. |
private void |
commit_createLogEvent(arlut.csd.ganymede.DBEditObject eObj)
This private helper method is executed in the middle of the commit() method, and handles logging for any changes made to a DBEditObject during the committed transaction. |
private void |
commit_createLogEvents()
This private helper method is executed in the middle of the commit() method, and handles logging for any changes made to objects during the committed transaction. |
private void |
commit_handlePhase1()
This private helper method for the commit() method handles phase 1 of transaction commit. |
private void |
commit_handlePhase2()
This private helper method for the commit() method records the creation/modification timestamp for the vector of committed objects, then calls commitPhase2() on them. |
private void |
commit_integrateChanges()
This private helper method for commit() integrates all committed objects back into the DBStore, handling on-disk change journaling, transaction logging, namespaces, and more. |
private java.util.Vector |
commit_lockBases()
Obtain a write lock on all bases modified by this transaction. |
private void |
commit_logTransaction()
This method handles the on-disk and email logging for events that have built up over the course of this transaction. |
private void |
commit_persistTransaction()
This private helper method for commit() writes the transaction to the on-disk transactions journal, which will persist our transaction's changes. |
private void |
commit_replaceObjects()
Private helper method for commit() that integrates committed objects back into the DBStore hashes. |
private void |
commit_updateBases()
Private helper method for commit() which causes all bases that were touched by this transaction to be updated. |
private void |
commit_updateNamespaces()
Private helper method for commit() which causes all namespaces to update themselves in conjunction with a commit. |
arlut.csd.ganymede.ReturnVal |
commit()
commit is used to cause all changes in association with this DBEditSet to be performed. |
private void |
deconstruct()
Private helper method for commit() and release(), which breaks apart and nulls references to data structures maintained for this transaction to aid GC. |
arlut.csd.ganymede.DBEditObject |
findObject(arlut.csd.ganymede.DBObject object)
Method to find a DBObject / DBEditObject if it has previously been checked out to this EditSet in some fashion. |
arlut.csd.ganymede.DBEditObject |
findObject(arlut.csd.ganymede.Invid invid)
Method to find a DBObject / DBEditObject if it has previously been checked out to this EditSet in some fashion. |
arlut.csd.ganymede.GanymedeSession |
getGSession()
Returns the user-level GanymedeSession object associated with this transaction, or null if there is no GanymedeSession associated. |
java.util.Hashtable |
getObjectHashClone()
To allow the GanymedeSession to get a copy of our object hash. |
arlut.csd.ganymede.DBEditObject[] |
getObjectList()
Return a list of objects that we are currently working on. |
arlut.csd.ganymede.DBSession |
getSession()
Method to return the DBSession handle owning this transaction. |
boolean |
isInteractive()
This method returns true if this transaction is being carried out by an interactive client. |
boolean |
isOversightOn()
Returns true if the GanymedeSession associated with this transaction has oversight turned on. |
void |
logEvent(arlut.csd.ganymede.DBLogEvent event)
This method is used to register a log event with this transaction. |
void |
logEvent(java.lang.String eventClassToken,
java.lang.String description,
arlut.csd.ganymede.Invid admin,
java.lang.String adminName,
java.util.Vector objects,
java.util.Vector notifyList)
This method is used to register a log event with this transaction. |
void |
logMail(java.util.Vector addresses,
java.lang.String subject,
java.lang.String message)
This method is used to record a message to be sent out when the transaction is committed. |
void |
logMail(java.util.Vector addresses,
java.lang.String subject,
java.lang.String message,
arlut.csd.ganymede.Invid admin,
java.lang.String adminName,
java.util.Vector objects)
This method is used to record a message to be sent out when the transaction is committed. |
arlut.csd.ganymede.DBCheckPoint |
popCheckpoint(java.lang.String name)
This method is used to pop a checkpoint off the checkpoint stack. |
arlut.csd.ganymede.DBCheckPoint |
popCheckpoint(java.lang.String name,
boolean inRollback)
This method is used to pop a checkpoint off the checkpoint stack. |
private void |
release()
release is used to abandon all changes made in association with this DBEditSet. |
private void |
releaseWriteLock()
This is a dinky little private helper method to keep things clean. |
boolean |
rollback(java.lang.String name)
This brings this transaction back to the state it was at at the time of the matching checkPoint() call. |
private void |
syncObjBackPointers(arlut.csd.ganymede.DBEditObject obj)
This method is executed towards the end of a transaction commit, and compares the current state of this object with its original state, and makes the appropriate changes to the backPointers hash in
the server's DBStore object. |
| Methods inherited from class java.lang.Object |
clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait |
| Field Detail |
static final boolean debug
private java.util.Hashtable objects
A hashtable mapping Invids to DBEditObjects checked out in
care of this transaction.
private java.util.Vector logEvents
A list of DBLogEvent's
to be written to the Ganymede logfile and/or mailed out when
this transaction commits.
private java.util.Hashtable basesModified
A record of the DBObjectBase's
touched by this transaction. These DBObjectBase's will be locked
when this transaction is committed.
This Hashtable maps DBObjectBase's to this, serving as a pre-Java 2 HashSet.
arlut.csd.ganymede.DBStore dbStore
arlut.csd.ganymede.DBSession session
java.lang.String description
private arlut.csd.Util.NamedStack checkpoints
DBCheckPoint objects
to keep track of check points performed during the course of this transaction.
private java.lang.Thread currentCheckpointThread
We keep track of the thread that is doing checkpointing.. once a thread starts a checkpoint on this transaction, we don't allow any other threads to checkpoint until the first thread releases its checkpoint. This is to prevent problems resulting from interleaved checkpoint/popCheckpoint/rollback activities across multiple threads.
private arlut.csd.ganymede.DBWriteLock wLock
releaseWriteLock()
method, but wLock should really never be non-null outside of the
context of the commit() call.
private boolean interactive
True if this DBEditSet is operating in interactive mode.
private boolean mustAbort
True if this DBEditSet is operating in non-interactive mode and a rollback was ordered. In such cases, the server skipped doing the checkpoint and so has no choice but to condemn the whole transaction.
| Constructor Detail |
public DBEditSet(arlut.csd.ganymede.DBStore dbStore,
arlut.csd.ganymede.DBSession session,
java.lang.String description,
boolean interactive)
dbStore - The owning DBStore object.session - The DBStore session owning this transaction.description - An optional string to identify this transactioninteractive - If false, this transaction will operate in
non-interactive mode. Certain Invid operations will be optimized
to avoid doing choice list queries and bind checkpoint
operations. When a transaction is operating in non-interactive mode,
any failure that cannot be handled cleanly due to the optimizations will
result in the transaction refusing to commit when commitTransaction()
is attempted. This mode is intended for batch operations.| Method Detail |
public arlut.csd.ganymede.DBSession getSession()
Method to return the DBSession handle owning this transaction.
public final arlut.csd.ganymede.GanymedeSession getGSession()
Returns the user-level GanymedeSession object associated with this transaction, or null if there is no GanymedeSession associated.
public final boolean isOversightOn()
Returns true if the GanymedeSession associated with this transaction has oversight turned on.
public boolean isInteractive()
This method returns true if this transaction is being carried out by an interactive client.
public java.util.Hashtable getObjectHashClone()
To allow the GanymedeSession to get a copy of our object hash.
public arlut.csd.ganymede.DBEditObject[] getObjectList()
Return a list of objects that we are currently working on.
public arlut.csd.ganymede.DBEditObject findObject(arlut.csd.ganymede.DBObject object)
Method to find a DBObject / DBEditObject if it has previously been checked out to this EditSet in some fashion.
public arlut.csd.ganymede.DBEditObject findObject(arlut.csd.ganymede.Invid invid)
Method to find a DBObject / DBEditObject if it has previously been checked out to this EditSet in some fashion. This method is used to allow consistency check code in the DBEditObjects to get a transaction consistent view of the system as it stands with the transaction's changes made.
public boolean addObject(arlut.csd.ganymede.DBEditObject object)
Method to associate a DBEditObject with this transaction.
This method is called by the createDBObject and editDBObject
methods in DBSession.
object - The newly created DBEditObject.
public void logEvent(java.lang.String eventClassToken,
java.lang.String description,
arlut.csd.ganymede.Invid admin,
java.lang.String adminName,
java.util.Vector objects,
java.util.Vector notifyList)
This method is used to register a log event with this transaction. If the transaction successfully commits, the provided log event will be recorded in the Ganymede log file and mail notification will be sent out if appropriate.
eventClassToken - a short string specifying a DBObject record describing
the general category for the eventdescription - Descriptive text to be entered in the record of the eventadmin - Invid pointing to the adminPersona that fired the event, if anyadminName - String containing the name of the adminPersona that fired the event, if anyobjects - A vector of invids of objects involved in this event.notifyList - A vector of Strings listing email addresses to send notification
of this event to.public void logEvent(arlut.csd.ganymede.DBLogEvent event)
This method is used to register a log event with this transaction. If the transaction successfully commits, the provided log event will be recorded in the Ganymede log file and mail notification will be sent out if appropriate.
event - A pre-formed log event to register with this transaction.
public void logMail(java.util.Vector addresses,
java.lang.String subject,
java.lang.String message,
arlut.csd.ganymede.Invid admin,
java.lang.String adminName,
java.util.Vector objects)
This method is used to record a message to be sent out when the transaction is committed.
subject - The subject line of the messagemessage - The body of the messageadmin - The invid of the admin whose action resulted in the mailadminName - The name of the admin whose actin resulted in the mailobjects - A vector of invids of objects involved in the mail
public void logMail(java.util.Vector addresses,
java.lang.String subject,
java.lang.String message)
This method is used to record a message to be sent out when the transaction is committed.
subject - The subject line of the messagemessage - The body of the messagepublic void checkpoint(java.lang.String name)
This method checkpoints the current transaction at its current state. If need be, this transaction can later be rolled back to this point by calling the rollback() method.
Once a thread checkpoints a transaction, no other thread can checkpoint a transaction until some thread clears the checkpoint, either by doing a rollback() or a popCheckpoint(). checkpoint() will block any threads that try to establish a checkpoint() until the prior thread's checkpoint is resolved.
See DBSession.deleteDBObject() and DBSesssion.createDBObject() for instances of this.
name - An identifier for this checkpointpublic arlut.csd.ganymede.DBCheckPoint popCheckpoint(java.lang.String name)
This method is used to pop a checkpoint off the checkpoint stack. This method is equivalent to a rollback where the checkpoint information is taken off the stack, but this DBEditSet's state is not reverted.
Any checkpoints that were placed on the stack after the checkpoint matching <name> will also be removed from the checkpoint stack.
name - An identifier for the checkpoint to take off
the checkpoint stack.
public arlut.csd.ganymede.DBCheckPoint popCheckpoint(java.lang.String name,
boolean inRollback)
This method is used to pop a checkpoint off the checkpoint stack. This method is equivalent to a rollback where the checkpoint information is taken off the stack, but this DBEditSet's state is not reverted.
Any checkpoints that were placed on the stack after the checkpoint matching <name> will also be removed from the checkpoint stack.
name - An identifier for the checkpoint to take off
the checkpoint stack.inRollback - If true, popCheckpoint will not actually
pop the checkpoint states out of the DBStore namespaces,
leaving that for rollback() to finish up.
public boolean rollback(java.lang.String name)
This brings this transaction back to the state it was at at the time of the matching checkPoint() call. Any objects that were checked out in care of this transaction since the checkPoint() will be checked back into the database and made available for other transactions to access. All namespace changes made by this transaction will likewise be rolled back to their state at the checkpoint.
name - An identifier for the checkpoint to be rolled back to.public arlut.csd.ganymede.ReturnVal commit()
commit is used to cause all changes in association with this DBEditSet to be performed. If commit() cannot make the changes for any reason, commit() will return a ReturnVal indicating failure and the cause of the commit failure. Depending on the source of the failure, the transaction may be left open for a subsequent transaction commit or release.
The returned ReturnVal
will have doNormalProcessing set to false if the transaction was
completely aborted. Both DBSession and the client should take a false doNormalProcessing
boolean as an indicator that the transaction was simply wiped out
and a new transaction should be opened for subsequent activity.
A true doNormalProcessing value indicates that the client can try
the commit again at a later time, perhaps after making changes to
fix the commit problem.
This method is synchronized and calls a synchronized method on the DBSession which contains this DBEditSet. Because of this, this method should really only be called by way of the DBSession.commitTransaction() method, to avoid the possibility of nested monitor deadlock.
private final java.util.Vector commit_lockBases()
throws CommitNonFatalException
Obtain a write lock on all bases modified by this transaction. This method may block indefinitely, waiting on other transactions which are in the process of modifying the DBStore hashes.
Returns a Vector of DBObjectBases that we have locked if we succeed.
Throws a CommitNonFatalException if we can't get the lock.
CommitNonFatalException
private final void commit_handlePhase1()
throws CommitNonFatalException
This private helper method for the commit() method handles phase 1 of transaction commit.
If an object refuses transaction commit, we'll throw a CommitNonFatalException with ReturnVal information encoded.
CommitNonFatalException
private final void commit_checkObjectMissingFields(arlut.csd.ganymede.DBEditObject eObj)
throws CommitNonFatalException
This private helper method for the commit() method runs a check looking for missing mandatory fields on an object involved with this transaction.
If the object is missing fields, a CommitNonFatalException will be thrown.
CommitNonFatalExceptionprivate final void commit_handlePhase2()
This private helper method for the commit() method records the creation/modification timestamp for the vector of committed objects, then calls commitPhase2() on them.
private final void commit_integrateChanges()
throws CommitFatalException
This private helper method for commit() integrates all committed objects back into the DBStore, handling on-disk change journaling, transaction logging, namespaces, and more.
CommitFatalExceptionprivate final void commit_createLogEvents()
This private helper method is executed in the middle of the commit() method, and handles logging for any changes made to objects during the committed transaction.
private final void commit_createLogEvent(arlut.csd.ganymede.DBEditObject eObj)
This private helper method is executed in the middle of the commit() method, and handles logging for any changes made to a DBEditObject during the committed transaction.
private final void commit_persistTransaction()
throws CommitFatalException
This private helper method for commit() writes the transaction to the on-disk transactions journal, which will persist our transaction's changes.
Will throw a CommitException if a failure was detected.
CommitFatalExceptionprivate final void commit_logTransaction()
This method handles the on-disk and email logging for events that have built up over the course of this transaction.
private final void commit_replaceObjects()
Private helper method for commit() that integrates committed objects back into the DBStore hashes.
private final void commit_updateNamespaces()
Private helper method for commit() which causes all namespaces to update themselves in conjunction with a commit.
private final void commit_updateBases()
Private helper method for commit() which causes all bases that were touched by this transaction to be updated.
This should be run as late as possible in the commit() sequence to minimize the chance that a previously scheduled builder task completes and updates its lastRunTime field after we have touched the timestamps on the changed bases.
private void syncObjBackPointers(arlut.csd.ganymede.DBEditObject obj)
This method is executed towards the end of a transaction commit,
and compares the current state of this object with its original state,
and makes the appropriate changes to the
backPointers hash in
the server's DBStore object.
The purpose of this is to support the decoupling of an object from its backlinks, so that objects can be asymmetrically linked to an object without having to check that object out for editing.
public boolean abort()
This method is intended for use by DBSession's abortTransaction() method, and returns true if the transaction could be aborted, false otherwise.
private final void release()
release is used to abandon all changes made in association with this DBEditSet. All DBObjects created, deleted, or modified, and all unique values allocated and freed during the course of actions on this transaction will be reverted to their state when this transaction was created.
Note that this does not mean that the entire DBStore will revert to its state at the beginning of this transaction; any changes not relating to objects and namespace values connected to this transaction will not be affected by this transaction's release.
private void deconstruct()
Private helper method for commit() and release(), which breaks apart and nulls references to data structures maintained for this transaction to aid GC.
This method also does a notifyAll() to wake up any checkpoint threads that are blocking waiting for the ability to checkpoint.
private void releaseWriteLock()
This is a dinky little private helper method to keep things clean. It's essential that wLock be released if things go wrong, else next time this session tries to commit a transaction, it'll wind up waiting forever for the old lock to be released.
|
||||||||||
| PREV CLASS NEXT CLASS | FRAMES NO FRAMES | |||||||||
| SUMMARY: NESTED | FIELD | CONSTR | METHOD | DETAIL: FIELD | CONSTR | METHOD | |||||||||