public final class DBNameSpace extends java.lang.Object implements NameSpace
DBNameSpaces are the objects used to manage unique value
tracking in DBFields that are
unique value constrained. DBNameSpace is smart enough to
coordinate unique value allocation and management during object
editing across concurrent transactions.
In general, transactions in Ganymede are not able to affect each
other at all, save through the acquisition of exclusive editing
locks on invidivual objects, and through the atomic acquisition of
values for unique value constrained DBFields. Once a transaction
allocates a unique value using either the mark(), unmark(), or reserve() methods, no other transaction can
allocate that value, until the first transaction calls the commit(), abort(), or rollback() methods.
In order to perform this unique value management, DBNameSpace
maintains a private Hashtable, uniqueHash, that
associates the allocated vales in the namespace with DBNameSpaceHandle
objects which track the transaction that is manipulating the value,
if any, as well as the DBField object in the database that is
checked in with that value. The GanymedeSession query
logic takes advantage of this to do optimized, hashed look-ups of
values for unique value constrained fields to locate objects in the
database rather than having to iterate over all objects of a given
type to find a particular match.
DBNameSpaces may be defined in the server's schema editor to be
either case sensitive or case insensitive. The DBNameSpace class
uses the GHashtable
class to handle the representational issues in the unique value
hash for this, as well as for things like IP address
representation.
| Modifier and Type | Class and Description |
|---|---|
(package private) static class |
DBNameSpace.DBNameSpaceCkPoint
This nested class holds checkpoint information associated with
an active transaction (a
DBEditSet) in care of a
DBNameSpace. |
(package private) static class |
DBNameSpace.DBNameSpaceTransaction
This nested class holds information associated with an active
transaction (a
DBEditSet) in care of a DBNameSpace. |
| Modifier and Type | Field and Description |
|---|---|
private boolean |
caseInsensitive
treat differently-cased Strings as the same for key?
|
(package private) static boolean |
debug |
(package private) static int |
DEFAULTSIZE
The initial number of slots that we will reserve in our
uniqueHash hashtable, if we are starting from scratch with a new
namespace.
|
(package private) static int |
GROWTHSPACE
The number of spaces we save in our hashtable before it will need
to grow again.
|
private int |
hashSize
At startup, if we are reading from a Ganymede db file of version
2.14 or later, we will read the size of the hash to allocate at
database loading time so we don't have to do a lot of hash
expansion.
|
private java.lang.String |
name
the name of this namespace
|
private GHashtable |
saveHash
During schema editing, we keep a copy of the uniqueHash that we had
when schema edited started.
|
private java.util.Hashtable<DBEditSet,DBNameSpace.DBNameSpaceTransaction> |
transactions
Hashtable mapping
DBEditSet's currently active modifying values in this namespace
to DBNameSpaceTransaction objects. |
(package private) static int |
TRANSCOUNT
The number of simultaneous transactions in progress
that we will size the transactions hash for initially.
|
(package private) static TranslationService |
ts
TranslationService object for handling string localization in
the Ganymede server.
|
private GHashtable |
uniqueHash
Hashtable mapping values allocated (permanently, for objects
checked in to the database, or temporarily, for objects being
manipulated by active transactions) in this namespace to
DBNameSpaceHandle
objects that track the current status of the values. |
| Constructor and Description |
|---|
DBNameSpace(java.io.DataInput in)
Create a new DBNameSpace object from a stream definition.
|
DBNameSpace(java.lang.String name,
boolean caseInsensitive)
Constructor for new DBNameSpace for DBStore initialization.
|
| Modifier and Type | Method and Description |
|---|---|
void |
abort(DBEditSet editSet)
Method to revert an editSet's namespace modifications to its
original state.
|
void |
checkpoint(DBEditSet editSet,
java.lang.String name)
Method to checkpoint namespace changes made by a specific transaction
so that state can be rolled back if necessary at a later time.
|
void |
checkSchemaEditInProgress(boolean expecting) |
void |
commit(DBEditSet editSet)
Method to put the editSet's current namespace modifications
into final effect and to make any abandoned values available for
other namespaces.
|
boolean |
containsKey(java.lang.Object value)
Returns true if this namespace has value allocated.
|
void |
emit(java.io.DataOutput out)
Write out a namespace definition to a DataOutput stream.
|
void |
emitXML(XMLDumpContext xDump)
Write out an XML entity for this namespace.
|
boolean |
findConflicts(DBNameSpace otherSpace)
This method is designed for doing conflict detection between
this DBNameSpace and another DBNameSpace that we might be looking
at merging into this namespace.
|
private DBNameSpaceHandle |
getHandle(java.lang.Object value)
Returns the DBNameSpaceHandle associated with the value
in this namespace, or null if the value is not allocated in
this namespace.
|
java.lang.String |
getName()
Returns the name of this namespace.
|
private DBNameSpace.DBNameSpaceTransaction |
getTransactionRecord(DBEditSet transaction)
This method returns the
DBNameSpaceTransaction associated with the given transaction,
creating one if one was not previously so associated. |
boolean |
isCaseInsensitive()
Returns true if case is to be disregarded in comparing
entries in namespace managed fields.
|
boolean |
isSchemaEditInProgress()
Returns true if this namespace has already been checked out for schema editing.
|
DBField |
lookupMyValue(GanymedeSession session,
java.lang.Object value)
This method looks to find where the given value is bound in
the namespace, taking into account the transactional view the
calling session has.
|
DBField |
lookupPersistent(java.lang.Object value)
This method allows the namespace to be used as a unique valued
search index.
|
DBField |
lookupShadow(java.lang.Object value)
If the value is attached to an object that is being created or
edited in a transaction, this method will return the editable
DBField that contains the constrained value during editing.
|
boolean |
mark(DBEditSet editSet,
java.lang.Object value,
DBField field)
This method marks a value as being used in this namespace.
|
void |
popCheckpoint(DBEditSet editSet,
java.lang.String name)
Method to remove a checkpoint from this namespace's
DBNameSpaceCkPoint hash.
|
private void |
putHandle(java.lang.Object value,
DBNameSpaceHandle handle)
Performs some assertinon checking, then places the given
DBNameSpaceHandle in the uniqueHash using value as they key.
|
private void |
receive(java.io.DataInput in)
Read in a namespace definition from a DataInput stream.
|
void |
receiveValue(java.lang.Object value,
DBField field)
Publicly accessible function used to record the presence of a
namespace value in this namespace during Ganymede database
loading.
|
private void |
remember(DBEditSet editSet,
java.lang.Object value)
Remember that this editSet has changed the location/status of
this value.
|
void |
removeHandle(java.lang.Object value)
Publicly accessible function used to clear the given
value from this namespace in a non-transactional fashion.
|
boolean |
reserve(DBEditSet editSet,
java.lang.Object value)
This method reserves a value so that the given editSet is
assured of being able to use this value at some point before the
transaction is commited or canceled.
|
boolean |
reserve(DBEditSet editSet,
java.lang.Object value,
boolean onlyUnused)
Deprecated.
We are no longer supporting false values of the
onlyUnused paramater. We never did so properly before, anyway.
|
boolean |
rollback(DBEditSet editSet,
java.lang.String name)
Method to rollback namespace changes made by a specific
transaction to a checkpoint.
|
void |
schemaEditAbort()
This method aborts any changes made during schema editing.
|
void |
schemaEditCheckout()
This method prepares this DBNameSpace for changes to be made
during schema editing.
|
void |
schemaEditCommit()
This method locks in any changes made after schema editing is complete.
|
boolean |
schemaEditRegister(java.lang.Object value,
DBField field)
This method links the given value to the specified field.
|
boolean |
schemaEditUnregister(java.lang.Object value,
Invid objid,
short field)
This method unlinks a single item from this namespace index, if and only
if the value is associated with the object and field id specified.
|
void |
schemaEditUnregister(short objectType,
short fieldId)
This method unlinks all values that are associated with the specified
object type and field id from this namespace.
|
void |
setInsensitive(boolean b)
Turns case sensitivity on/off.
|
boolean |
setName(java.lang.String newName)
Sets the name of this namespace.
|
boolean |
testmark(DBEditSet editSet,
java.lang.Object value)
This method tests to see whether a value in the namespace can
be marked as in use.
|
boolean |
testunmark(DBEditSet editSet,
java.lang.Object value,
DBField oldField)
This method tests to see whether a value in the namespace can
be marked as not in use.
|
java.lang.String |
toString() |
boolean |
unmark(DBEditSet editSet,
java.lang.Object value,
DBField oldField)
Used to mark a value as not used in the namespace.
|
java.util.Vector<java.lang.String> |
verify_noninteractive(DBEditSet editSet)
This method returns null if the given transaction doesn't have
any shadowFieldB's outstanding.
|
static final boolean debug
static final TranslationService ts
static final int TRANSCOUNT
static final int DEFAULTSIZE
static final int GROWTHSPACE
private int hashSize
private boolean caseInsensitive
private java.lang.String name
private GHashtable uniqueHash
DBNameSpaceHandle
objects that track the current status of the values.private GHashtable saveHash
private java.util.Hashtable<DBEditSet,DBNameSpace.DBNameSpaceTransaction> transactions
DBEditSet's currently active modifying values in this namespace
to DBNameSpaceTransaction objects.public DBNameSpace(java.lang.String name,
boolean caseInsensitive)
name - Name for this name spacecaseInsensitive - If true, case is disregarded in this namespacepublic DBNameSpace(java.io.DataInput in)
throws java.io.IOException
java.io.IOExceptionprivate void receive(java.io.DataInput in)
throws java.io.IOException
java.io.IOExceptionpublic void emit(java.io.DataOutput out)
throws java.io.IOException
java.io.IOExceptionpublic void emitXML(XMLDumpContext xDump) throws java.io.IOException
java.io.IOExceptionpublic java.lang.String getName()
public boolean setName(java.lang.String newName)
public boolean isCaseInsensitive()
isCaseInsensitive in interface NameSpaceNameSpacepublic void setInsensitive(boolean b)
setInsensitive in interface NameSpaceNameSpacepublic boolean containsKey(java.lang.Object value)
public void receiveValue(java.lang.Object value,
DBField field)
Publicly accessible function used to record the presence of a namespace value in this namespace during Ganymede database loading.
Used by the DBObject receive() method and the DBJournal's JournalEntry class'
process() method to build up the namespace during server
start-up.
public void removeHandle(java.lang.Object value)
Publicly accessible function used to clear the given value from this namespace in a non-transactional fashion.
Used by DBJournal's JournalEntry class' process() method to rectify the namespace
during server start-up.
public DBField lookupPersistent(java.lang.Object value)
This method allows the namespace to be used as a unique valued search index.
Note that this lookup is case sensitive or not according to the case sensitivity of this DBNameSpace. If this DBNameSpace is case insensitive, the DBField returned may contain the value (if value is a String) with different capitalization.
As well, this method is really probably only useful in the context of a DBReadLock, but we're not doing anything to enforce this requirement at this point.
value - The value to search for in the namespace hash.public DBField lookupShadow(java.lang.Object value)
If the value is attached to an object that is being created or edited in a transaction, this method will return the editable DBField that contains the constrained value during editing.
Note that this lookup is case sensitive or not according to the case sensitivity of this DBNameSpace. If this DBNameSpace is case insensitive, the DBField returned may contain the value (if value is a String) with different capitalization.
As well, this method is really probably useful in the context of a DBReadLock, but we're not doing anything to enforce this requirement at this point.
value - The value to search for in the namespace hash.public DBField lookupMyValue(GanymedeSession session, java.lang.Object value)
This method looks to find where the given value is bound in the namespace, taking into account the transactional view the calling session has. If the value is attached to an object in the current transaction, this method will return a reference to the editable shadow DBField containing the value. If not, this method will either return the DBField containing the read-only persistent version from the DBStore, or null if the value sought has been cleared from use in the objects being edited by the transaction.
Note that this lookup is case sensitive or not according to the case sensitivity of this DBNameSpace. If this DBNameSpace is case insensitive, the DBField returned may contain the value (if value is a String) with different capitalization.
As well, this method is really probably useful in the context of a DBReadLock, but we're not doing anything to enforce this requirement at this point.
session - The GanymedeSession to use to lookup the containing object..
useful when a GanymedeSession is doing the looking up of valuevalue - The value to search for in the namespace hash.public boolean reserve(DBEditSet editSet, java.lang.Object value)
This method reserves a value so that the given editSet is assured of being able to use this value at some point before the transaction is commited or canceled. reserve() is different from mark() in that there is no field specified to be holding the value, and that when the transaction is committed or canceled, the value will be returned to the available list. During the transaction, the transaction code can mark the value at any time with assurance that they will be able to do so.
If a transaction attempts to reserve() a value that is already being held by an object in the transaction, reserve() will return false.
editSet - The transaction claiming the unique value value - The unique value that transaction editset is attempting to claim@Deprecated public boolean reserve(DBEditSet editSet, java.lang.Object value, boolean onlyUnused)
This method reserves a value so that the given editSet is assured of being able to use this value at some point before the transaction is commited or canceled. reserve() is different from mark() in that there is no field specified to be holding the value, and that when the transaction is committed or canceled, the value will be returned to the available list. During the transaction, the transaction code can mark the value at any time with assurance that they will be able to do so.
If onlyUsed is false and a transaction attempts to reserve() a value that is already being held by an object in the transaction, reserve() will return true, even though a subsequent mark() attempt would fail unless the value is first unmarked.
editSet - The transaction claiming the unique value value - The unique value that transaction editset is
attempting to claimonlyUnused - If true, reserve() will return false if the
value is already attached to a field connected to this namespace,
even if in an object attached to the editSet provided.public boolean testmark(DBEditSet editSet, java.lang.Object value)
This method tests to see whether a value in the namespace can be marked as in use. Such a marking is done to allow an editset to have the ability to juggle values in namespace associated fields without allowing another editset to acquire a value needed if the editset transaction is aborted.
For array db fields, all elements in the array should be testmark'ed in the context of a synchronized block on the namespace before going back and marking each value (while still in the synchronized block on the namespace).. this ensures that we won't mark several values in an array before discovering that one of the values in a DBArrayField is already taken.
The success of testmark() is no guarantee of a future successful mark() operation, of course, unless the testmark and mark operations are done within a synchronization block on the namespace.
editSet - The transaction testing permission to claim value.value - The unique value desired by editSet.public boolean mark(DBEditSet editSet, java.lang.Object value, DBField field)
editSet - The transaction claiming the unique value <value>value - The unique value that transaction editset is attempting to claimfield - The DBField which will take the unique value.public boolean testunmark(DBEditSet editSet, java.lang.Object value, DBField oldField)
This method tests to see whether a value in the namespace can be marked as not in use. Such a marking is done to allow an editset to have the ability to juggle values in namespace associated fields without allowing another editset to acquire a value needed if the editset transaction is aborted.
For array db fields, all elements in the array should be testunmark'ed in the context of a synchronized block on the namespace before actually unmarking all the values. See the comments in testmark() for the logic here. Note that testunmark() is less useful than testmark() because we really aren't expecting anything to prevent us from unmarking() something.
editSet - The transaction that is determining whether value can be freed.value - The unique value being tested.public boolean unmark(DBEditSet editSet, java.lang.Object value, DBField oldField)
editSet - The transaction that is freeing value.value - The unique value being tentatively marked as unused.oldField - The old DBField that the namespace value is being
unmarked forpublic void checkpoint(DBEditSet editSet, java.lang.String name)
editSet - The transaction that needs to be checkpointed.name - The name of the checkpoint to be marked.public void popCheckpoint(DBEditSet editSet, java.lang.String name)
Method to remove a checkpoint from this namespace's DBNameSpaceCkPoint hash. This is to be done when the calling code knows that it will no longer need to be able to rollback to the named checkpoint.
This method really isn't very important, because when the transaction is committed or aborted, the checkpoints hashtable will be cleared of editSet anyway.
editSet - The transaction that is requesting the checkpoint pop.name - The name of the checkpoint to be popped.public boolean rollback(DBEditSet editSet, java.lang.String name)
editSet - The transaction that needs to be checkpointed.name - The name of the checkpoint to be rolled back to.public java.util.Vector<java.lang.String> verify_noninteractive(DBEditSet editSet)
This method returns null if the given transaction doesn't have any shadowFieldB's outstanding. This is the desired case. If the given transaction has some values with shadowFieldB's set, that means that those unique values are left "bound" to more than one field, which is an error that non-interactive clients (the xmlclient) can run into.
If we have such conflicts, we return a vector of namespace values that are in conflict at transaction commit time, else we return null, which indicates that this namespace has been verified.
public void commit(DBEditSet editSet)
Method to put the editSet's current namespace modifications into final effect and to make any abandoned values available for other namespaces.
Note that a NameSpace should really never fail here. We assume that all NameSpace management code up to this point has functioned properly.. at this point, the EditSet has already committed changes to the DBStore and to any external processes, we're just doing paperwork at this point.
editSet - The transaction being committed.public void abort(DBEditSet editSet)
editSet - The transaction whose claimed values in this
namespace need to be freed.public java.lang.String toString()
toString in class java.lang.Objectpublic void schemaEditCheckout()
public boolean isSchemaEditInProgress()
public void checkSchemaEditInProgress(boolean expecting)
public void schemaEditCommit()
public void schemaEditAbort()
public boolean schemaEditRegister(java.lang.Object value,
DBField field)
public boolean schemaEditUnregister(java.lang.Object value,
Invid objid,
short field)
public void schemaEditUnregister(short objectType,
short fieldId)
public boolean findConflicts(DBNameSpace otherSpace)
This method is designed for doing conflict detection between this DBNameSpace and another DBNameSpace that we might be looking at merging into this namespace. This is usually necessary when a Ganymede adopter is collapsing two namespaces into one.
In addition to returning true if there are values in conflict between the two namespaces, or false if conflicts exist, a report of the conflicting values will be written to the Ganymede admin console and the Ganymede server's stdout.
private void putHandle(java.lang.Object value,
DBNameSpaceHandle handle)
private DBNameSpaceHandle getHandle(java.lang.Object value)
private DBNameSpace.DBNameSpaceTransaction getTransactionRecord(DBEditSet transaction)
This method returns the DBNameSpaceTransaction associated with the given transaction,
creating one if one was not previously so associated.
This method will always return a valid DBNameSpaceTransaction record.
private void remember(DBEditSet editSet, java.lang.Object value)
Remember that this editSet has changed the location/status of this value.
This is a private convenience method.
This method associates the value with the given editset in a stored transaction record, so that we can rollback the namespace to a fixed state later.