ccs.cdb
Class CDBeeTree

java.lang.Object
  extended by ccs.cdb.CDBeeTree

public class CDBeeTree
extends java.lang.Object

CDBeeTree provides a persistent object store (a "CDB") based on the encrypted, concurrent BLOB persistence provided by BeeTree. See the package description for an explanation of the "CDB" prefix.

CDBeeTree's type separation system is based on the notion of "sets". A set, as used here, is a collection of classes - here called sub-classes - which are all assignable from (ie. are, or are subclasses of) a single set class. The set class must be a subclass of CDBObject. All objects which are instances of classes in the same set - informally, we say below that the object is "a member of" the class, although strictly the member is the object's class, not the object itself - share the same key space, which is separate from the key space of any other set (in that CDB or another). In other words, two objects in different sets can have the same key without there being a clash.

To retrieve an object which belongs to a set which contains several sub-classes, use find / next / prev in the usual way. However, the parameter object you supply (which is to be populated with the state of the retrieved object) may be an instance of any sub-class in the set. If the supplied object is not of the same class as the object to be retrieved, a "clone" object is created and populated (unmarshalled) instead, and made available as the clone member of CDBObject.

CDBObjects all define their own marshal versions. When marshalling a CDBObject for storage, the latest version is always stored. When unmarshalling, the unmarshal method is given the marshal version which was used to marshal. In this way objects can transparently evolve over time: as each object is read out of the CDB and written back in, the object is automatically upgraded.

Most methods are marked as throwing IOException. In particular, you may expect:

See Also:
CDBObject, BeeTree

Constructor Summary
CDBeeTree(java.io.File f, byte[] password, boolean create)
          Create a new CDBeeTree indexing the supplied File.
 
Method Summary
<T extends CDBObject>
void
addAutoSet(java.lang.Class<T> setClass)
          Add a set, then add the set class as its own sub-class.
 void addSet(java.lang.Class setClass)
          Add a new set to the CDB.
<T extends CDBObject>
void
addSubClass(java.lang.Class<T> setClass, java.lang.Class<? extends T> subClass)
          Add a new sub-class to an existing set of the CDB.
<T extends CDBObject>
boolean
assertAutoSet(java.lang.Class<T> setClass)
          Add a set, then add the set class as its own sub-class, only as required.
<T extends CDBObject>
boolean
assertSet(java.lang.Class<T> setClass, java.lang.Class<? extends T> subClass)
          Add a set and one of its sub-classes, only as required.
 void changeKey(CDBObject cdbo, java.lang.String newkey)
          Changes the key of the supplied object.
 void delete(CDBObject cdbo)
          Deletes the supplied object from the CDB.
 void delSet(java.lang.Class setClass, BeeTreeObserver bto, int wipeMode)
          Delete a set, and all objects within the CDB which belong to that set.
 void delSubClass(java.lang.Class setClass, java.lang.Class subClass, BeeTreeObserver bto, int wipeMode)
          Delete a sub-class from a set, and all objects within the CDB which belong to that sub-class.
 void dumpSets(java.io.PrintStream out)
          Print the set structure out.
 void eviscerate(boolean isWipe, boolean isRemoveMeta)
          Removes all objects from the CDB, and optionally removes the set structure as well.
 boolean findExact(CDBObject cdbo)
          Finds an object from an exact key.
 boolean findExactKey(CDBObject cdbo)
          As findExact, except that the object is not unmarshalled.
 boolean findFirst(CDBObject cdbo)
          Finds an object from a partial key.
 boolean findFirstKey(CDBObject cdbo)
          As findFirst, except that the object is not unmarshalled.
 BeeTree getBeeTree()
          Returns the underlying BeeTree blob-persister object.
 Cipher getCipherInstance()
          Returns a new, uninitialised instance of the Cipher corresponding to the current Cipher version.
 java.io.File getContainingFile()
          Returns the File containing the CDB.
 Cipher getNullCipherInstance()
          Returns a new, uninitialised instance of the Cipher the tree uses when it's not actually encrypted.
 byte[] getPassword()
          returns a copy of the current password, if any.
 long getTotalFree()
          Returns the total amount of free space inside the CDB.
 int getTotalSpaces()
          Returns the number of free spaces inside the CDB.
 boolean hasSet(java.lang.Class setClass)
          Whether a set is already in the CDB.
 boolean hasSubClass(java.lang.Class setClass, java.lang.Class subClass)
          Whether the specified set exists, and has the specified class as a sub-class - see addSubClass and the opening essay.
 void insert(CDBObject cdbo)
          Inserts an object into the CDB.
 java.lang.Class[] listSetClasses()
          Retuns a list of the set classes present in this CDB.
 java.lang.Class[] listSubClasses(java.lang.Class setClass)
          Returns a list of the sub-classes of a given set of this CDB.
 boolean next(CDBObject cdbo)
          Find the next object.
 boolean nextKey(CDBObject cdbo)
          As next, except the CDBObject is not unmarshalled.
 boolean nextMatch(CDBObject cdbo)
          Find the next object which matches the partial key from the most recent findFirst.
 boolean nextMatchKey(CDBObject cdbo)
          As nextMatch, except that the object is not unmarshalled.
 boolean prev(CDBObject cdbo)
          Find the previous object, as next.
 boolean prevKey(CDBObject cdbo)
          Find the previous object but don't unmarshal, as nextKey.
 void reloadMetadata()
          Reload set-management information for this CDBeeTree.
 void setNodeCacheSize(int size)
          Changes the size of the node cache.
 void setThreshold(int threshold)
          Changes the swapping threshold for temporary space when marshalling.
 void threadLock()
          Lock the underlying beetree so that only this thread in this VM can use it; all other threads in all other VMs are locked out.
 void threadLockRO()
          As threadLock, but only acquires an RO lock.
 void threadUnlock()
          Release the beetree from your previously-applied thread lock.
 void threadUnlockRO()
          Release the CDBeeTree from your previously-applied RO thread lock.
 void update(CDBObject cdbo)
          Updates the object, which is already in the CDB.
 
Methods inherited from class java.lang.Object
clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
 

Constructor Detail

CDBeeTree

public CDBeeTree(java.io.File f,
                 byte[] password,
                 boolean create)
          throws java.io.IOException
Create a new CDBeeTree indexing the supplied File. The password (passphrase, cryptographic key - see opening essay for BeeTree) encrypts the CDB; if zero-length a null cipher is applied. Applying strong encryption is little slower than applying null encryption.

Parameters:
f - The disk file to contain the BeeTree.
password - The password for the BeeTree, supplied as a set of bytes. If your app is using a string, think about character encoding. Supply null to not use encryption.
create - If true, create a new CDB. Any existing file will be wiped. If you don't want to bother with wiping, delete it yourself. If false, read in details from an existing CDB.
Throws:
java.io.IOException - See opening discussion.
Method Detail

hasSet

public boolean hasSet(java.lang.Class setClass)
               throws DeadlockException
Whether a set is already in the CDB.

Throws:
DeadlockException

addSet

public void addSet(java.lang.Class setClass)
            throws java.io.IOException
Add a new set to the CDB. You must then add at least one "sub-class" - see opening essay - to the set in order to make it useable. This sub-class may be the set-class. Any other CDBeeTree objects looking at this CDB must have reloadMetadata invoked on them for the change to take effect. You may find assertSet more convenient.

Parameters:
setClass - The set class to add.
Throws:
java.io.IOException - See opening discussion.
See Also:
CDBObject

hasSubClass

public boolean hasSubClass(java.lang.Class setClass,
                           java.lang.Class subClass)
                    throws DeadlockException
Whether the specified set exists, and has the specified class as a sub-class - see addSubClass and the opening essay.

Throws:
DeadlockException

addSubClass

public <T extends CDBObject> void addSubClass(java.lang.Class<T> setClass,
                                              java.lang.Class<? extends T> subClass)
                 throws java.io.IOException
Add a new sub-class to an existing set of the CDB. This sub-class must be either the set class, or a class which extends (subclasses) the set class. Any other CDBeeTree objects looking at this set must have reloadMetadata invoked on them for the change to take effect.

Parameters:
setClass - The set class of the set to which the sub-class will be added.
subClass - the sub-class to add.
Throws:
java.io.IOException - See opening discussion.

addAutoSet

public <T extends CDBObject> void addAutoSet(java.lang.Class<T> setClass)
                throws java.io.IOException
Add a set, then add the set class as its own sub-class. Utility method - addSet then addSubClass is equivalent. Any other CDBeeTree objects looking at this CDB must have reloadMetadata invoked on them for the change to take effect.

Parameters:
setClass - The set class.
Throws:
java.io.IOException - See opening discussion.

assertAutoSet

public <T extends CDBObject> boolean assertAutoSet(java.lang.Class<T> setClass)
                      throws java.io.IOException
Add a set, then add the set class as its own sub-class, only as required. In other words, the set and sub-class will exist after the call, and it doesn't matter if they already existed beforehand. Utility method. If this causes a change (ie. the set wasn't there already) then any other CDBeeTree objects looking at this CDB must have reloadMetadata invoked on them for the change to take effect.

Parameters:
setClass - The set class of the set to create, if need be.
Returns:
Whether any change was required.
Throws:
java.io.IOException - See opening discussion.

assertSet

public <T extends CDBObject> boolean assertSet(java.lang.Class<T> setClass,
                                               java.lang.Class<? extends T> subClass)
                  throws java.io.IOException
Add a set and one of its sub-classes, only as required. In other words, the set and sub-class will exist after the call, and it doesn't matter if they already existed beforehand. (addSet / addSubClass throw if the elements pre-exist). Utility method. If this causes a change (ie. the set wasn't there already) then any other CDBeeTree objects looking at this CDB must have reloadMetadata invoked on them for the change to take effect.

Parameters:
setClass - The set class of the set to create, if need be.
subClass - the sub-class to add to the set, if need be.
Returns:
Whether any change was required.
Throws:
java.io.IOException - See opening discussion.

delSet

public void delSet(java.lang.Class setClass,
                   BeeTreeObserver bto,
                   int wipeMode)
            throws java.io.IOException
Delete a set, and all objects within the CDB which belong to that set. This will involve compacting the CDB - potentially a long job. You should ensure that there are no other CDBeeTree objects accessing the same CDB, or that they have reloadMetadata invoked on them immediately after - otherwise they might create objects of the deleted set, which would cause problems later.

Parameters:
setClass - the set class of the set to be deleted.
bto - An optional BeeTreeObserver which can monitor the compaction process.
wipeMode - A constant from ccs.utils.FileKiller, dictating how thoroughly the old database is to be wiped.
Throws:
java.io.IOException - See opening discussion.

delSubClass

public void delSubClass(java.lang.Class setClass,
                        java.lang.Class subClass,
                        BeeTreeObserver bto,
                        int wipeMode)
                 throws java.io.IOException
Delete a sub-class from a set, and all objects within the CDB which belong to that sub-class. This will involve compacting the CDB - potentially a long job. You should ensure that there are no other CDBeeTree objects accessing the same CDB, or that they have reloadMetadata invoked on them immediately after - otherwise they might create objects of the deleted sub-class, which would cause problems later.

Parameters:
setClass - the set class whose sub-class is to be deleted.
subClass - the sub-class which is to be deleted.
bto - An optional BeeTreeObserver which can monitor the compaction process.
wipeMode - A constant from ccs.utils.FileKiller, dictating how thoroughly the old database is to be wiped.
Throws:
java.io.IOException - See opening discussion.

listSetClasses

public java.lang.Class[] listSetClasses()
                                 throws DeadlockException
Retuns a list of the set classes present in this CDB.

Returns:
the setclasses.
Throws:
DeadlockException

listSubClasses

public java.lang.Class[] listSubClasses(java.lang.Class setClass)
                                 throws DeadlockException
Returns a list of the sub-classes of a given set of this CDB.

Parameters:
setClass - The setclass whose subclasses are to be listed.
Throws:
DeadlockException

eviscerate

public void eviscerate(boolean isWipe,
                       boolean isRemoveMeta)
                throws java.io.IOException
Removes all objects from the CDB, and optionally removes the set structure as well. Clearly this function should be used with great care, hence the rather sanguine name.

Parameters:
isWipe - Whether to attempt to wipe the underlying file. The wipe is a rather limited single-pass wipe; for greater security you should use BeeTreeCompactor with a multipass FileKiller mode, instead of this method.
isRemoveMeta - Whether to remove the metadata (set structure) as well as all objects.
Throws:
java.io.IOException

reloadMetadata

public void reloadMetadata()
                    throws java.io.IOException
Reload set-management information for this CDBeeTree. Use this when some other CDBeeTree accessing the same disk file has used addSet etc.

Throws:
java.io.IOException

getBeeTree

public BeeTree getBeeTree()
Returns the underlying BeeTree blob-persister object. This object is not set-aware. This interface is for operations upon the CDB as a whole, notably compacting it using a BeeTreeCompactor (this is supported). You shouldn't use it for anything else (nor should you need to). BeeTree is MT-safe.

Returns:
The BeeTree

dumpSets

public void dumpSets(java.io.PrintStream out)
              throws java.io.IOException
Print the set structure out. This is a debugging tool and is not I18N'ed.

Parameters:
out - The stream to dump to. If null, System.out is used.
Throws:
java.io.IOException - if out throws.

insert

public void insert(CDBObject cdbo)
            throws java.io.IOException
Inserts an object into the CDB. The current-object pointer is not affected.

Parameters:
cdbo - The object to insert.
Throws:
java.io.IOException - if there was a problem - see opening essay.

update

public void update(CDBObject cdbo)
            throws java.io.IOException
Updates the object, which is already in the CDB. The current-object pointer for prev / next operations is set to the updated object.

Parameters:
cdbo - The object to update.
Throws:
java.io.IOException - if there was a problem - see opening essay.

delete

public void delete(CDBObject cdbo)
            throws java.io.IOException
Deletes the supplied object from the CDB. The space it occupied in the file is wiped clear and marked for re-use. The current-object pointer is set to the deleted object (resulting in a throw if used without a find).

Parameters:
cdbo - the object to delete.
Throws:
java.io.IOException - if there was a problem - see opening essay.

changeKey

public void changeKey(CDBObject cdbo,
                      java.lang.String newkey)
               throws java.io.IOException
Changes the key of the supplied object. The current-object pointer for prev / next operations is set to the updated object. The setKey method (and hence the cpsetKey method) will be called on cdbo to change the key. The app is responsible for any other action required to bring the object up to date. Since the object is not marshalled or unmarshalled during the process, niether preMarshal or preUnmarshal will be invoked on it by this method.

Parameters:
cdbo - The object to update.
newkey - The new key.
Throws:
java.io.IOException - if there was a problem - see opening essay.

findFirst

public boolean findFirst(CDBObject cdbo)
                  throws java.io.IOException
Finds an object from a partial key. Give the partial key in cdbo.key. The full object corresponding to the first key matching the partial key is returned, together with the full key. After a findFirst, next and prev will find the next and previous records (and can be applied iteratively).

Parameters:
cdbo - a CDBObject of the required set, containing the partial key.
Returns:
true if the search succeeded, false if it failed (no object in the set had a key consistent with that supplied.)
Throws:
java.io.IOException - if there was a problem - see opening essay.

findFirstKey

public boolean findFirstKey(CDBObject cdbo)
                     throws java.io.IOException
As findFirst, except that the object is not unmarshalled. For finding keys, when not concerned with the objects.

Parameters:
cdbo - a CDBObject of the required set, containing the partial key.
Returns:
true if the search succeeded, false if it failed (no object had a key consistent with that supplied.)
Throws:
java.io.IOException - if there was a problem - see opening essay.

findExact

public boolean findExact(CDBObject cdbo)
                  throws java.io.IOException
Finds an object from an exact key. Give the key in cdbo.key. This saves you from having to check that the key you get is not a superset of the key you wanted. It is also fractionally quicker than findFirst. After a findExact, next and prev will find the next and previous records. (and can be applied iteratively).

Parameters:
cdbo - a CDBObject of the required set, containing the key.
Returns:
true if the search succeeded, false if it failed (no object in the set had that key.)
Throws:
java.io.IOException - if there was a problem - see opening essay.

findExactKey

public boolean findExactKey(CDBObject cdbo)
                     throws java.io.IOException
As findExact, except that the object is not unmarshalled. For finding keys, when not concerned with the objects.

Parameters:
cdbo - a CDBObject of the required set, containing the key.
Returns:
true if the search succeeded, false if it failed (no object in the set had that key.)
Throws:
java.io.IOException - if there was a problem - see opening essay.

next

public boolean next(CDBObject cdbo)
             throws java.io.IOException
Find the next object. Returns as find. If the search fails (as in 'returns false', not as in 'throws an exception') the current-record pointer remains unchanged.

Parameters:
cdbo - a blank CDBBObject of the correct set.
Returns:
true if the search succeeded, false if it failed - this object was the last in the set.
Throws:
java.io.IOException - if there was a problem - see opening essay.

nextKey

public boolean nextKey(CDBObject cdbo)
                throws java.io.IOException
As next, except the CDBObject is not unmarshalled. For finding keys, when not concerned with the objects they index.

Parameters:
cdbo - a blank CDBBObject of the correct set.
Returns:
true if the search succeeded, false if it failed - this object was the last in the set.
Throws:
java.io.IOException - if there was a problem - see opening essay.

nextMatch

public boolean nextMatch(CDBObject cdbo)
                  throws java.io.IOException
Find the next object which matches the partial key from the most recent findFirst. Returns as next. If the operation returns false, the current-record pointer remains unchanged. There is no prevMatch because the process is asymmetrical - prevMatch would be twinned with findLast, and that is not implemented either. (It could be, were there enough demand).

Parameters:
cdbo - a blank CDBBObject of the correct set.
Returns:
true if the search succeeded, false if it failed - this object was the last in the set.
Throws:
java.io.IOException - if there was a problem - see opening essay.

nextMatchKey

public boolean nextMatchKey(CDBObject cdbo)
                     throws java.io.IOException
As nextMatch, except that the object is not unmarshalled.

Parameters:
cdbo - a blank CDBBObject of the correct set.
Returns:
true if the search succeeded, false if it failed - this object was the last in the set that matched the key.
Throws:
java.io.IOException - if there was a problem - see opening essay.

prev

public boolean prev(CDBObject cdbo)
             throws java.io.IOException
Find the previous object, as next.

Parameters:
cdbo - a blank CDBBObject of the correct set.
Returns:
true if the search succeeded, false if it failed - this object was the first in the set.
Throws:
java.io.IOException - if there was a problem - see opening essay.

prevKey

public boolean prevKey(CDBObject cdbo)
                throws java.io.IOException
Find the previous object but don't unmarshal, as nextKey.

Parameters:
cdbo - a blank CDBBObject of the correct set.
Returns:
true if the search succeeded, false if it failed - this object was the first in the set.
Throws:
java.io.IOException - if there was a problem - see opening essay.

threadLock

public void threadLock()
                throws java.io.IOException
Lock the underlying beetree so that only this thread in this VM can use it; all other threads in all other VMs are locked out. This guarantees that a set of operations on the beetree are atomic; this is necessary but not sufficient to comprise a transaction. For the sake of efficiency, apps should try to complete such atomicised operations complete quickly. The disk file is open while the lock holds, increasing its vulnerability in the event of a system failure.

Apps should ensure that the lock is released; generally this is best done using a try...finally block.

This call will block until such a lock can be obtained.

Throws:
java.io.IOException - if there was a problem with disk I/O.

threadUnlock

public void threadUnlock()
                  throws java.lang.IllegalStateException,
                         java.io.IOException
Release the beetree from your previously-applied thread lock.

Throws:
java.lang.IllegalStateException - if this thread does not hold the lock.
java.io.IOException - if there was a problem with disk I/O.

threadLockRO

public void threadLockRO()
                  throws java.io.IOException
As threadLock, but only acquires an RO lock. Improves multithread concurrency, but you do need to make sure that your transaction doesn't do any write operations. Don't nest RO and RW thread locks.

Throws:
java.io.IOException

threadUnlockRO

public void threadUnlockRO()
                    throws java.io.IOException
Release the CDBeeTree from your previously-applied RO thread lock.

Throws:
java.io.IOException

getTotalFree

public long getTotalFree()
                  throws ConsistencyException
Returns the total amount of free space inside the CDB. This space is created when objects or indexing data are deleted. If it becomes a significant fraction of the size of the file, you should compact the CDB.

Returns:
the total free space.
Throws:
ConsistencyException - If the BeeTree is invalid.

getTotalSpaces

public int getTotalSpaces()
                   throws ConsistencyException
Returns the number of free spaces inside the CDB. These are created when objects or indexing data are deleted. If this becomes large, (say a few thousand) you should compact the CDB.

Known bug: the free list is not written back properly. See getTotalFree

Returns:
the total number of free spaces.
Throws:
ConsistencyException - If the BeeTree is invalid.

setThreshold

public void setThreshold(int threshold)
Changes the swapping threshold for temporary space when marshalling. Objects shorter than this are handled entirely in memory. Larger objects may be swapped out to temporary disk files (which are automatically wiped clear when no longer required).

Parameters:
threshold - The threshold.

getContainingFile

public java.io.File getContainingFile()
Returns the File containing the CDB. Do not update this file directly - the results will be horrible.

Returns:
The disk file.

getPassword

public byte[] getPassword()
returns a copy of the current password, if any.

Returns:
the password, or null if it doesn't exist.

setNodeCacheSize

public void setNodeCacheSize(int size)
Changes the size of the node cache. The default size of 131 should be fine for most apps; scale down if you're critically short of memory, or scale up if your CDB is enormous. The size should be a prime number for best performance.


getCipherInstance

public Cipher getCipherInstance()
Returns a new, uninitialised instance of the Cipher corresponding to the current Cipher version.


getNullCipherInstance

public Cipher getNullCipherInstance()
Returns a new, uninitialised instance of the Cipher the tree uses when it's not actually encrypted.