Class Database
Includes support for:
- Objects and fields defined by a
SchemaModel
, with positive schema verification - Simple value fields containing any standard or custom type that has an
Encoding
- Invertable reference fields with referential integrity and configurable delete cascading
- Lockless counter fields
- Complex fields of type
List
,NavigableSet
, andNavigableMap
- Configurable indexing of any simple field or complex sub-field
- Composite indexes on multiple simple fields
- Notification of object creation and deletion
- Notification of object field changes, as seen through an arbitrary path of references
- Automatic schema tracking and migration with notification support
See Transaction
for further details on the above functionality.
This class defines an abstraction layer that usually sits below a Permazen
but is completely
independent of Permazen
and can be used on its own.
Compared to Permazen
, a Database
has these differences:
- A
SchemaModel
must be explicitly provided to define the schema in use, whereas when using aPermazen
the schema is derived automatically from annotated Java model classes. - Simple fields are encoded/decoded into
byte[]
arrays using anEncoding
which defines the field's "type". - References from one object to another are represented by
ObjId
s and encoded/decoded usingReferenceEncoding
. - There is no explicit notion of object sub-types, i.e., the object type hierarchy is completely flat. However, object types can share the same field definitions, and reference fields can be restricted to only refer to certain other object types.
- There is no automatic validation support.
Schema Tracking
Within each Database
is stored a record of all schemas used with that database (termed the "schema bundle").
When creating a new transaction, the caller provides a SchemaModel
to use for accessing objects in the transaction.
If the schema is not already registered in the database, it is automatically registered if at the start of the transaction
assuming TransactionConfig.isAllowNewSchema()
is true (otherwise a SchemaMismatchException
is thrown).
Transactions can be opened with an empty SchemaModel
when no particular schema
is needed. In any case, the empty SchemaModel
is never recorded in a database.
Schema Migration
Each object in a Database
is associated with an object type
in one of the registered schemas;
this dictates which fields the object contains, how they are indexed, etc. Newly created objects are always defined
in terms of the transaction's configured schema, but it's also possible to access objects that were created
in previous transactions under different schemas.
When an object is accessed during a Transaction
, if the object's schema is not the transaction's configured
schema, then (if requested) the object will be automatically migrated to the transaction's schema if the object's type
still exists (otherwise a TypeNotInSchemaException
is thrown).
Object migration involves the following steps:
- Fields that exist in the old schema but not in the current schema are removed.
- Fields that exist in the current schema but not in the old schema are initialized to their default values.
- For fields that are common to both the old and the new schema:
- If the two field's
Encoding
s are the same, the value is not changed - Otherwise, the field's old value is converted to the new
Encoding
, if possible, viaEncoding.convert()
. - Otherwise, the field is reset to its default value.
- Any
SchemaChangeListener
s registered with theTransaction
are notified.
Object type and field identity is based on names. So when comparing across schemas, two object types or fields are assumed to be "the same" if they have the same name.
Indexes may be added and removed across different schemas without losing information, however,
indexes will only contain those objects whose schema includes the index. In other words, it's not
possible to find an object using an index that was added after the object was created until the object
is migrated to a newer schema. The same principle applies to other schema-defined behavior, for example,
the DeleteAction
taken when a referenced object is deleted depends on the DeleteAction
configured in the schema of the object containing the reference.
- See Also:
-
Field Summary
Modifier and TypeFieldDescriptionstatic final int
The maximum number of fields that may be indexed in a composite index (4). -
Constructor Summary
-
Method Summary
Modifier and TypeMethodDescriptioncreateDetachedTransaction
(KVStore kvstore, TransactionConfig txConfig) Create a detached transaction based on the provided key/value store.createTransaction
(TransactionConfig txConfig) Create a newTransaction
on this database using the specific configuration.createTransaction
(KVTransaction kvt, TransactionConfig txConfig) Create a newTransaction
on this database using an already-openedKVTransaction
and specified configuration.createTransaction
(SchemaModel schemaModel) Create a newTransaction
on this database using the givenSchemaModel
and the defaults for all otherTransactionConfig
items.Get theEncodingRegistry
associated with this instance.Get theKVDatabase
underlying this instance.void
setEncodingRegistry
(EncodingRegistry encodingRegistry) Set theEncodingRegistry
associated with this instance.
-
Field Details
-
MAX_INDEXED_FIELDS
public static final int MAX_INDEXED_FIELDSThe maximum number of fields that may be indexed in a composite index (4).- See Also:
-
-
Constructor Details
-
Database
Constructor.- Parameters:
kvdb
- the underlying key/value store in which to store information- Throws:
IllegalArgumentException
- ifkvdb
is null
-
-
Method Details
-
getEncodingRegistry
Get theEncodingRegistry
associated with this instance.By default a
DefaultEncodingRegistry
is automatically created.- Returns:
- encoding registry associated with this instance
-
setEncodingRegistry
Set theEncodingRegistry
associated with this instance.- Parameters:
encodingRegistry
- encoding registry to associate with this instance- Throws:
IllegalArgumentException
- ifencodingRegistry
is null
-
getKVDatabase
Get theKVDatabase
underlying this instance.- Returns:
- underlying key/value database
-
createTransaction
Create a newTransaction
on this database using the givenSchemaModel
and the defaults for all otherTransactionConfig
items.Equivalent to:
createTransaction
(TransactionConfig.builder().schemaModel(schemaModel).build())
.- Parameters:
schemaModel
- schema model- Returns:
- newly created transaction
- Throws:
InvalidSchemaException
- if the configured schema is invalid (i.e., does not pass validation checks)SchemaMismatchException
- if the configuredSchemaModel
has any explicit storage ID assignments that conflict with storage ID assignments already recorded in the databaseInconsistentDatabaseException
- if inconsistent or invalid meta-data is detected in the databaseInconsistentDatabaseException
- if an uninitialized database is encountered but the database is not emptyIllegalArgumentException
- ifschemaModel
is null
-
createTransaction
Create a newTransaction
on this database using the specific configuration.- Parameters:
txConfig
- transaction configuration- Returns:
- newly created transaction
- Throws:
InvalidSchemaException
- if the configured schema is invalid (i.e., does not pass validation checks)SchemaMismatchException
- if the configured schema is not registered in the database andTransactionConfig.isAllowNewSchema()
is falseSchemaMismatchException
- if the configuredSchemaModel
has any explicit storage ID assignments that conflict with storage ID assignments already recorded in the databaseInconsistentDatabaseException
- if inconsistent or invalid meta-data is detected in the databaseInconsistentDatabaseException
- if an uninitialized database is encountered but the database is not emptyIllegalArgumentException
- iftxConfig
is null
-
createTransaction
Create a newTransaction
on this database using an already-openedKVTransaction
and specified configuration.The given
KVTransaction
will be committed or rolled-back along with the returnedTransaction
.See
createTransaction(TransactionConfig)
for further details.- Parameters:
kvt
- already opened key/value store transactiontxConfig
- transaction configuration- Returns:
- newly created transaction
- Throws:
IllegalArgumentException
- ifkvt
ortxConfig
is null
-
createDetachedTransaction
Create a detached transaction based on the provided key/value store.The key/value store will be initialized if necessary (i.e.,
kvstore
may be empty), otherwise it will be validated against the schema information associated with this instance.The returned
DetachedTransaction
does not supportcommit()
orrollback()
and can be used indefinitely. It does supportaddCallback()
but that method has no effect because the transaction cannot be committed.DetachedTransaction
's do implementCloseable
; if thkvstore
is aCloseableKVStore
, then it will beclose()
'd if/when the returnedDetachedTransaction
is.See
createTransaction(TransactionConfig)
for further details.- Parameters:
kvstore
- key/value store, empty or having content compatible with this transaction'sDatabase
txConfig
- transaction configuration- Returns:
- detached transaction based on
kvstore
- Throws:
InvalidSchemaException
- if the configured schema is invalid (i.e., does not pass validation checks)SchemaMismatchException
- if the configuredSchemaModel
has any explicit storage ID assignments that conflict with storage ID assignments already recorded in the databaseInconsistentDatabaseException
- if inconsistent or invalid meta-data is detected in the databaseInconsistentDatabaseException
- if an uninitialized database is encountered but the database is not emptyIllegalArgumentException
- ifkvstore
ortxConfig
is null
-