From a66c69ac7d87c5b7c90ad425a64202b40eb7f104 Mon Sep 17 00:00:00 2001 From: Axel Hanikel Date: Wed, 24 Oct 2018 12:48:59 +0200 Subject: [PATCH] OAK-7864 - Recording read operations to the segment store --- .../oak/segment/SegmentNodeStore.java | 19 +- .../segment/SegmentNodeStoreRegistrar.java | 12 +- .../oak/segment/tool/LoggingHook.java | 2 +- .../segment/tool/LoggingNodeStateWrapper.java | 189 ++++++++++++++++++ .../oak/segment/tool/NodeStateWrapper.java | 30 +++ 5 files changed, 247 insertions(+), 5 deletions(-) create mode 100644 oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/tool/LoggingNodeStateWrapper.java create mode 100644 oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/tool/NodeStateWrapper.java diff --git a/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/SegmentNodeStore.java b/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/SegmentNodeStore.java index 2cfb39bd69..4372ad37c4 100644 --- a/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/SegmentNodeStore.java +++ b/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/SegmentNodeStore.java @@ -30,6 +30,7 @@ import java.io.InputStream; import java.util.Collections; import java.util.Map; import java.util.function.Consumer; +import java.util.function.Function; import org.apache.jackrabbit.oak.api.Blob; import org.apache.jackrabbit.oak.api.CommitFailedException; @@ -39,6 +40,7 @@ import org.apache.jackrabbit.oak.segment.scheduler.Commit; import org.apache.jackrabbit.oak.segment.scheduler.LockBasedScheduler; import org.apache.jackrabbit.oak.segment.scheduler.Scheduler; import org.apache.jackrabbit.oak.segment.tool.LoggingHook; +import org.apache.jackrabbit.oak.segment.tool.NodeStateWrapper; import org.apache.jackrabbit.oak.spi.blob.BlobStore; import org.apache.jackrabbit.oak.spi.commit.CommitHook; import org.apache.jackrabbit.oak.spi.commit.CommitInfo; @@ -87,6 +89,8 @@ public class SegmentNodeStore implements NodeStore, Observable { private LoggingHook loggingHook; + private Function rootNodeStateWrapper; + private SegmentNodeStoreBuilder( @NotNull Revisions revisions, @NotNull SegmentReader reader, @@ -127,6 +131,12 @@ public class SegmentNodeStore implements NodeStore, Observable { return this; } + @NotNull + public SegmentNodeStoreBuilder withRootNodeStateWrapper(Function rootNodeStateWrapper) { + this.rootNodeStateWrapper = rootNodeStateWrapper; + return this; + } + @NotNull public SegmentNodeStore build() { checkState(!isCreated); @@ -175,6 +185,8 @@ public class SegmentNodeStore implements NodeStore, Observable { private final LoggingHook loggingHook; + private final Function rootNodeStateWrapper; + private SegmentNodeStore(SegmentNodeStoreBuilder builder) { this.writer = builder.writer; this.blobStore = builder.blobStore; @@ -183,6 +195,7 @@ public class SegmentNodeStore implements NodeStore, Observable { .dispatchChanges(builder.dispatchChanges) .build(); this.loggingHook = builder.loggingHook; + this.rootNodeStateWrapper = builder.rootNodeStateWrapper; } @Override @@ -196,7 +209,11 @@ public class SegmentNodeStore implements NodeStore, Observable { @Override @NotNull public NodeState getRoot() { - return scheduler.getHeadNodeState().getChildNode(ROOT); + final NodeState root = scheduler.getHeadNodeState().getChildNode(ROOT); + if (rootNodeStateWrapper != null) { + return rootNodeStateWrapper.apply(root); + } + return root; } @NotNull diff --git a/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/SegmentNodeStoreRegistrar.java b/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/SegmentNodeStoreRegistrar.java index 127465d0cd..a74004d0bb 100644 --- a/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/SegmentNodeStoreRegistrar.java +++ b/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/SegmentNodeStoreRegistrar.java @@ -62,6 +62,7 @@ import org.apache.jackrabbit.oak.segment.file.tar.TarPersistence; import org.apache.jackrabbit.oak.segment.spi.persistence.SegmentNodeStorePersistence; import org.apache.jackrabbit.oak.segment.split.SplitPersistence; import org.apache.jackrabbit.oak.segment.tool.LoggingHook; +import org.apache.jackrabbit.oak.segment.tool.LoggingNodeStateWrapper; import org.apache.jackrabbit.oak.spi.blob.BlobStore; import org.apache.jackrabbit.oak.spi.blob.GarbageCollectableBlobStore; import org.apache.jackrabbit.oak.spi.cluster.ClusterRepositoryInfo; @@ -366,9 +367,14 @@ class SegmentNodeStoreRegistrar { SegmentNodeStore.SegmentNodeStoreBuilder segmentNodeStoreBuilder = SegmentNodeStoreBuilders.builder(store).withStatisticsProvider(cfg.getStatisticsProvider()); segmentNodeStoreBuilder.dispatchChanges(cfg.dispatchChanges()); - Logger log = LoggerFactory.getLogger(LoggingHook.class.getName() + ".writer"); - if (log.isTraceEnabled()) { - segmentNodeStoreBuilder.withLoggingHook(log::trace); + final Logger writeLog = LoggerFactory.getLogger(LoggingHook.class.getName() + ".writer"); + if (writeLog.isTraceEnabled()) { + segmentNodeStoreBuilder.withLoggingHook(writeLog::trace); + } + + final Logger readLog = LoggerFactory.getLogger(LoggingHook.class.getName() + ".reader"); + if (readLog.isTraceEnabled()) { + segmentNodeStoreBuilder.withRootNodeStateWrapper(root -> new LoggingNodeStateWrapper("", root, true)); } SegmentNodeStore segmentNodeStore = segmentNodeStoreBuilder.build(); diff --git a/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/tool/LoggingHook.java b/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/tool/LoggingHook.java index 11db115202..24ae467a63 100644 --- a/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/tool/LoggingHook.java +++ b/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/tool/LoggingHook.java @@ -130,7 +130,7 @@ public class LoggingHook implements CommitHook, NodeStateDiff { return val.toString(); } - private static String urlEncode(String s) { + protected static String urlEncode(String s) { String ret; try { ret = URLEncoder.encode(s, "UTF-8").replace("%2F", "/").replace("%3A", ":"); diff --git a/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/tool/LoggingNodeStateWrapper.java b/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/tool/LoggingNodeStateWrapper.java new file mode 100644 index 0000000000..0b222556d4 --- /dev/null +++ b/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/tool/LoggingNodeStateWrapper.java @@ -0,0 +1,189 @@ +/* + * 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.tool; + +import java.util.ArrayList; +import java.util.List; +import org.apache.jackrabbit.oak.api.PropertyState; +import org.apache.jackrabbit.oak.spi.state.ChildNodeEntry; +import org.apache.jackrabbit.oak.spi.state.NodeBuilder; +import org.apache.jackrabbit.oak.spi.state.NodeState; +import org.apache.jackrabbit.oak.spi.state.NodeStateDiff; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class LoggingNodeStateWrapper extends NodeStateWrapper { + + private static final Logger LOG = LoggerFactory.getLogger(LoggingHook.class.getName() + ".reader"); + + private final String path; + private final boolean isRootNode; + + public LoggingNodeStateWrapper(String path, NodeState ns, boolean isRootNode) { + super(ns); + this.path = path; + this.isRootNode = isRootNode; + } + + public boolean isRootNode() { + return isRootNode; + } + + @Override + public boolean exists() { + return ns.exists(); + } + + @Override + public boolean hasProperty(String name) { + return ns.hasProperty(name); + } + + @Override + public PropertyState getProperty(String name) { + log.propertyRead(path, name); + return ns.getProperty(name); + } + + @Override + public boolean getBoolean(String name) { + return ns.getBoolean(name); + } + + @Override + public long getLong(String name) { + return ns.getLong(name); + } + + @Override + public String getString(String name) { + return ns.getString(name); + } + + @Override + public Iterable getStrings(String name) { + return ns.getStrings(name); + } + + @Override + public String getName(String name) { + return ns.getName(name); + } + + @Override + public Iterable getNames(String name) { + return ns.getNames(name); + } + + @Override + public long getPropertyCount() { + return ns.getPropertyCount(); + } + + @Override + public Iterable getProperties() { + return ns.getProperties(); + } + + @Override + public boolean hasChildNode(String name) { + return ns.hasChildNode(name); + } + + @Override + public NodeState getChildNode(String name) throws IllegalArgumentException { + final String newName = path + "/" + name; + log.nodeRead(newName); + return new LoggingNodeStateWrapper(newName, ns.getChildNode(name), false); + } + + @Override + public long getChildNodeCount(long max) { + return ns.getChildNodeCount(max); + } + + @Override + public Iterable getChildNodeNames() { + return ns.getChildNodeNames(); + } + + public class ChildNodeEntryWrapper implements ChildNodeEntry { + + private final ChildNodeEntry entry; + + public ChildNodeEntryWrapper(ChildNodeEntry entry) { + this.entry = entry; + } + + @Override + public String getName() { + return entry.getName(); + } + + @Override + public NodeState getNodeState() { + return new LoggingNodeStateWrapper(String.join("/", path, entry.getName()), entry.getNodeState(), false); + } + } + + @Override + public Iterable getChildNodeEntries() { + final List entries = new ArrayList(); + ns.getChildNodeEntries().forEach(e -> entries.add(new ChildNodeEntryWrapper(e))); + return entries; + } + + @Override + public NodeBuilder builder() { + return ns.builder(); + } + + @Override + public boolean compareAgainstBaseState(NodeState base, NodeStateDiff diff) { + return ns.compareAgainstBaseState(base, diff); + } + + private interface ReaderLogger { + public void nodeRead(String n); + public void propertyRead(String n, String p); + } + + private ReaderLogger log = new ReaderLogger() { + @Override + public void nodeRead(String n) { + if (n == null) { + n = "::: unknown :::"; + } + log("n? " + LoggingHook.urlEncode(n)); + } + + @Override + public void propertyRead(String n, String p) { + if (n == null) { + n = "::: unknown :::"; + } + log("p? " + LoggingHook.urlEncode(n) + " " + LoggingHook.urlEncode(p)); + } + + private void log(String s) { + LOG.trace(System.currentTimeMillis() + " " + LoggingHook.urlEncode(Thread.currentThread().getName()) + " " + s); + } + }; +} diff --git a/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/tool/NodeStateWrapper.java b/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/tool/NodeStateWrapper.java new file mode 100644 index 0000000000..51cfc4ea8d --- /dev/null +++ b/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/tool/NodeStateWrapper.java @@ -0,0 +1,30 @@ +/* + * 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.tool; + +import org.apache.jackrabbit.oak.spi.state.NodeState; + +public abstract class NodeStateWrapper implements NodeState { + protected final NodeState ns; + + public NodeStateWrapper(NodeState ns) { + this.ns = ns; + } +} -- 2.17.1