Berkeley DB Java Edition
version 3.0.12

com.sleepycat.persist.evolve
Class ConversionStore

java.lang.Object
  extended by com.sleepycat.persist.raw.RawStore
      extended by com.sleepycat.persist.evolve.ConversionStore

public class ConversionStore
extends RawStore

Provides access to incompatible raw data in a store for performing manual conversions. When opening a conversion store, mutations need not be configured for handling class incompatibilities and IncompatibleClassException will not be thrown.

Manual conversions are needed when Mutations are insufficient for making complex changes to a class hierarchy or entity model. When using an conversion store, an entity may be read even if its stored class definition is incompatible with the current class definition or if the old class is no longer present. Entities may be arbitrarily manipulated, converted to be compatible with current class definitions, and written back to the store.

Note that entities with incompatible classes may be read but not written. Entities written must always conform to the current class definitions.

After a conversion, in order to open the store as an EntityStore or RawStore without causing an IncompatibleClassException, the deleteUnusedType method should be called for every incompatible class. This method should be called after converting or deleting all instances of the incompatible class.

The deleteUnusedType method does not verify that no instances of the given type exist, since that would require traversing one or more primary indices. Instead, the caller is required to have traversed all applicable indices and converted all instance of the type. If an instance of the type still exists and is later accessed via an EntityStore or RawStore, a DeletedClassException will be thrown.

A entity store does not keep track of how many instances exist for a given version of a class. The only way to find old versions is to iterate through all primary indices that may contain incompatible classes and check the types and versions. The type of a stored object is returned by RawObject.getType(); this will either be equal to the current type (returned by EntityModel.getRawType) or the previously stored type (returned by EntityModel.getAllRawTypes). Types may be compared using the equals method, or the version number may be checked.

Using a Temporary Index

Conversion via a temporary index is required for performing a key conversion, since key formats may not be changed. It may also be used to avoid making a backup of the environment before performing a conversion, since the original index is not changed until the temporary index is installed, and the temporary index may be installed safely using a transaction.

For example:

 // The class name and version of the entity instances to be converted.
 //
 String className = ...;
 int classVersion = ...;

 // Open the conversion store, the current index and a temporary index.
 //
 Environment env = ...;
 ConversionStore store = new ConversionStore(env, "myStore", null);
 PrimaryIndex<Object,RawObject> oldIndex = store.getPrimaryIndex(className);
 PrimaryIndex<Object,RawObject> tempIndex = store.getTempIndex(className);

 // Copy the instances from oldIndex to tempIndex, converting all instances
 // to conform to current class definitions.  (See Converter for
 // examples of conversion techniques.)
 //
 ...

 // Using a single transaction, atomically install the new index and delete
 // the (now unused) type of the old instances.
 //
 Transaction txn = env.beginTransaction(null, null);
 store.installTempIndex(txn, tempIndex);
 store.deleteUnusedType(txn, className, classVersion);
 txn.commit();

Using this approach, complex conversions can be performed using any number of indices at once, and a single transaction can be used to atomically commit the changes.

Note that an entire index conversion could be performed in a single transaction. However, for large indices this would use unacceptable amounts of memory to hold transactional locks. Therefore, the recommended approach for converting a large index is to copy it to a temporary index, without transactions, and then use a transaction to install the index and delete the unused types.

Author:
Mark Hayes

Constructor Summary
ConversionStore(Environment env, String storeName, StoreConfig config)
          Opens an entity store for unchecked raw data access.
 
Method Summary
 PrimaryIndex<Object,RawObject> createTempIndex(String entityClass)
          Opens a new temporary primary index for copying new data to a new index rather than updating an index in place.
 void deleteUnusedType(Transaction txn, String className, int classVersion)
          Removes a type for which all instances have been converted.
 void installTempIndex(Transaction txn, PrimaryIndex<Object,RawObject> tempIndex)
          Installs a temporary primary index as the current index.
 
Methods inherited from class com.sleepycat.persist.raw.RawStore
close, getConfig, getEnvironment, getModel, getMutations, getPrimaryIndex, getSecondaryIndex, getStoreName
 
Methods inherited from class java.lang.Object
clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
 

Constructor Detail

ConversionStore

public ConversionStore(Environment env,
                       String storeName,
                       StoreConfig config)
                throws DatabaseException
Opens an entity store for unchecked raw data access.

Parameters:
env - an open Berkeley DB environment.
storeName - the name of the entity store within the given environment.
config - the store configuration, or null to use default configuration properties.
Throws:
IllegalArgumentException - if the Environment is read-only or the config ReadOnly property is true.
DatabaseException
Method Detail

createTempIndex

public PrimaryIndex<Object,RawObject> createTempIndex(String entityClass)
                                               throws DatabaseException
Opens a new temporary primary index for copying new data to a new index rather than updating an index in place. The temporary index will be initially empty.

Entities may be copied from the current primary index to the temporary primary index, changing the key format in the process if desired. When conversion is completed successfully, installTempIndex(com.sleepycat.je.Transaction, com.sleepycat.persist.PrimaryIndex) should be called. If this conversion store is closed without calling installTempIndex(com.sleepycat.je.Transaction, com.sleepycat.persist.PrimaryIndex), the temporary index will be deleted. If a conversion store is opened and any residual temporary indices exist, they will be deleted.

Conversion via a temporary index is required for performing a key conversion, since key formats may not be changed. It may also be used to avoid making a backup of the environment before performing a conversion, since the original index is not changed until the temporary index is installed, and the temporary index may be installed safely using a transaction.

Throws:
DatabaseException

installTempIndex

public void installTempIndex(Transaction txn,
                             PrimaryIndex<Object,RawObject> tempIndex)
                      throws DatabaseException
Installs a temporary primary index as the current index. The current index is removed and the temporary index is renamed to the current index.

Throws:
DatabaseException

deleteUnusedType

public void deleteUnusedType(Transaction txn,
                             String className,
                             int classVersion)
Removes a type for which all instances have been converted.

When performing a conversion, instances of an incompatible class version may be converted to a different type or deleted entirely. This method is called to inform the store that such a type has no instances and no longer requires conversion. In addition to freeing the space taken by the unused type definition, deleting an incompatible type allows opening an EntityStore (or RawStore) without causing an IncompatibleClassException.

This method does not verify that no instances of the given type exist, since that would require traversing one or more primary indices. Instead, the caller is required to have traversed all applicable indices and converted all instance of the type. If an instance of the type still exists and is later accessed via an EntityStore or RawStore, a DeletedClassException will be thrown.


Berkeley DB Java Edition
version 3.0.12

Copyright (c) 1996-2006 Sleepycat Software, Inc. - All rights reserved.