You are viewing a plain text version of this content. The canonical link for it is here.
Posted to oak-commits@jackrabbit.apache.org by am...@apache.org on 2016/10/24 04:51:47 UTC
svn commit: r1766339 - in /jackrabbit/oak/trunk:
oak-core/src/main/java/org/apache/jackrabbit/oak/api/jmx/
oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/blob/
oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/blob/
oak-it/src/test/jav...
Author: amitj
Date: Mon Oct 24 04:51:47 2016
New Revision: 1766339
URL: http://svn.apache.org/viewvc?rev=1766339&view=rev
Log:
OAK-4870: Implement caching for S3DataStore
- Consolidated cache stats including download and staging cache
- OSGi component registration and tests
Added:
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/api/jmx/ConsolidatedDataStoreCacheStatsMBean.java (with props)
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/blob/ConsolidatedDataStoreCacheStats.java (with props)
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/blob/ConsolidatedDataStoreStatsTest.java (with props)
jackrabbit/oak/trunk/oak-it/src/test/java/org/apache/jackrabbit/oak/plugins/document/DocumentCachingDataStoreStatsTest.java (with props)
jackrabbit/oak/trunk/oak-it/src/test/java/org/apache/jackrabbit/oak/plugins/segment/SegmentCachingDataStoreStatsTest.java (with props)
jackrabbit/oak/trunk/oak-it/src/test/java/org/apache/jackrabbit/oak/segment/SegmentCachingDataStoreStatsTest.java (with props)
Added: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/api/jmx/ConsolidatedDataStoreCacheStatsMBean.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/api/jmx/ConsolidatedDataStoreCacheStatsMBean.java?rev=1766339&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/api/jmx/ConsolidatedDataStoreCacheStatsMBean.java (added)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/api/jmx/ConsolidatedDataStoreCacheStatsMBean.java Mon Oct 24 04:51:47 2016
@@ -0,0 +1,38 @@
+/*
+ * 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.api.jmx;
+
+import javax.management.openmbean.TabularData;
+
+public interface ConsolidatedDataStoreCacheStatsMBean {
+ String TYPE = "ConsolidatedDataStoreCacheStats";
+
+ TabularData getCacheStats();
+
+ /**
+ * Determines whether a file-like entity with the given name
+ * has been "synced" (completely copied) to S3.
+ *
+ * @param nodePathName - Path to the entity to check. This is
+ * the repository node path, not an external file path.
+ * @return true if the file is synced to S3.
+ */
+ boolean isFileSynced(final String nodePathName);
+}
Propchange: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/api/jmx/ConsolidatedDataStoreCacheStatsMBean.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/blob/ConsolidatedDataStoreCacheStats.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/blob/ConsolidatedDataStoreCacheStats.java?rev=1766339&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/blob/ConsolidatedDataStoreCacheStats.java (added)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/blob/ConsolidatedDataStoreCacheStats.java Mon Oct 24 04:51:47 2016
@@ -0,0 +1,307 @@
+/*
+ * 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.blob;
+
+import java.math.BigDecimal;
+import java.math.MathContext;
+import java.util.List;
+import java.util.concurrent.TimeUnit;
+
+import javax.management.openmbean.CompositeDataSupport;
+import javax.management.openmbean.CompositeType;
+import javax.management.openmbean.OpenDataException;
+import javax.management.openmbean.OpenType;
+import javax.management.openmbean.SimpleType;
+import javax.management.openmbean.TabularData;
+import javax.management.openmbean.TabularDataSupport;
+import javax.management.openmbean.TabularType;
+
+import com.google.common.base.Strings;
+import org.apache.felix.scr.annotations.Activate;
+import org.apache.felix.scr.annotations.Component;
+import org.apache.felix.scr.annotations.Deactivate;
+import org.apache.felix.scr.annotations.Reference;
+import org.apache.jackrabbit.core.data.DataIdentifier;
+import org.apache.jackrabbit.oak.api.Blob;
+import org.apache.jackrabbit.oak.api.PropertyState;
+import org.apache.jackrabbit.oak.api.Type;
+import org.apache.jackrabbit.oak.api.jmx.CacheStatsMBean;
+import org.apache.jackrabbit.oak.api.jmx.ConsolidatedDataStoreCacheStatsMBean;
+import org.apache.jackrabbit.oak.commons.PathUtils;
+import org.apache.jackrabbit.oak.osgi.OsgiWhiteboard;
+import org.apache.jackrabbit.oak.plugins.blob.datastore.DataStoreBlobStore;
+import org.apache.jackrabbit.oak.plugins.blob.datastore.InMemoryDataRecord;
+import org.apache.jackrabbit.oak.spi.state.NodeState;
+import org.apache.jackrabbit.oak.spi.state.NodeStore;
+import org.apache.jackrabbit.oak.spi.whiteboard.Registration;
+import org.apache.jackrabbit.oak.spi.whiteboard.Whiteboard;
+import org.osgi.framework.BundleContext;
+
+import static com.google.common.collect.Lists.newArrayList;
+import static org.apache.jackrabbit.oak.commons.IOUtils.humanReadableByteCount;
+import static org.apache.jackrabbit.oak.spi.whiteboard.WhiteboardUtils.registerMBean;
+
+/**
+ * Stats for caching data store.
+ */
+@Component
+public class ConsolidatedDataStoreCacheStats implements ConsolidatedDataStoreCacheStatsMBean {
+
+ private final List<Registration> registrations = newArrayList();
+
+ private final List<DataStoreCacheStatsMBean> cacheStats = newArrayList();
+
+ @Reference public AbstractSharedCachingDataStore cachingDataStore;
+
+ @Reference public NodeStore nodeStore;
+
+ @Override
+ public TabularData getCacheStats() {
+ TabularDataSupport tds;
+ try {
+ TabularType tt = new TabularType(CacheStatsData.class.getName(),
+ "Consolidated DataStore Cache Stats", CacheStatsData.TYPE, new String[]{"name"});
+ tds = new TabularDataSupport(tt);
+ for(DataStoreCacheStatsMBean stats : cacheStats){
+ tds.put(new CacheStatsData(stats).toCompositeData());
+ }
+ } catch (OpenDataException e) {
+ throw new IllegalStateException(e);
+ }
+ return tds;
+ }
+
+ @Activate
+ private void activate(BundleContext context){
+ Whiteboard wb = new OsgiWhiteboard(context);
+ List<DataStoreCacheStatsMBean> allStats = cachingDataStore.getStats();
+ for (DataStoreCacheStatsMBean stat : allStats) {
+ registrations.add(
+ registerMBean(wb, CacheStatsMBean.class, stat, CacheStatsMBean.TYPE,
+ stat.getName()));
+ cacheStats.add(stat);
+ }
+ registrations.add(
+ registerMBean(wb, ConsolidatedDataStoreCacheStatsMBean.class, this,
+ ConsolidatedDataStoreCacheStatsMBean.TYPE,
+ "Consolidated DataStore Cache statistics"));
+ }
+
+ @Deactivate
+ private void deactivate(){
+ for (Registration r : registrations) {
+ r.unregister();
+ }
+ registrations.clear();
+ }
+
+ /**
+ * Determines whether a file-like entity with the given name
+ * has been "synced" (completely copied) to S3.
+ *
+ * Determination of "synced":
+ * - A nodeName of null or "" is always "not synced".
+ * - A nodeName that does not map to a valid node is always "not synced".
+ * - If the node for this nodeName does not have a binary property,
+ * this node is always "not synced" since such a node would never be
+ * copied to S3.
+ * - If the node for this nodeName is not in the nodeStore, this node is
+ * always "not synced".
+ * - Otherwise, the state is "synced" if the corresponding blob is
+ * completely stored in S3.
+ *
+ * @param nodePathName - Path to the entity to check. This is
+ * a node path, not an external file path.
+ * @return true if the file is synced to S3.
+ */
+ @Override
+ public boolean isFileSynced(final String nodePathName) {
+ if (Strings.isNullOrEmpty(nodePathName)) {
+ return false;
+ }
+
+ if (null == nodeStore) {
+ return false;
+ }
+
+ final NodeState leafNode = findLeafNode(nodePathName);
+ if (!leafNode.exists()) {
+ return false;
+ }
+
+ boolean nodeHasBinaryProperties = false;
+ for (final PropertyState propertyState : leafNode.getProperties()) {
+ nodeHasBinaryProperties |= (propertyState.getType() == Type.BINARY || propertyState.getType() == Type.BINARIES);
+ try {
+ if (propertyState.getType() == Type.BINARY) {
+ final Blob blob = (Blob) propertyState.getValue(propertyState.getType());
+ if (null == blob || !haveRecordForBlob(blob)) {
+ return false;
+ }
+ } else if (propertyState.getType() == Type.BINARIES) {
+ final List<Blob> blobs = (List<Blob>) propertyState.getValue(propertyState.getType());
+ if (null == blobs) {
+ return false;
+ }
+ for (final Blob blob : blobs) {
+ if (!haveRecordForBlob(blob)) {
+ return false;
+ }
+ }
+ }
+ }
+ catch (ClassCastException e) {
+ return false;
+ }
+ }
+
+ // If we got here and nodeHasBinaryProperties is true,
+ // it means at least one binary property was found for
+ // the leaf node and that we were able to locate a
+ // records for binaries found.
+ return nodeHasBinaryProperties;
+ }
+
+ private NodeState findLeafNode(final String nodePathName) {
+ final Iterable<String> pathNodes = PathUtils.elements(PathUtils.getParentPath(nodePathName));
+ final String leafNodeName = PathUtils.getName(nodePathName);
+
+ NodeState currentNode = nodeStore.getRoot();
+ for (String pathNodeName : pathNodes) {
+ if (pathNodeName.length() > 0) {
+ NodeState childNode = currentNode.getChildNode(pathNodeName);
+ if (!childNode.exists()) {
+ break;
+ }
+ currentNode = childNode;
+ }
+ }
+ return currentNode.getChildNode(leafNodeName);
+ }
+
+ private boolean haveRecordForBlob(final Blob blob) {
+ final String fullBlobId = blob.getContentIdentity();
+ if (!Strings.isNullOrEmpty(fullBlobId)
+ && !InMemoryDataRecord.isInstance(fullBlobId)) {
+ String blobId = DataStoreBlobStore.BlobId.of(fullBlobId).getBlobId();
+ return cachingDataStore.exists(new DataIdentifier(blobId));
+ }
+ return false;
+ }
+
+ private static class CacheStatsData {
+ static final String[] FIELD_NAMES = new String[]{
+ "name",
+ "requestCount",
+ "hitCount",
+ "hitRate",
+ "missCount",
+ "missRate",
+ "loadCount",
+ "loadSuccessCount",
+ "loadExceptionCount",
+ "totalLoadTime",
+ "averageLoadPenalty",
+ "evictionCount",
+ "elementCount",
+ "totalWeight",
+ "totalMemWeight",
+ "maxWeight",
+ };
+
+ static final String[] FIELD_DESCRIPTIONS = FIELD_NAMES;
+
+ @SuppressWarnings("rawtypes")
+ static final OpenType[] FIELD_TYPES = new OpenType[]{
+ SimpleType.STRING,
+ SimpleType.LONG,
+ SimpleType.LONG,
+ SimpleType.BIGDECIMAL,
+ SimpleType.LONG,
+ SimpleType.BIGDECIMAL,
+ SimpleType.LONG,
+ SimpleType.LONG,
+ SimpleType.LONG,
+ SimpleType.STRING,
+ SimpleType.STRING,
+ SimpleType.LONG,
+ SimpleType.LONG,
+ SimpleType.STRING,
+ SimpleType.STRING,
+ SimpleType.STRING,
+ };
+
+ static final CompositeType TYPE = createCompositeType();
+
+ static CompositeType createCompositeType() {
+ try {
+ return new CompositeType(
+ CacheStatsData.class.getName(),
+ "Composite data type for Cache statistics",
+ CacheStatsData.FIELD_NAMES,
+ CacheStatsData.FIELD_DESCRIPTIONS,
+ CacheStatsData.FIELD_TYPES);
+ } catch (OpenDataException e) {
+ throw new IllegalStateException(e);
+ }
+ }
+
+ private final DataStoreCacheStatsMBean stats;
+
+ public CacheStatsData(DataStoreCacheStatsMBean stats){
+ this.stats = stats;
+ }
+
+ CompositeDataSupport toCompositeData() {
+ Object[] values = new Object[]{
+ stats.getName(),
+ stats.getRequestCount(),
+ stats.getHitCount(),
+ new BigDecimal(stats.getHitRate(),new MathContext(2)),
+ stats.getMissCount(),
+ new BigDecimal(stats.getMissRate(), new MathContext(2)),
+ stats.getLoadCount(),
+ stats.getLoadSuccessCount(),
+ stats.getLoadExceptionCount(),
+ timeInWords(stats.getTotalLoadTime()),
+ TimeUnit.NANOSECONDS.toMillis((long) stats.getAverageLoadPenalty()) + "ms",
+ stats.getEvictionCount(),
+ stats.getElementCount(),
+ humanReadableByteCount(stats.estimateCurrentWeight()),
+ humanReadableByteCount(stats.estimateCurrentMemoryWeight()),
+ humanReadableByteCount(stats.getMaxTotalWeight()),
+ };
+ try {
+ return new CompositeDataSupport(TYPE, FIELD_NAMES, values);
+ } catch (OpenDataException e) {
+ throw new IllegalStateException(e);
+ }
+ }
+ }
+
+ static String timeInWords(long nanos) {
+ long millis = TimeUnit.NANOSECONDS.toMillis(nanos);
+ return String.format("%d min, %d sec",
+ TimeUnit.MILLISECONDS.toMinutes(millis),
+ TimeUnit.MILLISECONDS.toSeconds(millis) -
+ TimeUnit.MINUTES.toSeconds(TimeUnit.MILLISECONDS.toMinutes(millis))
+ );
+ }
+}
Propchange: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/blob/ConsolidatedDataStoreCacheStats.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/blob/ConsolidatedDataStoreStatsTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/blob/ConsolidatedDataStoreStatsTest.java?rev=1766339&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/blob/ConsolidatedDataStoreStatsTest.java (added)
+++ jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/blob/ConsolidatedDataStoreStatsTest.java Mon Oct 24 04:51:47 2016
@@ -0,0 +1,504 @@
+/*
+ * 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.blob;
+
+import java.io.ByteArrayInputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.security.DigestOutputStream;
+import java.security.MessageDigest;
+import java.util.List;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.ScheduledFuture;
+import java.util.concurrent.TimeUnit;
+
+import com.google.common.base.Charsets;
+import com.google.common.base.Optional;
+import com.google.common.collect.Lists;
+import com.google.common.io.Closer;
+import org.apache.commons.io.IOUtils;
+import org.apache.commons.io.output.NullOutputStream;
+import org.apache.jackrabbit.core.data.DataRecord;
+import org.apache.jackrabbit.core.data.DataStoreException;
+import org.apache.jackrabbit.oak.api.Blob;
+import org.apache.jackrabbit.oak.api.CommitFailedException;
+import org.apache.jackrabbit.oak.commons.PathUtils;
+import org.apache.jackrabbit.oak.commons.concurrent.ExecutorCloser;
+import org.apache.jackrabbit.oak.plugins.memory.MemoryNodeStore;
+import org.apache.jackrabbit.oak.plugins.memory.MultiBinaryPropertyState;
+import org.apache.jackrabbit.oak.spi.blob.SharedBackend;
+import org.apache.jackrabbit.oak.spi.commit.CommitInfo;
+import org.apache.jackrabbit.oak.spi.commit.EmptyHook;
+import org.apache.jackrabbit.oak.spi.state.NodeBuilder;
+import org.apache.jackrabbit.oak.spi.state.NodeStore;
+import org.apache.jackrabbit.oak.stats.DefaultStatisticsProvider;
+import org.apache.jackrabbit.oak.stats.StatisticsProvider;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+import org.junit.rules.TemporaryFolder;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import static org.apache.commons.codec.binary.Hex.encodeHexString;
+import static org.apache.commons.io.FileUtils.copyInputStreamToFile;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+public class ConsolidatedDataStoreStatsTest extends AbstractDataStoreCacheTest {
+ private static final Logger LOG = LoggerFactory.getLogger(ConsolidatedDataStoreStatsTest.class);
+ private static final String ID_PREFIX = "12345";
+ private static String testNodePathName = "test/node/path/name";
+
+ @Rule
+ public TemporaryFolder folder = new TemporaryFolder(new File("target"));
+
+ @Rule
+ public ExpectedException expectedEx = ExpectedException.none();
+
+ private final Closer closer = Closer.create();
+ private File root;
+ private File testFile;
+
+ private CountDownLatch taskLatch;
+ private CountDownLatch callbackLatch;
+ private CountDownLatch afterExecuteLatch;
+ private TestExecutor executor;
+ private StatisticsProvider statsProvider;
+ private ScheduledExecutorService scheduledExecutor;
+ private ConsolidatedDataStoreCacheStats stats;
+ private NodeStore nodeStore;
+ private AbstractSharedCachingDataStore dataStore;
+ private static Blob mockBlob;
+
+ @Before
+ public void setup() throws Exception {
+ root = folder.newFolder();
+ init(1);
+ }
+
+ private void init(int i) throws Exception {
+ testFile = folder.newFile();
+ copyInputStreamToFile(randomStream(0, 16384), testFile);
+ String testNodeId = getIdForInputStream(new FileInputStream(testFile));
+ mockBlob = mock(Blob.class);
+ when(mockBlob.getContentIdentity()).thenReturn(testNodeId);
+
+ nodeStore = initNodeStore(Optional.of(mockBlob),
+ Optional.<Blob>absent(),
+ Optional.<String>absent(),
+ Optional.<Integer>absent(),
+ Optional.<List<Blob>>absent());
+
+ // create executor
+ taskLatch = new CountDownLatch(1);
+ callbackLatch = new CountDownLatch(1);
+ afterExecuteLatch = new CountDownLatch(i);
+ executor = new TestExecutor(1, taskLatch, callbackLatch, afterExecuteLatch);
+
+ // stats
+ ScheduledExecutorService statsExecutor = Executors.newSingleThreadScheduledExecutor();
+ closer.register(new ExecutorCloser(statsExecutor, 500, TimeUnit.MILLISECONDS));
+ statsProvider = new DefaultStatisticsProvider(statsExecutor);
+
+ scheduledExecutor = Executors.newSingleThreadScheduledExecutor();
+ closer.register(new ExecutorCloser(scheduledExecutor, 500, TimeUnit.MILLISECONDS));
+ dataStore = new AbstractSharedCachingDataStore() {
+ @Override protected SharedBackend createBackend() {
+ return new TestMemoryBackend();
+ }
+
+ @Override public int getMinRecordLength() {
+ return 0;
+ }
+ };
+ dataStore.setStatisticsProvider(statsProvider);
+ dataStore.listeningExecutor = executor;
+ dataStore.schedulerExecutor = scheduledExecutor;
+ dataStore.init(root.getAbsolutePath());
+
+ stats = new ConsolidatedDataStoreCacheStats();
+ stats.nodeStore = nodeStore;
+ stats.cachingDataStore = dataStore;
+ }
+
+ @After
+ public void tear() throws Exception {
+ closer.close();
+ dataStore.close();
+ }
+
+ private String getIdForInputStream(final InputStream in)
+ throws Exception {
+ MessageDigest digest = MessageDigest.getInstance("SHA-1");
+ OutputStream output = new DigestOutputStream(new NullOutputStream(), digest);
+ try {
+ IOUtils.copyLarge(in, output);
+ } finally {
+ IOUtils.closeQuietly(output);
+ IOUtils.closeQuietly(in);
+ }
+ return encodeHexString(digest.digest());
+ }
+
+ private static NodeStore initNodeStore(final Optional<Blob> blobProp1,
+ final Optional<Blob> blobProp2,
+ final Optional<String> stringProp,
+ final Optional<Integer> intProp,
+ final Optional<List<Blob>> blobPropList)
+ throws CommitFailedException {
+ final NodeStore nodeStore = new MemoryNodeStore();
+ NodeBuilder rootBuilder = nodeStore.getRoot().builder();
+ NodeBuilder builder = initNodeBuilder(rootBuilder);
+
+ if (blobProp1.isPresent()) {
+ builder.setProperty("blobProp1", blobProp1.get());
+ }
+ if (blobProp2.isPresent()) {
+ builder.setProperty("blobProp2", blobProp2.get());
+ }
+ if (stringProp.isPresent()) {
+ builder.setProperty("stringProp", stringProp.get());
+ }
+ if (intProp.isPresent()) {
+ builder.setProperty("intProp", intProp.get());
+ }
+ if (blobPropList.isPresent()) {
+ builder.setProperty(MultiBinaryPropertyState
+ .binaryPropertyFromBlob("blobPropList", blobPropList.get()));
+ }
+
+ nodeStore.merge(rootBuilder, EmptyHook.INSTANCE, CommitInfo.EMPTY);
+
+ return nodeStore;
+ }
+
+ private static NodeBuilder initNodeBuilder(final NodeBuilder rootBuilder) {
+ NodeBuilder builder = rootBuilder;
+ for (final String nodeName : PathUtils.elements(testNodePathName)) {
+ builder = builder.child(nodeName);
+ }
+ return builder;
+ }
+
+ @Test
+ public void noPath()
+ throws Exception {
+ assertFalse(stats.isFileSynced(testNodePathName));
+ }
+
+ @Test
+ public void nullString()
+ throws Exception {
+ assertFalse(stats.isFileSynced(null));
+ }
+
+ @Test
+ public void emptyString()
+ throws Exception {
+ assertFalse(stats.isFileSynced(""));
+ }
+
+ @Test
+ public void differentPaths() throws Exception {
+ init(4);
+ final NodeStore nodeStore = new MemoryNodeStore();
+ stats.nodeStore = nodeStore;
+
+ final String path1 = "path/to/node/1";
+ final String path2 = "path/to/node/2";
+ final String path3 = "shortpath";
+ final String path4 = "a/very/very/long/path/leads/to/node/4";
+ final List<String> paths = Lists.newArrayList(path1, path2, path3, path4);
+ final String leadingSlashPath = "/" + path1;
+
+ final List<String> blobContents = Lists.newArrayList("1", "2", "3", "4");
+ final List<Blob> blobs = Lists.newArrayList(
+ mock(Blob.class),
+ mock(Blob.class),
+ mock(Blob.class),
+ mock(Blob.class)
+ );
+ final List<String> blobIds = Lists.newArrayList(
+ getIdForInputStream(getStream(blobContents.get(0))),
+ getIdForInputStream(getStream(blobContents.get(1))),
+ getIdForInputStream(getStream(blobContents.get(2))),
+ getIdForInputStream(getStream(blobContents.get(3)))
+ );
+ when(blobs.get(0).getContentIdentity()).thenReturn(blobIds.get(0));
+ when(blobs.get(1).getContentIdentity()).thenReturn(blobIds.get(1));
+ when(blobs.get(2).getContentIdentity()).thenReturn(blobIds.get(2));
+ when(blobs.get(3).getContentIdentity()).thenReturn(blobIds.get(3));
+
+ final NodeBuilder rootBuilder = nodeStore.getRoot().builder();
+
+ final List<NodeBuilder> builders = Lists.newArrayList();
+ for (final String path : paths) {
+ NodeBuilder builder = rootBuilder;
+ for (final String nodeName : PathUtils.elements(path)) {
+ builder = builder.child(nodeName);
+ }
+ builders.add(builder);
+ }
+ builders.get(0).setProperty("blob1", blobs.get(0));
+ builders.get(1).setProperty("blob2", blobs.get(1));
+ builders.get(2).setProperty("blob3", blobs.get(2));
+ builders.get(3).setProperty("blob4", blobs.get(3));
+
+ nodeStore.merge(rootBuilder, EmptyHook.INSTANCE, CommitInfo.EMPTY);
+
+ final List<DataRecord> records = Lists.newArrayList();
+ try {
+ for (final String s : blobContents) {
+ records.add(dataStore.addRecord(getStream(s)));
+ }
+
+ taskLatch.countDown();
+ callbackLatch.countDown();
+ waitFinish();
+
+ for (final String path : Lists
+ .newArrayList(path1, path2, path3, path4, leadingSlashPath)) {
+ assertTrue(stats.isFileSynced(path));
+ }
+
+ for (final String invalidPath : Lists
+ .newArrayList(path1 + "/", "/" + path1 + "/", "/path//to/node///1")) {
+ try {
+ stats.isFileSynced(invalidPath);
+ assertFalse(false); // shouldn't get here on an invalid path
+ } catch (AssertionError e) {
+ // expected
+ }
+ }
+ }
+ finally {
+ delete(dataStore, records);
+ }
+ }
+
+ @Test
+ public void multiplePropertiesAndBinarySynced() throws Exception {
+ NodeStore nodeStore = initNodeStore(Optional.of(mockBlob),
+ Optional.<Blob>absent(),
+ Optional.of("abc"),
+ Optional.of(123),
+ Optional.<List<Blob>>absent());
+
+ assertSyncedTrue(stats, dataStore, new FileInputStream(testFile));
+ }
+
+ @Test
+ public void multipleBinaryPropsAllSynced() throws Exception {
+ Blob mockBlob2 = mock(Blob.class);
+ final String id2 = getIdForInputStream(getStream("testContents2"));
+ when(mockBlob2.getContentIdentity()).thenReturn(id2);
+ NodeStore nodeStore = initNodeStore(Optional.of(mockBlob),
+ Optional.of(mockBlob2),
+ Optional.<String>absent(),
+ Optional.<Integer>absent(),
+ Optional.<List<Blob>>absent());
+
+ assertSyncedTrue(stats, dataStore, new FileInputStream(testFile),
+ getStream("testContents2"));
+ }
+
+ @Test
+ public void multipleBinaryPropsNotAllSynced() throws Exception {
+ Blob mockBlob2 = mock(Blob.class);
+ final String id2 = getIdForInputStream(getStream("testContents2"));
+ when(mockBlob2.getContentIdentity()).thenReturn(id2);
+ NodeStore nodeStore = initNodeStore(Optional.of(mockBlob),
+ Optional.of(mockBlob2),
+ Optional.<String>absent(),
+ Optional.<Integer>absent(),
+ Optional.<List<Blob>>absent());
+
+ assertSyncedFalse(stats, dataStore, new FileInputStream(testFile));
+ }
+
+ @Test
+ public void binaryPropSingle() throws Exception {
+ List<Blob> blobPropList = Lists.newArrayList(mockBlob);
+ NodeStore nodeStore = initNodeStore(Optional.<Blob>absent(),
+ Optional.<Blob>absent(),
+ Optional.<String>absent(),
+ Optional.<Integer>absent(),
+ Optional.of(blobPropList));
+
+ assertSyncedTrue(stats, dataStore, new FileInputStream(testFile));
+ }
+
+ @Test
+ public void binariesPropertyMultiple() throws Exception {
+ Blob mockBlob2 = mock(Blob.class);
+ final String id2 = getIdForInputStream(getStream("testContents2"));
+ when(mockBlob2.getContentIdentity()).thenReturn(id2);
+ List<Blob> blobPropList = Lists.newArrayList(mockBlob, mockBlob2);
+ NodeStore nodeStore = initNodeStore(Optional.<Blob>absent(),
+ Optional.<Blob>absent(),
+ Optional.<String>absent(),
+ Optional.<Integer>absent(),
+ Optional.of(blobPropList));
+
+ assertSyncedTrue(stats, dataStore, new FileInputStream(testFile),
+ getStream("testContents2"));
+ }
+
+ @Test
+ public void binariesPropertyNotAllSynced() throws Exception {
+ Blob mockBlob2 = mock(Blob.class);
+ final String id2 = getIdForInputStream(getStream("testContents2"));
+ when(mockBlob2.getContentIdentity()).thenReturn(id2);
+ List<Blob> blobPropList = Lists.newArrayList(mockBlob, mockBlob2);
+ NodeStore nodeStore = initNodeStore(Optional.<Blob>absent(),
+ Optional.<Blob>absent(),
+ Optional.<String>absent(),
+ Optional.<Integer>absent(),
+ Optional.of(blobPropList));
+
+ assertSyncedFalse(stats, dataStore, new FileInputStream(testFile));
+ }
+
+ @Test
+ public void binarySyncedAndBinariesNotSynced() throws Exception {
+ Blob mockBlob2 = mock(Blob.class);
+ final String id2 = getIdForInputStream(getStream("testContents2"));
+ when(mockBlob2.getContentIdentity()).thenReturn(id2);
+ Blob mockBlob3 = mock(Blob.class);
+ final String id3 = getIdForInputStream(getStream("testContents3"));
+ when(mockBlob2.getContentIdentity()).thenReturn(id3);
+ List<Blob> blobPropList = Lists.newArrayList(mockBlob2, mockBlob3);
+ NodeStore nodeStore = initNodeStore(Optional.of(mockBlob),
+ Optional.<Blob>absent(),
+ Optional.<String>absent(),
+ Optional.<Integer>absent(),
+ Optional.of(blobPropList));
+
+ assertSyncedFalse(stats, dataStore, new FileInputStream(testFile),
+ getStream("testContents2"));
+ }
+
+ @Test
+ public void binaryNotSyncedAndBinariesSynced() throws Exception {
+ Blob mockBlob2 = mock(Blob.class);
+ final String id2 = getIdForInputStream(getStream("testContents2"));
+ when(mockBlob2.getContentIdentity()).thenReturn(id2);
+ Blob mockBlob3 = mock(Blob.class);
+ final String id3 = getIdForInputStream(getStream("testContents3"));
+ when(mockBlob2.getContentIdentity()).thenReturn(id3);
+ List<Blob> blobPropList = Lists.newArrayList(mockBlob2, mockBlob3);
+ NodeStore nodeStore = initNodeStore(Optional.of(mockBlob),
+ Optional.<Blob>absent(),
+ Optional.<String>absent(),
+ Optional.<Integer>absent(),
+ Optional.of(blobPropList));
+ assertSyncedFalse(stats, dataStore, getStream("testContents2"),
+ getStream("testContents3"));
+ }
+
+ @Test
+ public void binaryAndBinariesSynced() throws Exception {
+ Blob mockBlob2 = mock(Blob.class);
+ final String id2 = getIdForInputStream(getStream("testContents2"));
+ when(mockBlob2.getContentIdentity()).thenReturn(id2);
+ Blob mockBlob3 = mock(Blob.class);
+ final String id3 = getIdForInputStream(getStream("testContents3"));
+ when(mockBlob3.getContentIdentity()).thenReturn(id3);
+ List<Blob> blobPropList = Lists.newArrayList(mockBlob2, mockBlob3);
+ NodeStore nodeStore = initNodeStore(Optional.of(mockBlob),
+ Optional.<Blob>absent(),
+ Optional.<String>absent(),
+ Optional.<Integer>absent(),
+ Optional.of(blobPropList));
+
+ assertSyncedFalse(stats, dataStore, new FileInputStream(testFile),
+ getStream("testContents2"), getStream("testContents3"));
+ }
+
+ private static void delete(AbstractSharedCachingDataStore s3ds, List<DataRecord> recs)
+ throws DataStoreException {
+ for (DataRecord rec : recs) {
+ if (null != rec) {
+ s3ds.deleteRecord(rec.getIdentifier());
+ }
+ }
+ }
+
+ private void assertSyncedFalse(ConsolidatedDataStoreCacheStats mBean,
+ AbstractSharedCachingDataStore s3ds, InputStream... streams) throws DataStoreException {
+
+ List<DataRecord> recs = Lists.newArrayList();
+ try {
+ for (InputStream is : streams) {
+ recs.add(s3ds.addRecord(is));
+ IOUtils.closeQuietly(is);
+ }
+ assertFalse(mBean.isFileSynced(testNodePathName));
+ taskLatch.countDown();
+ callbackLatch.countDown();
+ waitFinish();
+ } finally {
+ delete(s3ds, recs);
+ }
+ }
+
+ private void assertSyncedTrue(ConsolidatedDataStoreCacheStats mBean,
+ AbstractSharedCachingDataStore s3ds, InputStream... streams) throws DataStoreException {
+ taskLatch.countDown();
+ callbackLatch.countDown();
+
+ List<DataRecord> recs = Lists.newArrayList();
+ try {
+ for (InputStream is : streams) {
+ recs.add(s3ds.addRecord(is));
+ IOUtils.closeQuietly(is);
+ }
+ waitFinish();
+ assertTrue(mBean.isFileSynced(testNodePathName));
+ } finally {
+ delete(s3ds, recs);
+ }
+ }
+
+ private void waitFinish() {
+ try {
+ // wait for upload finish
+ afterExecuteLatch.await();
+ // Force execute removal from staging cache
+ ScheduledFuture<?> scheduledFuture = scheduledExecutor
+ .schedule(dataStore.getCache().getStagingCache().new RemoveJob(), 0,
+ TimeUnit.MILLISECONDS);
+ scheduledFuture.get();
+ LOG.info("After jobs completed");
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+ private static InputStream getStream(String str) {
+ return new ByteArrayInputStream(str.getBytes(Charsets.UTF_8));
+ }
+}
Propchange: jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/blob/ConsolidatedDataStoreStatsTest.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: jackrabbit/oak/trunk/oak-it/src/test/java/org/apache/jackrabbit/oak/plugins/document/DocumentCachingDataStoreStatsTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-it/src/test/java/org/apache/jackrabbit/oak/plugins/document/DocumentCachingDataStoreStatsTest.java?rev=1766339&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-it/src/test/java/org/apache/jackrabbit/oak/plugins/document/DocumentCachingDataStoreStatsTest.java (added)
+++ jackrabbit/oak/trunk/oak-it/src/test/java/org/apache/jackrabbit/oak/plugins/document/DocumentCachingDataStoreStatsTest.java Mon Oct 24 04:51:47 2016
@@ -0,0 +1,134 @@
+/*
+ * 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.Map;
+
+import org.apache.jackrabbit.oak.api.jmx.ConsolidatedDataStoreCacheStatsMBean;
+import org.apache.jackrabbit.oak.plugins.blob.AbstractSharedCachingDataStore;
+import org.apache.jackrabbit.oak.plugins.blob.ConsolidatedDataStoreCacheStats;
+import org.apache.jackrabbit.oak.spi.blob.BlobStore;
+import org.apache.jackrabbit.oak.spi.state.NodeStore;
+import org.apache.jackrabbit.oak.stats.StatisticsProvider;
+import org.apache.sling.testing.mock.osgi.ReferenceViolationException;
+import org.apache.sling.testing.mock.osgi.junit.OsgiContext;
+import org.junit.Assume;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+import org.osgi.framework.ServiceRegistration;
+
+import static com.google.common.collect.Maps.newHashMap;
+import static org.apache.sling.testing.mock.osgi.MockOsgi.deactivate;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.mockito.Mockito.mock;
+
+/**
+ * Tests the registration of the {@link ConsolidatedDataStoreCacheStatsMBean}.
+ */
+public class DocumentCachingDataStoreStatsTest {
+
+ @Rule
+ public OsgiContext context = new OsgiContext();
+
+ @Rule
+ public ExpectedException expectedEx = ExpectedException.none();
+
+ @BeforeClass
+ public static void checkMongoDbAvailable() {
+ Assume.assumeTrue(MongoUtils.isAvailable());
+ }
+
+ @Before
+ public void setUp() {
+ context.registerService(StatisticsProvider.class, StatisticsProvider.NOOP);
+ }
+
+ @Test
+ public void testUseCachingBlobStore() {
+ ServiceRegistration delegateReg =
+ context.bundleContext().registerService(AbstractSharedCachingDataStore.class.getName(),
+ mock(AbstractSharedCachingDataStore.class), null);
+ assertNotNull(context.getService(AbstractSharedCachingDataStore.class));
+ registerBlobStore();
+
+ registerDocumentNodeStoreService(true);
+ assertServiceActivated();
+
+ ConsolidatedDataStoreCacheStats dataStoreStats =
+ context.registerInjectActivateService(new ConsolidatedDataStoreCacheStats(), null);
+ assertNotNull(context.getService(ConsolidatedDataStoreCacheStatsMBean.class));
+
+ deactivate(dataStoreStats);
+ unregisterDocumentNodeStoreService();
+ unregisterBlobStore();
+ delegateReg.unregister();
+ }
+
+ @Test
+ public void testNoCachingBlobStore() {
+ expectedEx.expect(ReferenceViolationException.class);
+
+ registerBlobStore();
+
+ registerDocumentNodeStoreService(true);
+ assertServiceActivated();
+
+ ConsolidatedDataStoreCacheStats dataStoreStats =
+ context.registerInjectActivateService(new ConsolidatedDataStoreCacheStats(), null);
+ assertNull(context.getService(ConsolidatedDataStoreCacheStatsMBean.class));
+
+ unregisterDocumentNodeStoreService();
+ unregisterBlobStore();
+ }
+
+ private DocumentNodeStoreService documentNodeStoreService;
+
+ private void registerDocumentNodeStoreService(boolean customBlobStore) {
+ Map<String, Object> properties = newHashMap();
+
+ properties.put("mongouri", MongoUtils.URL);
+ properties.put("db", MongoUtils.DB);
+ properties.put(DocumentNodeStoreService.CUSTOM_BLOB_STORE, customBlobStore);
+ documentNodeStoreService =
+ context.registerInjectActivateService(new DocumentNodeStoreService(), properties);
+ }
+
+ private void unregisterDocumentNodeStoreService() {
+ deactivate(documentNodeStoreService);
+ }
+
+ private ServiceRegistration blobStore;
+
+ private void registerBlobStore() {
+ blobStore = context.bundleContext()
+ .registerService(BlobStore.class.getName(), mock(BlobStore.class), null);
+ }
+
+ private void unregisterBlobStore() {
+ blobStore.unregister();
+ }
+
+ private void assertServiceActivated() {
+ assertNotNull(context.getService(NodeStore.class));
+ }
+}
Propchange: jackrabbit/oak/trunk/oak-it/src/test/java/org/apache/jackrabbit/oak/plugins/document/DocumentCachingDataStoreStatsTest.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: jackrabbit/oak/trunk/oak-it/src/test/java/org/apache/jackrabbit/oak/plugins/segment/SegmentCachingDataStoreStatsTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-it/src/test/java/org/apache/jackrabbit/oak/plugins/segment/SegmentCachingDataStoreStatsTest.java?rev=1766339&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-it/src/test/java/org/apache/jackrabbit/oak/plugins/segment/SegmentCachingDataStoreStatsTest.java (added)
+++ jackrabbit/oak/trunk/oak-it/src/test/java/org/apache/jackrabbit/oak/plugins/segment/SegmentCachingDataStoreStatsTest.java Mon Oct 24 04:51:47 2016
@@ -0,0 +1,133 @@
+/*
+ * 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.segment;
+
+import java.io.File;
+import java.util.Map;
+
+import org.apache.jackrabbit.oak.api.jmx.ConsolidatedDataStoreCacheStatsMBean;
+import org.apache.jackrabbit.oak.plugins.blob.AbstractSharedCachingDataStore;
+import org.apache.jackrabbit.oak.plugins.blob.ConsolidatedDataStoreCacheStats;
+import org.apache.jackrabbit.oak.spi.blob.BlobStore;
+import org.apache.jackrabbit.oak.spi.state.NodeStore;
+import org.apache.jackrabbit.oak.stats.StatisticsProvider;
+import org.apache.sling.testing.mock.osgi.ReferenceViolationException;
+import org.apache.sling.testing.mock.osgi.junit.OsgiContext;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+import org.junit.rules.TemporaryFolder;
+import org.osgi.framework.ServiceRegistration;
+
+import static com.google.common.collect.Maps.newHashMap;
+import static org.apache.jackrabbit.oak.plugins.segment.SegmentNodeStoreService.CUSTOM_BLOB_STORE;
+import static org.apache.jackrabbit.oak.segment.SegmentNodeStoreService.DIRECTORY;
+import static org.apache.sling.testing.mock.osgi.MockOsgi.deactivate;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.mockito.Mockito.mock;
+
+/**
+ * Tests the registration of the {@link ConsolidatedDataStoreCacheStatsMBean}.
+ */
+public class SegmentCachingDataStoreStatsTest {
+
+ @Rule
+ public OsgiContext context = new OsgiContext();
+
+ @Rule
+ public TemporaryFolder folder = new TemporaryFolder(new File("target"));
+
+ @Rule
+ public ExpectedException expectedEx = ExpectedException.none();
+
+ @Before
+ public void setUp() {
+ context.registerService(StatisticsProvider.class, StatisticsProvider.NOOP);
+ }
+
+ @Test
+ public void testUseCachingBlobStore() {
+ ServiceRegistration delegateReg =
+ context.bundleContext().registerService(AbstractSharedCachingDataStore.class.getName(),
+ mock(AbstractSharedCachingDataStore.class), null);
+ assertNotNull(context.getService(AbstractSharedCachingDataStore.class));
+ registerBlobStore();
+
+ registerSegmentNodeStoreService(true);
+ assertServiceActivated();
+
+ ConsolidatedDataStoreCacheStats dataStoreStats =
+ context.registerInjectActivateService(new ConsolidatedDataStoreCacheStats(), null);
+ assertNotNull(context.getService(ConsolidatedDataStoreCacheStatsMBean.class));
+
+ deactivate(dataStoreStats);
+ unregisterSegmentNodeStoreService();
+ unregisterBlobStore();
+ delegateReg.unregister();
+ }
+
+ @Test
+ public void testNoCachingBlobStore() {
+ expectedEx.expect(ReferenceViolationException.class);
+
+ registerBlobStore();
+
+ registerSegmentNodeStoreService(true);
+ assertServiceActivated();
+
+ ConsolidatedDataStoreCacheStats dataStoreStats =
+ context.registerInjectActivateService(new ConsolidatedDataStoreCacheStats(), null);
+ assertNull(context.getService(ConsolidatedDataStoreCacheStatsMBean.class));
+
+ unregisterSegmentNodeStoreService();
+ unregisterBlobStore();
+ }
+
+ private SegmentNodeStoreService segmentNodeStoreService;
+
+ private void registerSegmentNodeStoreService(boolean customBlobStore) {
+ Map<String, Object> properties = newHashMap();
+
+ properties.put(CUSTOM_BLOB_STORE, customBlobStore);
+ properties.put(DIRECTORY, folder.getRoot().getAbsolutePath());
+
+ segmentNodeStoreService = context.registerInjectActivateService(new SegmentNodeStoreService(), properties);
+ }
+
+ private void unregisterSegmentNodeStoreService() {
+ deactivate(segmentNodeStoreService);
+ }
+
+ private ServiceRegistration blobStore;
+
+ private void registerBlobStore() {
+ blobStore = context.bundleContext().registerService(BlobStore.class.getName(), mock(BlobStore.class), null);
+ }
+
+ private void unregisterBlobStore() {
+ blobStore.unregister();
+ }
+
+ private void assertServiceActivated() {
+ assertNotNull(context.getService(NodeStore.class));
+ assertNotNull(context.getService(SegmentStoreProvider.class));
+ }
+}
Propchange: jackrabbit/oak/trunk/oak-it/src/test/java/org/apache/jackrabbit/oak/plugins/segment/SegmentCachingDataStoreStatsTest.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: jackrabbit/oak/trunk/oak-it/src/test/java/org/apache/jackrabbit/oak/segment/SegmentCachingDataStoreStatsTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-it/src/test/java/org/apache/jackrabbit/oak/segment/SegmentCachingDataStoreStatsTest.java?rev=1766339&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-it/src/test/java/org/apache/jackrabbit/oak/segment/SegmentCachingDataStoreStatsTest.java (added)
+++ jackrabbit/oak/trunk/oak-it/src/test/java/org/apache/jackrabbit/oak/segment/SegmentCachingDataStoreStatsTest.java Mon Oct 24 04:51:47 2016
@@ -0,0 +1,134 @@
+/*
+ * 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.segment;
+
+import java.io.File;
+import java.util.Map;
+
+import org.apache.jackrabbit.oak.api.jmx.ConsolidatedDataStoreCacheStatsMBean;
+import org.apache.jackrabbit.oak.plugins.blob.AbstractSharedCachingDataStore;
+import org.apache.jackrabbit.oak.plugins.blob.ConsolidatedDataStoreCacheStats;
+import org.apache.jackrabbit.oak.spi.blob.BlobStore;
+import org.apache.jackrabbit.oak.spi.state.NodeStore;
+import org.apache.jackrabbit.oak.stats.StatisticsProvider;
+import org.apache.sling.testing.mock.osgi.ReferenceViolationException;
+import org.apache.sling.testing.mock.osgi.junit.OsgiContext;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+import org.junit.rules.TemporaryFolder;
+import org.osgi.framework.ServiceRegistration;
+
+import static com.google.common.collect.Maps.newHashMap;
+import static org.apache.jackrabbit.oak.segment.SegmentNodeStoreService.CUSTOM_BLOB_STORE;
+import static org.apache.jackrabbit.oak.segment.SegmentNodeStoreService.DIRECTORY;
+import static org.apache.sling.testing.mock.osgi.MockOsgi.deactivate;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.mockito.Mockito.mock;
+
+/**
+ * Tests the registration of the {@link ConsolidatedDataStoreCacheStatsMBean}.
+ */
+public class SegmentCachingDataStoreStatsTest {
+
+ @Rule
+ public OsgiContext context = new OsgiContext();
+
+ @Rule
+ public TemporaryFolder folder = new TemporaryFolder(new File("target"));
+
+ @Rule
+ public ExpectedException expectedEx = ExpectedException.none();
+
+ @Before
+ public void setUp() {
+ context.registerService(StatisticsProvider.class, StatisticsProvider.NOOP);
+ }
+
+ @Test
+ public void testUseCachingBlobStore() {
+ ServiceRegistration delegateReg =
+ context.bundleContext().registerService(AbstractSharedCachingDataStore.class.getName(),
+ mock(AbstractSharedCachingDataStore.class), null);
+ assertNotNull(context.getService(AbstractSharedCachingDataStore.class));
+ registerBlobStore();
+
+ registerSegmentNodeStoreService(true);
+ assertServiceActivated();
+
+ ConsolidatedDataStoreCacheStats dataStoreStats =
+ context.registerInjectActivateService(new ConsolidatedDataStoreCacheStats(), null);
+ assertNotNull(context.getService(ConsolidatedDataStoreCacheStatsMBean.class));
+
+ deactivate(dataStoreStats);
+ unregisterSegmentNodeStoreService();
+ unregisterBlobStore();
+ delegateReg.unregister();
+ }
+
+ @Test
+ public void testNoCachingBlobStore() {
+ expectedEx.expect(ReferenceViolationException.class);
+
+ registerBlobStore();
+
+ registerSegmentNodeStoreService(true);
+ assertServiceActivated();
+
+ ConsolidatedDataStoreCacheStats dataStoreStats =
+ context.registerInjectActivateService(new ConsolidatedDataStoreCacheStats(), null);
+ assertNull(context.getService(ConsolidatedDataStoreCacheStatsMBean.class));
+
+ unregisterSegmentNodeStoreService();
+ unregisterBlobStore();
+ }
+
+ private SegmentNodeStoreService segmentNodeStoreService;
+
+ private void registerSegmentNodeStoreService(boolean customBlobStore) {
+ Map<String, Object> properties = newHashMap();
+
+ properties.put(CUSTOM_BLOB_STORE, customBlobStore);
+ properties.put(DIRECTORY, folder.getRoot().getAbsolutePath());
+
+ segmentNodeStoreService =
+ context.registerInjectActivateService(new SegmentNodeStoreService(), properties);
+ }
+
+ private void unregisterSegmentNodeStoreService() {
+ deactivate(segmentNodeStoreService);
+ }
+
+ private ServiceRegistration blobStore;
+
+ private void registerBlobStore() {
+ blobStore = context.bundleContext().registerService(BlobStore.class.getName(), mock(BlobStore.class), null);
+ }
+
+ private void unregisterBlobStore() {
+ blobStore.unregister();
+ }
+
+ private void assertServiceActivated() {
+ assertNotNull(context.getService(NodeStore.class));
+ assertNotNull(context.getService(SegmentStoreProvider.class));
+ }
+}
Propchange: jackrabbit/oak/trunk/oak-it/src/test/java/org/apache/jackrabbit/oak/segment/SegmentCachingDataStoreStatsTest.java
------------------------------------------------------------------------------
svn:eol-style = native