| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You under the Apache License, Version 2.0 |
| * (the "License"); you may not use this file except in compliance with |
| * the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| package org.apache.jackrabbit.oak.plugins.document; |
| |
| import java.util.List; |
| import java.util.Map; |
| |
| import org.apache.jackrabbit.oak.cache.CacheStats; |
| import org.apache.jackrabbit.oak.plugins.document.UpdateOp.Condition; |
| import org.apache.jackrabbit.oak.plugins.document.cache.CacheInvalidationStats; |
| import org.jetbrains.annotations.NotNull; |
| import org.jetbrains.annotations.Nullable; |
| |
| /** |
| * The interface for the backend storage for documents. |
| * <p> |
| * In general atomicity of operations on a DocumentStore are limited to a single |
| * document. That is, an implementation does not have to guarantee atomicity of |
| * the entire effect of a method call. A method that fails with an exception may |
| * have modified just some documents and then abort. However, an implementation |
| * must not modify a document partially. Either the complete update operation is |
| * applied to a document or no modification is done at all. |
| * <p> |
| * The key is the id of a document. Keys are opaque strings. All characters are |
| * allowed. Leading and trailing whitespace is allowed. For keys, the maximum |
| * length is 512 bytes in the UTF-8 representation. |
| */ |
| public interface DocumentStore { |
| |
| /** |
| * Get the document with the given {@code key}. This is a convenience method |
| * and equivalent to {@link #find(Collection, String, int)} with a |
| * {@code maxCacheAge} of {@code Integer.MAX_VALUE}. |
| * <p> |
| * The returned document is immutable. |
| * |
| * @param <T> the document type |
| * @param collection the collection |
| * @param key the key |
| * @return the document, or null if not found |
| * @throws DocumentStoreException if the operation failed. E.g. because of |
| * an I/O error. |
| */ |
| @Nullable |
| <T extends Document> T find(Collection<T> collection, String key) |
| throws DocumentStoreException; |
| |
| /** |
| * Get the document with the {@code key}. The implementation may serve the |
| * document from a cache, but the cached document must not be older than |
| * the given {@code maxCacheAge} in milliseconds. An implementation must |
| * invalidate a cached document when it detects it is outdated. That is, a |
| * subsequent call to {@link #find(Collection, String)} must return the |
| * newer version of the document. |
| * <p> |
| * The returned document is immutable. |
| * |
| * @param <T> the document type |
| * @param collection the collection |
| * @param key the key |
| * @param maxCacheAge the maximum age of the cached document (in ms) |
| * @return the document, or null if not found |
| * @throws DocumentStoreException if the operation failed. E.g. because of |
| * an I/O error. |
| */ |
| @Nullable |
| <T extends Document> T find(Collection<T> collection, String key, int maxCacheAge) |
| throws DocumentStoreException; |
| |
| /** |
| * Get a list of documents where the key is greater than a start value and |
| * less than an end value. |
| * <p> |
| * The returned documents are sorted by key and are immutable. |
| * |
| * @param <T> the document type |
| * @param collection the collection |
| * @param fromKey the start value (excluding) |
| * @param toKey the end value (excluding) |
| * @param limit the maximum number of entries to return (starting with the lowest key) |
| * @return the list (possibly empty) |
| * @throws DocumentStoreException if the operation failed. E.g. because of |
| * an I/O error. |
| */ |
| @NotNull |
| <T extends Document> List<T> query(Collection<T> collection, |
| String fromKey, |
| String toKey, |
| int limit) throws DocumentStoreException; |
| |
| /** |
| * Get a list of documents where the key is greater than a start value and |
| * less than an end value <em>and</em> the given "indexed property" is greater |
| * or equals the specified value. |
| * <p> |
| * The indexed property can either be a {@link Long} value, in which case numeric |
| * comparison applies, or a {@link Boolean} value, in which case "false" is mapped |
| * to "0" and "true" is mapped to "1". |
| * <p> |
| * The returned documents are sorted by key and are immutable. |
| * |
| * @param <T> the document type |
| * @param collection the collection |
| * @param fromKey the start value (excluding) |
| * @param toKey the end value (excluding) |
| * @param indexedProperty the name of the indexed property (optional) |
| * @param startValue the minimum value of the indexed property |
| * @param limit the maximum number of entries to return |
| * @return the list (possibly empty) |
| * @throws DocumentStoreException if the operation failed. E.g. because of |
| * an I/O error. |
| */ |
| @NotNull |
| <T extends Document> List<T> query(Collection<T> collection, |
| String fromKey, |
| String toKey, |
| String indexedProperty, |
| long startValue, |
| int limit) throws DocumentStoreException; |
| |
| /** |
| * Remove a document. This method does nothing if there is no document |
| * with the given key. |
| * <p> |
| * In case of a {@code 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. |
| * |
| * @param <T> the document type |
| * @param collection the collection |
| * @param key the key |
| * @throws DocumentStoreException if the operation failed. E.g. because of |
| * an I/O error. |
| */ |
| <T extends Document> void remove(Collection<T> collection, String key) |
| throws DocumentStoreException; |
| |
| /** |
| * Batch 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 by {@code keys} may have been |
| * removed. |
| * <p> |
| * In case of a {@code 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. |
| * |
| * @param <T> the document type |
| * @param collection the collection |
| * @param keys list of keys |
| * @throws DocumentStoreException if the operation failed. E.g. because of |
| * an I/O error. |
| */ |
| <T extends Document> void remove(Collection<T> collection, List<String> keys) |
| throws DocumentStoreException; |
| |
| /** |
| * Batch remove documents with given keys and corresponding equal conditions |
| * on {@link NodeDocument#MODIFIED_IN_SECS} values. Keys for documents that |
| * do not exist are simply ignored. A document is only removed if the |
| * corresponding condition is met. |
| * <p> |
| * In case of a {@code 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. |
| * |
| * @param <T> |
| * the document type |
| * @param collection |
| * the collection. |
| * @param toRemove |
| * the keys of the documents to remove with the corresponding |
| * timestamps. |
| * @return the number of removed documents. |
| * @throws DocumentStoreException |
| * if the operation failed. E.g. because of an I/O error. |
| */ |
| <T extends Document> int remove(Collection<T> collection, Map<String, Long> toRemove) |
| throws DocumentStoreException; |
| |
| |
| /** |
| * Batch remove documents where the given "indexed property" is within the given |
| * range (exclusive) - {@code (startValue, endValue)}. |
| * <p> |
| * The indexed property is a {@link Long} value and numeric comparison applies. |
| * <p> |
| * In case of a {@code 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. |
| * |
| * @param <T> the document type |
| * @param collection the collection. |
| * @param indexedProperty the name of the indexed property |
| * @param startValue the minimum value of the indexed property (exclusive) |
| * @param endValue the maximum value of the indexed property (exclusive) |
| * @return the number of removed documents. |
| * @throws DocumentStoreException if the operation failed. E.g. because of |
| * an I/O error. |
| */ |
| <T extends Document> int remove(Collection<T> collection, |
| String indexedProperty, long startValue, long endValue) |
| throws DocumentStoreException; |
| |
| /** |
| * Try to create a list of documents. This method returns {@code true} iff |
| * none of the documents existed before and the create was successful. This |
| * method will return {@code false} if 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 the {@code updateOps}. It is the responsibility of |
| * the caller to check, which documents were created and take appropriate |
| * action. The same is true when this method throws |
| * {@code DocumentStoreException} (e.g. when a communication error occurs). |
| * In this case only some documents may have been created. |
| * |
| * @param <T> the document type |
| * @param collection the collection |
| * @param updateOps the list of documents to add (where {@link Condition}s are not allowed) |
| * @return true if this worked (if none of the documents already existed) |
| * @throws IllegalArgumentException when at least one of the {@linkplain UpdateOp}s is conditional |
| * @throws DocumentStoreException if the operation failed. E.g. because of |
| * an I/O error. |
| */ |
| <T extends Document> boolean create(Collection<T> collection, |
| List<UpdateOp> updateOps) |
| throws IllegalArgumentException, DocumentStoreException; |
| |
| /** |
| * 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 (see {@link UpdateOp#isNew()}). The returned |
| * document is immutable. |
| * <p> |
| * If this method fails with a {@code 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 calling |
| * {@link #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. |
| * |
| * @param <T> |
| * the document type |
| * @param collection |
| * the collection |
| * @param update |
| * the update operation (where {@link Condition}s are not |
| * allowed) |
| * @return the old document or {@code null} if it either didn't exist |
| * before, or the {@linkplain UpdateOp} required the document to be |
| * present but {@link UpdateOp#isNew()} was {@code false}. |
| * @throws IllegalArgumentException |
| * when the {@linkplain UpdateOp} is conditional |
| * @throws DocumentStoreException |
| * if the operation failed. E.g. because of an I/O error. |
| */ |
| @Nullable |
| <T extends Document> T createOrUpdate(Collection<T> collection, |
| UpdateOp update) |
| throws IllegalArgumentException, DocumentStoreException; |
| |
| /** |
| * Create or unconditionally update a number of documents. An implementation |
| * does not have to guarantee that all changes are applied atomically, |
| * together. |
| * <p> |
| * In case of a {@code 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 {@linkplain UpdateOp}s |
| * 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. |
| * |
| * @param <T> the document type |
| * @param collection the collection |
| * @param updateOps the update operation list |
| * @return the list containing old documents or <code>null</code> values if they didn't exist |
| * before (see {@linkplain #createOrUpdate(Collection, UpdateOp)}), where the order |
| * reflects the order in the "updateOps" parameter |
| * @throws DocumentStoreException if the operation failed. E.g. because of |
| * an I/O error. |
| */ |
| <T extends Document> List<T> createOrUpdate(Collection<T> collection, |
| List<UpdateOp> updateOps) |
| throws DocumentStoreException; |
| |
| /** |
| * Performs a conditional update (e.g. using |
| * {@link UpdateOp.Condition.Type#EXISTS} and only updates the |
| * document if the condition is <code>true</code>. The returned document is |
| * immutable. |
| * <p> |
| * In case of a {@code 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. |
| * |
| * @param <T> the document type |
| * @param collection the collection |
| * @param update the update operation with the condition |
| * @return the old document or <code>null</code> if the condition is not met or |
| * if the document wasn't found |
| * @throws DocumentStoreException if the operation failed. E.g. because of |
| * an I/O error. |
| */ |
| @Nullable |
| <T extends Document> T findAndUpdate(Collection<T> collection, |
| UpdateOp update) |
| throws DocumentStoreException; |
| |
| /** |
| * Invalidate 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 if {@link #getIfCached(Collection, String)} |
| * returns a non-null value for a key. |
| * <p> |
| * 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 {@link #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 to {@link #find(Collection, String)} |
| * must guarantee the returned document reflects all the changes done up to |
| * when {@code invalidateCache()} was called. |
| * <p> |
| * In some implementations this method can be a NOP because documents can |
| * only be modified through a single instance of a {@code DocumentStore}. |
| * |
| * @return cache invalidation statistics or {@code null} if none are |
| * available. |
| */ |
| @Nullable |
| CacheInvalidationStats invalidateCache(); |
| |
| /** |
| * Invalidate the document cache but only with entries that match one |
| * of the keys provided. |
| * |
| * See {@link #invalidateCache()} for the general contract of cache |
| * invalidation. |
| * |
| * @param keys the keys of the documents to invalidate. |
| * @return cache invalidation statistics or {@code null} if none are |
| * available. |
| */ |
| @Nullable |
| CacheInvalidationStats invalidateCache(Iterable<String> keys); |
| |
| /** |
| * Invalidate the document cache for the given key. |
| * |
| * See {@link #invalidateCache()} for the general contract of cache |
| * invalidation. |
| * |
| * @param collection the collection |
| * @param key the key |
| */ |
| <T extends Document> void invalidateCache(Collection<T> collection, String key); |
| |
| /** |
| * Dispose this instance. |
| */ |
| void dispose(); |
| |
| /** |
| * Fetches the cached document. If the document is not present in the cache |
| * {@code null} will be returned. This method is consistent with other find |
| * methods that may return cached documents and will return {@code null} |
| * even when the implementation has a negative cache for documents that |
| * do not exist. This method will never return {@link NodeDocument#NULL}. |
| * |
| * @param <T> the document type |
| * @param collection the collection |
| * @param key the key |
| * @return cached document if present. Otherwise {@code null}. |
| */ |
| @Nullable |
| <T extends Document> T getIfCached(Collection<T> collection, String key); |
| |
| /** |
| * Set the level of guarantee for read and write operations, if supported by this backend. |
| * |
| * @param readWriteMode the read/write mode |
| */ |
| void setReadWriteMode(String readWriteMode); |
| |
| /** |
| * @return status information about the cache |
| */ |
| @Nullable |
| Iterable<CacheStats> getCacheStats(); |
| |
| /** |
| * @return description of the underlying storage. |
| */ |
| Map<String, String> getMetadata(); |
| |
| /** |
| * Returns statistics about the underlying storage. The information and |
| * keys returned by this method are implementation specific, may change |
| * between releases or may even depend on deployment aspects. E.g. depending |
| * on access rights, the method may return more or less information from |
| * the underlying store. This method should only be used for informational |
| * or debug purposes. |
| * |
| * @return statistics about this document store. |
| */ |
| @NotNull |
| Map<String, String> getStats(); |
| |
| /** |
| * @return 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). |
| * @throws UnsupportedOperationException if this DocumentStore does not |
| * support this method |
| * @throws DocumentStoreException if an I/O error occurs. |
| */ |
| long determineServerTimeDifferenceMillis() |
| throws UnsupportedOperationException, DocumentStoreException; |
| } |