Class RDBDocumentStore
- java.lang.Object
-
- org.apache.jackrabbit.oak.plugins.document.rdb.RDBDocumentStore
-
- All Implemented Interfaces:
DocumentStore
public class RDBDocumentStore extends Object implements DocumentStore
Implementation ofDocumentStorefor relational databases.Supported Databases
The code is supposed to be sufficiently generic to run with a variety of database implementations. However, the tables are created when required to simplify testing, and that code specifically supports these databases:
- H2DB
- Apache Derby
- IBM DB2
- PostgreSQL
- MariaDB (MySQL)
- Microsoft SQL Server
- Oracle
Table Layout
Data for each of the DocumentStore's
Collections is stored in its own database table (with a name matching the collection).The tables essentially implement key/value storage, where the key usually is derived from an Oak path, and the value is a serialization of a
Document(or a part of one). Additional fields are used for queries, debugging, and concurrency control:Column Type Description ID varchar(512) not null primary key The document's key (for databases that can not handle 512 character primary keys, such as MySQL, varbinary is possible as well). MODIFIED bigint Low-resolution timestamp. HASBINARY smallint Flag indicating whether the document has binary properties. DELETEDONCE smallint Flag indicating whether the document has been deleted once. MODCOUNT bigint Modification counter, used for avoiding overlapping updates. DSIZE bigint The approximate size of the document's JSON serialization (for debugging purposes). VERSION smallint The schema version the code writing to a row (or inserting it) was aware of (introduced with schema version 1). Not set for rows written by version 0 client code. SDTYPE smallint Split Document type. SDMAXREVTIME bigint Split document max revision time.. DATA varchar(16384) The document's JSON serialization (only used for small document sizes, in which case BDATA (below) is not set), or a sequence of JSON serialized update operations to be applied against the last full serialization. BDATA blob The document's JSON serialization (usually GZIPped, only used for "large" documents). The names of database tables can be prefixed; the purpose is mainly for testing, as tables can also be dropped automatically when the store is disposed (this only happens for those tables that have been created on demand).
Versioning
The initial database layout used in OAK 1.0 through 1.6 is version 0.
Version 1 introduces an additional "version" column, which records the schema version of the code writing to the database (upon insert and update). This is in preparation of future layout changes which might introduce new columns.
Version 2 introduces an additional "sdtype" and "sdmaxrevtime".
The code deals with both version 0, version 1 and version 2 table layouts. By default, it tries to create version 2 tables, and also tries to upgrade existing version 0 and 1 tables to version 2.
DB-specific information
Databases need to be configured so that:
- Text fields support all Unicode code points,
- Collation of text fields happens by Unicode code point,
- and BLOBs need to support at least 16 MB.
See the RDBDocumentStore documentation for more information.
Table Creation
The code tries to create the tables when they are not present. Likewise, it tries to upgrade to a newer schema when needed.
Users/Administrators who prefer to stay in control over table generation can create them "manually". The oak-run "
rdbddldump" command can be used to print out the DDL statements that would have been used for auto-creation and/or automatic schema updates.Caching
The cache borrows heavily from the
MongoDocumentStoreimplementation.Queries
The implementation currently supports only three indexed properties: "_bin", "deletedOnce", and "_modified". Attempts to use a different indexed property will cause a
DocumentStoreException.
-
-
Nested Class Summary
Nested Classes Modifier and Type Class Description protected static classRDBDocumentStore.QueryConditionprotected classRDBDocumentStore.UnsupportedIndexedPropertyException
-
Field Summary
Fields Modifier and Type Field Description static intCHAR2OCTETRATIOstatic StringCOLLISIONSMODCOUNTOptional counter for changes to "_collisions" map (NodeDocument.COLLISIONS).protected static List<String>EMPTY_KEY_PATTERNprotected static intSCHEMAprotected static booleanUSECMODCOUNTstatic StringVERSIONPROP
-
Constructor Summary
Constructors Constructor Description RDBDocumentStore(DataSource ds, DocumentNodeStoreBuilder<?> builder)Creates a RDBDocumentStore instance using the providedDataSource,DocumentNodeStoreBuilder, and defaultRDBOptions.RDBDocumentStore(DataSource ds, DocumentNodeStoreBuilder<?> builder, RDBOptions options)Creates a RDBDocumentStore instance using the providedDataSource,DocumentNodeStoreBuilder, andRDBOptions.
-
Method Summary
All Methods Static Methods Instance Methods Concrete Methods Modifier and Type Method Description static byte[]asBytes(@NotNull String data)protected <T extends Document>
TconvertFromDBObject(@NotNull Collection<T> collection, @NotNull RDBRow row)<T extends Document>
booleancreate(Collection<T> collection, List<UpdateOp> updateOps)Try to create a list of documents.<T extends Document>
List<T>createOrUpdate(Collection<T> collection, List<UpdateOp> updateOps)Create or unconditionally update a number of documents.<T extends Document>
TcreateOrUpdate(Collection<T> collection, UpdateOp update)Atomically checks if the document exists and updates it, otherwise the document is created (aka "upsert"), unless the update operation requires the document to be present (seeUpdateOp.isNew()).longdetermineServerTimeDifferenceMillis()voiddispose()Dispose this instance.protected voidfinalize()<T extends Document>
Tfind(Collection<T> collection, String id)Get the document with the givenkey.<T extends Document>
Tfind(Collection<T> collection, String id, int maxCacheAge)Get the document with thekey.<T extends Document>
TfindAndUpdate(Collection<T> collection, UpdateOp update)Performs a conditional update (e.g.Iterable<CacheStats>getCacheStats()StringgetDroppedTables()<T extends Document>
TgetIfCached(Collection<T> collection, String id)Fetches the cached document.Map<String,String>getMetadata()protected <T extends Document>
longgetMinValue(Collection<T> collection, String field, String fromKey, String toKey, List<String> excludeKeyPatterns, List<RDBDocumentStore.QueryCondition> conditions)protected NodeDocumentCachegetNodeDocumentCache()@NotNull Map<String,String>getStats()Statistics are generated for each table.protected <T extends Document>
@NotNull org.apache.jackrabbit.oak.plugins.document.rdb.RDBDocumentStore.RDBTableMetaDatagetTable(Collection<T> collection)static List<String>getTableNames()CacheInvalidationStatsinvalidateCache()Invalidate the document cache.CacheInvalidationStatsinvalidateCache(Iterable<String> keys)Invalidate the document cache but only with entries that match one of the keys provided.<T extends Document>
voidinvalidateCache(Collection<T> collection, String id)Invalidate the document cache for the given key.booleanisReadOnly()<T extends Document>
@NotNull List<T>query(Collection<T> collection, String fromKey, String toKey, int limit)Get a list of documents where the key is greater than a start value and less than an end value.<T extends Document>
@NotNull List<T>query(Collection<T> collection, String fromKey, String toKey, String indexedProperty, long startValue, int limit)Get a list of documents where the key is greater than a start value and less than an end value and the given "indexed property" is greater or equals the specified value.protected <T extends Document>
@NotNull List<T>query(Collection<T> collection, String fromKey, String toKey, List<String> excludeKeyPatterns, List<RDBDocumentStore.QueryCondition> conditions, int limit)protected <T extends Document>
Iterable<T>queryAsIterable(Collection<T> collection, String fromKey, String toKey, List<String> excludeKeyPatterns, List<RDBDocumentStore.QueryCondition> conditions, int limit, String sortBy)protected <T extends Document>
longqueryCount(Collection<T> collection, String fromKey, String toKey, List<String> excludeKeyPatterns, List<RDBDocumentStore.QueryCondition> conditions)<T extends Document>
voidremove(Collection<T> collection, String id)Remove a document.<T extends Document>
intremove(Collection<T> collection, String indexedProperty, long startValue, long endValue)Batch remove documents where the given "indexed property" is within the given range (exclusive) -(startValue, endValue).<T extends Document>
voidremove(Collection<T> collection, List<String> ids)Batch remove documents with given keys.<T extends Document>
intremove(Collection<T> collection, Map<String,Long> toRemove)Batch remove documents with given keys and corresponding equal conditions onNodeDocument.MODIFIED_IN_SECSvalues.voidsetReadWriteMode(String readWriteMode)Set the level of guarantee for read and write operations, if supported by this backend.voidsetStatsCollector(DocumentStoreStatsCollector stats)-
Methods inherited from class java.lang.Object
clone, equals, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
-
Methods inherited from interface org.apache.jackrabbit.oak.plugins.document.DocumentStore
findAndUpdate, getNodeNameLimit, prefetch, query, throttler
-
-
-
-
Field Detail
-
COLLISIONSMODCOUNT
public static final String COLLISIONSMODCOUNT
Optional counter for changes to "_collisions" map (NodeDocument.COLLISIONS).- See Also:
- Constant Field Values
-
CHAR2OCTETRATIO
public static final int CHAR2OCTETRATIO
- See Also:
- Constant Field Values
-
USECMODCOUNT
protected static final boolean USECMODCOUNT
- See Also:
- Constant Field Values
-
SCHEMA
protected static final int SCHEMA
- See Also:
- Constant Field Values
-
VERSIONPROP
public static String VERSIONPROP
-
-
Constructor Detail
-
RDBDocumentStore
public RDBDocumentStore(DataSource ds, DocumentNodeStoreBuilder<?> builder, RDBOptions options)
Creates a RDBDocumentStore instance using the providedDataSource,DocumentNodeStoreBuilder, andRDBOptions.
-
RDBDocumentStore
public RDBDocumentStore(DataSource ds, DocumentNodeStoreBuilder<?> builder)
Creates a RDBDocumentStore instance using the providedDataSource,DocumentNodeStoreBuilder, and defaultRDBOptions.
-
-
Method Detail
-
find
public <T extends Document> T find(Collection<T> collection, String id)
Description copied from interface:DocumentStoreGet the document with the givenkey. This is a convenience method and equivalent toDocumentStore.find(Collection, String, int)with amaxCacheAgeofInteger.MAX_VALUE.The returned document is immutable.
- Specified by:
findin interfaceDocumentStore- Type Parameters:
T- the document type- Parameters:
collection- the collectionid- the key- Returns:
- the document, or null if not found
-
find
public <T extends Document> T find(Collection<T> collection, String id, int maxCacheAge)
Description copied from interface:DocumentStoreGet the document with thekey. The implementation may serve the document from a cache, but the cached document must not be older than the givenmaxCacheAgein milliseconds. An implementation must invalidate a cached document when it detects it is outdated. That is, a subsequent call toDocumentStore.find(Collection, String)must return the newer version of the document.The returned document is immutable.
- Specified by:
findin interfaceDocumentStore- Type Parameters:
T- the document type- Parameters:
collection- the collectionid- the keymaxCacheAge- the maximum age of the cached document (in ms)- Returns:
- the document, or null if not found
-
query
@NotNull public <T extends Document> @NotNull List<T> query(Collection<T> collection, String fromKey, String toKey, int limit)
Description copied from interface:DocumentStoreGet a list of documents where the key is greater than a start value and less than an end value.The returned documents are sorted by key and are immutable.
- Specified by:
queryin interfaceDocumentStore- Type Parameters:
T- the document type- Parameters:
collection- the collectionfromKey- the start value (excluding)toKey- the end value (excluding)limit- the maximum number of entries to return (starting with the lowest key)- Returns:
- the list (possibly empty)
-
query
@NotNull public <T extends Document> @NotNull List<T> query(Collection<T> collection, String fromKey, String toKey, String indexedProperty, long startValue, int limit)
Description copied from interface:DocumentStoreGet a list of documents where the key is greater than a start value and less than an end value and the given "indexed property" is greater or equals the specified value.The indexed property can either be a
Longvalue, in which case numeric comparison applies, or aBooleanvalue, in which case "false" is mapped to "0" and "true" is mapped to "1".The returned documents are sorted by key and are immutable.
- Specified by:
queryin interfaceDocumentStore- Type Parameters:
T- the document type- Parameters:
collection- the collectionfromKey- the start value (excluding)toKey- the end value (excluding)indexedProperty- the name of the indexed property (optional)startValue- the minimum value of the indexed propertylimit- the maximum number of entries to return- Returns:
- the list (possibly empty)
-
query
@NotNull protected <T extends Document> @NotNull List<T> query(Collection<T> collection, String fromKey, String toKey, List<String> excludeKeyPatterns, List<RDBDocumentStore.QueryCondition> conditions, int limit)
-
remove
public <T extends Document> void remove(Collection<T> collection, String id)
Description copied from interface:DocumentStoreRemove a document. This method does nothing if there is no document with the given key.In case of a
DocumentStoreException, the document with the given key may or may not have been removed from the store. It is the responsibility of the caller to check whether it still exists. The implementation however ensures that the result of the operation is properly reflected in the document cache. That is, an implementation could simply evict the document with the given key.- Specified by:
removein interfaceDocumentStore- Type Parameters:
T- the document type- Parameters:
collection- the collectionid- the key
-
remove
public <T extends Document> void remove(Collection<T> collection, List<String> ids)
Description copied from interface:DocumentStoreBatch remove documents with given keys. Keys for documents that do not exist are simply ignored. If this method fails with an exception, then only some of the documents identified bykeysmay have been removed.In case of a
DocumentStoreException, the documents with the given keys may or may not have been removed from the store. It may also be possible that only some have been removed from the store. It is the responsibility of the caller to check which documents still exist. The implementation however ensures that the result of the operation is properly reflected in the document cache. That is, an implementation could simply evict documents with the given keys from the cache.- Specified by:
removein interfaceDocumentStore- Type Parameters:
T- the document type- Parameters:
collection- the collectionids- list of keys
-
remove
public <T extends Document> int remove(Collection<T> collection, Map<String,Long> toRemove)
Description copied from interface:DocumentStoreBatch remove documents with given keys and corresponding equal conditions onNodeDocument.MODIFIED_IN_SECSvalues. Keys for documents that do not exist are simply ignored. A document is only removed if the corresponding condition is met.In case of a
DocumentStoreException, the documents with the given keys may or may not have been removed from the store. It may also be possible that only some have been removed from the store. It is the responsibility of the caller to check which documents still exist. The implementation however ensures that the result of the operation is properly reflected in the document cache. That is, an implementation could simply evict documents with the given keys from the cache.- Specified by:
removein interfaceDocumentStore- Type Parameters:
T- the document type- Parameters:
collection- the collection.toRemove- the keys of the documents to remove with the corresponding timestamps.- Returns:
- the number of removed documents.
-
remove
public <T extends Document> int remove(Collection<T> collection, String indexedProperty, long startValue, long endValue) throws DocumentStoreException
Description copied from interface:DocumentStoreBatch remove documents where the given "indexed property" is within the given range (exclusive) -(startValue, endValue).The indexed property is a
Longvalue and numeric comparison applies.In case of a
DocumentStoreException, the documents with the given keys may or may not have been removed from the store. It may also be possible that only some have been removed from the store. It is the responsibility of the caller to check which documents still exist. The implementation however ensures that the result of the operation is properly reflected in the document cache. That is, an implementation could simply evict documents with the given keys from the cache.- Specified by:
removein interfaceDocumentStore- Type Parameters:
T- the document type- Parameters:
collection- the collection.indexedProperty- the name of the indexed propertystartValue- the minimum value of the indexed property (exclusive)endValue- the maximum value of the indexed property (exclusive)- Returns:
- the number of removed documents.
- Throws:
DocumentStoreException- if the operation failed. E.g. because of an I/O error.
-
create
public <T extends Document> boolean create(Collection<T> collection, List<UpdateOp> updateOps)
Description copied from interface:DocumentStoreTry to create a list of documents. This method returnstrueiff none of the documents existed before and the create was successful. This method will returnfalseif one of the documents already exists in the store. Some documents may still have been created in the store. An implementation does not have to guarantee an atomic create of all the documents described in theupdateOps. It is the responsibility of the caller to check, which documents were created and take appropriate action. The same is true when this method throwsDocumentStoreException(e.g. when a communication error occurs). In this case only some documents may have been created.- Specified by:
createin interfaceDocumentStore- Type Parameters:
T- the document type- Parameters:
collection- the collectionupdateOps- the list of documents to add (whereUpdateOp.Conditions are not allowed)- Returns:
- true if this worked (if none of the documents already existed)
-
createOrUpdate
public <T extends Document> T createOrUpdate(Collection<T> collection, UpdateOp update)
Description copied from interface:DocumentStoreAtomically checks if the document exists and updates it, otherwise the document is created (aka "upsert"), unless the update operation requires the document to be present (seeUpdateOp.isNew()). The returned document is immutable.If this method fails with a
DocumentStoreException, then the document may or may not have been created or updated. It is the responsibility of the caller to check the result e.g. by callingDocumentStore.find(Collection, String). The implementation however ensures that the result of the operation is properly reflected in the document cache. That is, an implementation could simply evict documents with the given keys from the cache.- Specified by:
createOrUpdatein interfaceDocumentStore- Type Parameters:
T- the document type- Parameters:
collection- the collectionupdate- the update operation (whereUpdateOp.Conditions are not allowed)- Returns:
- the old document or
nullif it either didn't exist before, or the UpdateOp required the document to be present butUpdateOp.isNew()wasfalse.
-
createOrUpdate
public <T extends Document> List<T> createOrUpdate(Collection<T> collection, List<UpdateOp> updateOps)
Description copied from interface:DocumentStoreCreate or unconditionally update a number of documents. An implementation does not have to guarantee that all changes are applied atomically, together.In case of a
DocumentStoreException(e.g. when a communication error occurs) only some changes may have been applied. In this case it is the responsibility of the caller to check which UpdateOps were applied and take appropriate action. The implementation however ensures that the result of the operations are properly reflected in the document cache. That is, an implementation could simply evict documents related to the given update operations from the cache.- Specified by:
createOrUpdatein interfaceDocumentStore- Type Parameters:
T- the document type- Parameters:
collection- the collectionupdateOps- the update operation list- Returns:
- the list containing old documents or
nullvalues if they didn't exist before (see DocumentStore.createOrUpdate(Collection, UpdateOp)), where the order reflects the order in the "updateOps" parameter
-
findAndUpdate
public <T extends Document> T findAndUpdate(Collection<T> collection, UpdateOp update)
Description copied from interface:DocumentStorePerforms a conditional update (e.g. usingUpdateOp.Condition.Type.EXISTSand only updates the document if the condition istrue. The returned document is immutable.In case of a
DocumentStoreException(e.g. when a communication error occurs) the update may or may not have been applied. In this case it is the responsibility of the caller to check whether the update was applied and take appropriate action. The implementation however ensures that the result of the operation is properly reflected in the document cache. That is, an implementation could simply evict the document related to the given update operation from the cache.- Specified by:
findAndUpdatein interfaceDocumentStore- Type Parameters:
T- the document type- Parameters:
collection- the collectionupdate- the update operation with the condition- Returns:
- the old document or
nullif the condition is not met or if the document wasn't found - See Also:
DocumentStore.createOrUpdate(Collection, List)
-
invalidateCache
public CacheInvalidationStats invalidateCache()
Description copied from interface:DocumentStoreInvalidate the document cache. Calling this method instructs the implementation to invalidate each document from the cache, which is not up to date with the underlying storage at the time this method is called. A document is considered in the cache ifDocumentStore.getIfCached(Collection, String)returns a non-null value for a key.An implementation is allowed to perform lazy invalidation and only check whether a document is up-to-date when it is accessed after this method is called. However, this also includes a call to
DocumentStore.getIfCached(Collection, String), which must only return the document if it was up-to-date at the time this method was called. Similarly, a call toDocumentStore.find(Collection, String)must guarantee the returned document reflects all the changes done up to wheninvalidateCache()was called.In some implementations this method can be a NOP because documents can only be modified through a single instance of a
DocumentStore.- Specified by:
invalidateCachein interfaceDocumentStore- Returns:
- cache invalidation statistics or
nullif none are available.
-
invalidateCache
public CacheInvalidationStats invalidateCache(Iterable<String> keys)
Description copied from interface:DocumentStoreInvalidate the document cache but only with entries that match one of the keys provided. SeeDocumentStore.invalidateCache()for the general contract of cache invalidation.- Specified by:
invalidateCachein interfaceDocumentStore- Parameters:
keys- the keys of the documents to invalidate.- Returns:
- cache invalidation statistics or
nullif none are available.
-
invalidateCache
public <T extends Document> void invalidateCache(Collection<T> collection, String id)
Description copied from interface:DocumentStoreInvalidate the document cache for the given key. SeeDocumentStore.invalidateCache()for the general contract of cache invalidation.- Specified by:
invalidateCachein interfaceDocumentStore- Parameters:
collection- the collectionid- the key
-
determineServerTimeDifferenceMillis
public long determineServerTimeDifferenceMillis()
- Specified by:
determineServerTimeDifferenceMillisin interfaceDocumentStore- Returns:
- the estimated time difference in milliseconds between the local instance and the (typically common, shared) document server system. The value can be zero if the times are estimated to be equal, positive when the local instance is ahead of the remote server and negative when the local instance is behind the remote server. An invocation is not cached and typically requires a round-trip to the server (but that is not a requirement).
-
getDroppedTables
public String getDroppedTables()
-
dispose
public void dispose()
Description copied from interface:DocumentStoreDispose this instance.- Specified by:
disposein interfaceDocumentStore
-
getIfCached
public <T extends Document> T getIfCached(Collection<T> collection, String id)
Description copied from interface:DocumentStoreFetches the cached document. If the document is not present in the cachenullwill be returned. This method is consistent with other find methods that may return cached documents and will returnnulleven when the implementation has a negative cache for documents that do not exist. This method will never returnNodeDocument.NULL.- Specified by:
getIfCachedin interfaceDocumentStore- Type Parameters:
T- the document type- Parameters:
collection- the collectionid- the key- Returns:
- cached document if present. Otherwise
null.
-
getCacheStats
public Iterable<CacheStats> getCacheStats()
- Specified by:
getCacheStatsin interfaceDocumentStore- Returns:
- status information about the cache
-
getMetadata
public Map<String,String> getMetadata()
- Specified by:
getMetadatain interfaceDocumentStore- Returns:
- description of the underlying storage.
-
getStats
@NotNull public @NotNull Map<String,String> getStats()
Statistics are generated for each table. The following fields are always added:- tableName.ns
- fully qualified name of the database table
- tableName.schemaInfo
- DDL information for table, as obtained during startup
- tableName.indexInfo
- DDL information for associated indexes, as obtained during startup
- tableName.count
- exact number of rows
Collection.CLUSTER_NODESis added:- clusterNodes.updates
- Writes to the table, counted by cluster node ID
RDBDocumentStoreDB.getAdditionalStatistics(RDBConnectionHandler, String, String)for details.- Specified by:
getStatsin interfaceDocumentStore- Returns:
- statistics about this document store.
-
isReadOnly
public boolean isReadOnly()
-
finalize
protected void finalize() throws Throwable
-
queryAsIterable
protected <T extends Document> Iterable<T> queryAsIterable(Collection<T> collection, String fromKey, String toKey, List<String> excludeKeyPatterns, List<RDBDocumentStore.QueryCondition> conditions, int limit, String sortBy)
-
queryCount
protected <T extends Document> long queryCount(Collection<T> collection, String fromKey, String toKey, List<String> excludeKeyPatterns, List<RDBDocumentStore.QueryCondition> conditions)
-
getMinValue
protected <T extends Document> long getMinValue(Collection<T> collection, String field, String fromKey, String toKey, List<String> excludeKeyPatterns, List<RDBDocumentStore.QueryCondition> conditions)
-
getTable
@NotNull protected <T extends Document> @NotNull org.apache.jackrabbit.oak.plugins.document.rdb.RDBDocumentStore.RDBTableMetaData getTable(Collection<T> collection)
-
asBytes
public static byte[] asBytes(@NotNull @NotNull String data)
-
setReadWriteMode
public void setReadWriteMode(String readWriteMode)
Description copied from interface:DocumentStoreSet the level of guarantee for read and write operations, if supported by this backend.- Specified by:
setReadWriteModein interfaceDocumentStore- Parameters:
readWriteMode- the read/write mode
-
setStatsCollector
public void setStatsCollector(DocumentStoreStatsCollector stats)
-
convertFromDBObject
@NotNull protected <T extends Document> T convertFromDBObject(@NotNull @NotNull Collection<T> collection, @NotNull @NotNull RDBRow row)
-
getNodeDocumentCache
protected NodeDocumentCache getNodeDocumentCache()
-
-