arlut.csd.ganymede
Class DBEditSet

java.lang.Object
  |
  +--arlut.csd.ganymede.DBEditSet

public class DBEditSet
extends java.lang.Object

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 release() 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.
(package private)  NamedStack checkpoints
          A stack of DBCheckPoint objects to keep track of check points performed during the course of this transaction.
(package private)  java.lang.Thread currentCheckpointThread
          We keep track of the thread that is doing checkpointing..
(package private)  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.
(package 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.
(package private)  java.util.Hashtable objects
          A hashtable mapping Invids to DBEditObjects checked out in care of this transaction.
(package private)  DBSession session
          A reference to the DBSession that this transaction is attached to.
(package private)  DBWriteLock wLock
          The writelock acquired during the course of a commit attempt.
 
Constructor Summary
DBEditSet(DBStore dbStore, DBSession session, java.lang.String description, boolean interactive)
          Constructor for DBEditSet
 
Method Summary
 boolean addObject(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.
 ReturnVal commit()
          commit is used to cause all changes in association with this DBEditSet to be performed.
 DBEditObject findObject(DBObject object)
          Method to find a DBObject / DBEditObject if it has previously been checked out to this EditSet in some fashion.
 DBEditObject findObject(Invid invid)
          Method to find a DBObject / DBEditObject if it has previously been checked out to this EditSet in some fashion.
 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.
 void logEvent(DBLogEvent event)
          This method is used to register a log event with this transaction.
 void logEvent(java.lang.String eventClassToken, java.lang.String description, 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, 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.
 DBCheckPoint popCheckpoint(java.lang.String name)
          This method is used to pop a checkpoint off the checkpoint stack.
 DBCheckPoint popCheckpoint(java.lang.String name, boolean inRollback)
          This method is used to pop a checkpoint off the checkpoint stack.
 void release()
          release is used to abandon all changes made in association with this DBEditSet.
private  void releaseWriteLock(java.lang.String reason)
          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(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, registerNatives, toString, wait, wait, wait
 

Field Detail

debug

static final boolean debug

objects

java.util.Hashtable objects
A hashtable mapping Invids to DBEditObjects checked out in care of this transaction.

logEvents

java.util.Vector logEvents
A list of DBLogEvent's to be written to the Ganymede logfile and/or mailed out when this transaction commits.

basesModified

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.


dbStore

DBStore dbStore
Who's our daddy?

session

DBSession session
A reference to the DBSession that this transaction is attached to.

description

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.

checkpoints

NamedStack checkpoints
A stack of DBCheckPoint objects to keep track of check points performed during the course of this transaction.

currentCheckpointThread

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.


wLock

DBWriteLock wLock
The writelock acquired during the course of a commit attempt. We keep this around as a DBEditSet field so that we can use the handy releaseWriteLock() method, but wLock should really never be non-null outside of the context of the commit() call.

interactive

private boolean interactive

True if this DBEditSet is operating in interactive mode.


mustAbort

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

DBEditSet

public DBEditSet(DBStore dbStore,
                 DBSession session,
                 java.lang.String description,
                 boolean interactive)
Constructor for DBEditSet
Parameters:
dbStore - The owning DBStore object.
session - The DBStore session owning this transaction.
description - An optional string to identify this transaction
interactive - 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

getSession

public DBSession getSession()

Method to return the DBSession handle owning this transaction.


isInteractive

public boolean isInteractive()

This method returns true if this transaction is being carried out by an interactive client.


findObject

public DBEditObject findObject(DBObject object)

Method to find a DBObject / DBEditObject if it has previously been checked out to this EditSet in some fashion.


findObject

public DBEditObject findObject(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.


addObject

public boolean addObject(DBEditObject object)

Method to associate a DBEditObject with this transaction.

This method is called by the createDBObject and editDBObject methods in DBSession.

Parameters:
object - The newly created DBEditObject.

logEvent

public void logEvent(java.lang.String eventClassToken,
                     java.lang.String description,
                     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.

Parameters:
eventClassToken - a short string specifying a DBObject record describing the general category for the event
description - Descriptive text to be entered in the record of the event
admin - Invid pointing to the adminPersona that fired the event, if any
adminName - String containing the name of the adminPersona that fired the event, if any
objects - 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.

logEvent

public void logEvent(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.

Parameters:
event - A pre-formed log event to register with this transaction.

logMail

public void logMail(java.util.Vector addresses,
                    java.lang.String subject,
                    java.lang.String message,
                    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.

Parameters:
addressList - Vector of Strings, the address list
subject - The subject line of the message
message - The body of the message
admin - The invid of the admin whose action resulted in the mail
adminName - The name of the admin whose actin resulted in the mail
objects - A vector of invids of objects involved in the mail

logMail

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.

Parameters:
addressList - Vector of Strings, the address list
subject - The subject line of the message
message - The body of the message

checkpoint

public 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.

Parameters:
name - An identifier for this checkpoint

popCheckpoint

public 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.

Parameters:
name - An identifier for the checkpoint to take off the checkpoint stack.
Returns:
null if the checkpoint could not be found on the stack, or the DBCheckPoint object representing the state of the transaction at the checkpoint time if the checkpoint could be found.

popCheckpoint

public 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.

Parameters:
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.
Returns:
null if the checkpoint could not be found on the stack, or the DBCheckPoint object representing the state of the transaction at the checkpoint time if the checkpoint could be found.

rollback

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.

Parameters:
name - An identifier for the checkpoint to be rolled back to.

commit

public 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, and will leave the transaction open for a subsequent commit() attempt, or an abort().

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, or manually cancel.

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.

Returns:
a ReturnVal indicating success or failure, or null on success without comment.

syncObjBackPointers

private void syncObjBackPointers(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.


release

public 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.


releaseWriteLock

private void releaseWriteLock(java.lang.String reason)

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.