blob: 61de09431caf1cd6eb7f3ac80fdbce30192b2a9b [file] [log] [blame]
/*
* 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.util;
import java.util.List;
import java.util.Map;
import org.apache.jackrabbit.oak.cache.CacheStats;
import org.apache.jackrabbit.oak.plugins.document.ClusterNodeInfo;
import org.apache.jackrabbit.oak.plugins.document.Collection;
import org.apache.jackrabbit.oak.plugins.document.Document;
import org.apache.jackrabbit.oak.plugins.document.DocumentStore;
import org.apache.jackrabbit.oak.plugins.document.DocumentStoreException;
import org.apache.jackrabbit.oak.plugins.document.UpdateOp;
import org.apache.jackrabbit.oak.plugins.document.cache.CacheInvalidationStats;
import org.jetbrains.annotations.NotNull;
/**
* Wrapper of another DocumentStore that does a lease check on any method
* invocation (read or update) and fails if the lease is not valid.
* <p>
* @see "https://issues.apache.org/jira/browse/OAK-2739 for more details"
*/
public final class LeaseCheckDocumentStoreWrapper implements DocumentStore {
private final DocumentStore delegate;
private final ClusterNodeInfo clusterNodeInfo;
public LeaseCheckDocumentStoreWrapper(final DocumentStore delegate, final ClusterNodeInfo clusterNodeInfo) {
if (delegate == null) {
throw new IllegalArgumentException("delegate must not be null");
}
this.delegate = delegate;
// clusterNodeInfo is allowed to be null - eg for testing
this.clusterNodeInfo = clusterNodeInfo;
}
private final void performLeaseCheck() {
if (clusterNodeInfo != null) {
clusterNodeInfo.performLeaseCheck();
}
}
@Override
public final <T extends Document> T find(Collection<T> collection, String key) {
performLeaseCheck();
return delegate.find(collection, key);
}
@Override
public final <T extends Document> T find(Collection<T> collection, String key,
int maxCacheAge) {
performLeaseCheck();
return delegate.find(collection, key, maxCacheAge);
}
@Override
public final <T extends Document> List<T> query(Collection<T> collection,
String fromKey, String toKey, int limit) {
performLeaseCheck();
return delegate.query(collection, fromKey, toKey, limit);
}
@Override
public final <T extends Document> List<T> query(Collection<T> collection,
String fromKey, String toKey, String indexedProperty,
long startValue, int limit) {
performLeaseCheck();
return delegate.query(collection, fromKey, toKey, indexedProperty, startValue, limit);
}
@Override
public final <T extends Document> void remove(Collection<T> collection, String key) {
performLeaseCheck();
delegate.remove(collection, key);
}
@Override
public final <T extends Document> void remove(Collection<T> collection,
List<String> keys) {
performLeaseCheck();
delegate.remove(collection, keys);
}
@Override
public final <T extends Document> int remove(Collection<T> collection,
Map<String, Long> toRemove) {
performLeaseCheck();
return delegate.remove(collection, toRemove);
}
@Override
public<T extends Document> int remove(Collection<T> collection,
String indexedProperty, long startValue, long endValue)
throws DocumentStoreException {
performLeaseCheck();
return delegate.remove(collection, indexedProperty, startValue, endValue);
}
@Override
public final <T extends Document> boolean create(Collection<T> collection,
List<UpdateOp> updateOps) {
performLeaseCheck();
return delegate.create(collection, updateOps);
}
@Override
public final <T extends Document> T createOrUpdate(Collection<T> collection,
UpdateOp update) {
performLeaseCheck();
return delegate.createOrUpdate(collection, update);
}
@Override
public <T extends Document> List<T> createOrUpdate(Collection<T> collection,
List<UpdateOp> updateOps) {
performLeaseCheck();
return delegate.createOrUpdate(collection, updateOps);
}
@Override
public final <T extends Document> T findAndUpdate(Collection<T> collection,
UpdateOp update) {
performLeaseCheck();
return delegate.findAndUpdate(collection, update);
}
@Override
public final CacheInvalidationStats invalidateCache() {
performLeaseCheck();
return delegate.invalidateCache();
}
@Override
public final CacheInvalidationStats invalidateCache(Iterable<String> keys) {
performLeaseCheck();
return delegate.invalidateCache(keys);
}
@Override
public final <T extends Document> void invalidateCache(Collection<T> collection,
String key) {
performLeaseCheck();
delegate.invalidateCache(collection, key);
}
@Override
public final void dispose() {
// this is debatable whether or not a lease check should be done on dispose.
// I'd say the lease must still be valid as on dispose there could be
// stuff written to the document store which should only be done
// when the lease is valid.
// however.. dispose() is also called as a result of the 'failed lease check stopping'
// mechanism - and in that case this would just throw an exception and the
// DocumentNodeStore.dispose() would not correctly finish.
// so: let's let the dispose ignore the lease state
delegate.dispose();
}
@Override
public final <T extends Document> T getIfCached(Collection<T> collection,
String key) {
performLeaseCheck();
return delegate.getIfCached(collection, key);
}
@Override
public final void setReadWriteMode(String readWriteMode) {
performLeaseCheck();
delegate.setReadWriteMode(readWriteMode);
}
@Override
public final Iterable<CacheStats> getCacheStats() {
performLeaseCheck();
return delegate.getCacheStats();
}
@Override
public final Map<String, String> getMetadata() {
performLeaseCheck();
return delegate.getMetadata();
}
@NotNull
@Override
public Map<String, String> getStats() {
performLeaseCheck();
return delegate.getStats();
}
@Override
public long determineServerTimeDifferenceMillis() {
performLeaseCheck();
return delegate.determineServerTimeDifferenceMillis();
}
}