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 fr...@apache.org on 2018/10/26 12:01:29 UTC
svn commit: r1844899 - in
/jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment:
SegmentNodeStore.java SegmentNodeStoreRegistrar.java tool/LoggingHook.java
Author: frm
Date: Fri Oct 26 12:01:29 2018
New Revision: 1844899
URL: http://svn.apache.org/viewvc?rev=1844899&view=rev
Log:
OAK-7849 - Implement a CommitHook to log commit activity
Contribution by Axel Hanikel
Added:
jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/tool/LoggingHook.java (with props)
Modified:
jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/SegmentNodeStore.java
jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/SegmentNodeStoreRegistrar.java
Modified: jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/SegmentNodeStore.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/SegmentNodeStore.java?rev=1844899&r1=1844898&r2=1844899&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/SegmentNodeStore.java (original)
+++ jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/SegmentNodeStore.java Fri Oct 26 12:01:29 2018
@@ -29,6 +29,7 @@ import java.io.IOException;
import java.io.InputStream;
import java.util.Collections;
import java.util.Map;
+import java.util.function.Consumer;
import org.apache.jackrabbit.oak.api.Blob;
import org.apache.jackrabbit.oak.api.CommitFailedException;
@@ -37,9 +38,11 @@ import org.apache.jackrabbit.oak.plugins
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.spi.blob.BlobStore;
import org.apache.jackrabbit.oak.spi.commit.CommitHook;
import org.apache.jackrabbit.oak.spi.commit.CommitInfo;
+import org.apache.jackrabbit.oak.spi.commit.CompositeHook;
import org.apache.jackrabbit.oak.spi.commit.Observable;
import org.apache.jackrabbit.oak.spi.commit.Observer;
import org.apache.jackrabbit.oak.spi.state.ConflictAnnotatingRebaseDiff;
@@ -81,7 +84,9 @@ public class SegmentNodeStore implements
@NotNull
private StatisticsProvider statsProvider = StatisticsProvider.NOOP;
-
+
+ private LoggingHook loggingHook;
+
private SegmentNodeStoreBuilder(
@NotNull Revisions revisions,
@NotNull SegmentReader reader,
@@ -110,7 +115,18 @@ public class SegmentNodeStore implements
this.statsProvider = checkNotNull(statisticsProvider);
return this;
}
-
+
+ /**
+ * {@link LoggingHook} for recording write operations to a log file
+ *
+ * @return this instance
+ */
+ @NotNull
+ public SegmentNodeStoreBuilder withLoggingHook(Consumer<String> writer) {
+ this.loggingHook = LoggingHook.newLoggingHook(writer);
+ return this;
+ }
+
@NotNull
public SegmentNodeStore build() {
checkState(!isCreated);
@@ -123,7 +139,7 @@ public class SegmentNodeStore implements
private static String getString(@Nullable BlobStore blobStore) {
return "blobStore=" + (blobStore == null ? "inline" : blobStore);
}
-
+
@Override
public String toString() {
return "SegmentNodeStoreBuilder{" +
@@ -157,6 +173,8 @@ public class SegmentNodeStore implements
private final SegmentNodeStoreStats stats;
+ private final LoggingHook loggingHook;
+
private SegmentNodeStore(SegmentNodeStoreBuilder builder) {
this.writer = builder.writer;
this.blobStore = builder.blobStore;
@@ -164,6 +182,7 @@ public class SegmentNodeStore implements
this.scheduler = LockBasedScheduler.builder(builder.revisions, builder.reader, stats)
.dispatchChanges(builder.dispatchChanges)
.build();
+ this.loggingHook = builder.loggingHook;
}
@Override
@@ -187,6 +206,9 @@ public class SegmentNodeStore implements
@NotNull CommitInfo info) throws CommitFailedException {
checkArgument(builder instanceof SegmentNodeBuilder);
checkArgument(((SegmentNodeBuilder) builder).isRootBuilder());
+ if (loggingHook != null) {
+ commitHook = new CompositeHook(commitHook, loggingHook);
+ }
return scheduler.schedule(new Commit(builder, commitHook, info));
}
Modified: jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/SegmentNodeStoreRegistrar.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/SegmentNodeStoreRegistrar.java?rev=1844899&r1=1844898&r2=1844899&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/SegmentNodeStoreRegistrar.java (original)
+++ jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/SegmentNodeStoreRegistrar.java Fri Oct 26 12:01:29 2018
@@ -61,6 +61,7 @@ import org.apache.jackrabbit.oak.segment
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.spi.blob.BlobStore;
import org.apache.jackrabbit.oak.spi.blob.GarbageCollectableBlobStore;
import org.apache.jackrabbit.oak.spi.cluster.ClusterRepositoryInfo;
@@ -81,6 +82,7 @@ import org.apache.jackrabbit.oak.stats.S
import org.osgi.framework.BundleContext;
import org.osgi.framework.Constants;
import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
class SegmentNodeStoreRegistrar {
@@ -364,6 +366,11 @@ 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);
+ }
+
SegmentNodeStore segmentNodeStore = segmentNodeStoreBuilder.build();
if (cfg.isPrimarySegmentStore()) {
Added: jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/tool/LoggingHook.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/tool/LoggingHook.java?rev=1844899&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/tool/LoggingHook.java (added)
+++ jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/tool/LoggingHook.java Fri Oct 26 12:01:29 2018
@@ -0,0 +1,177 @@
+/*
+ * 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 static org.apache.jackrabbit.oak.api.Type.BINARIES;
+import static org.apache.jackrabbit.oak.api.Type.BINARY;
+import static org.apache.jackrabbit.oak.api.Type.STRING;
+import static org.apache.jackrabbit.oak.api.Type.STRINGS;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.UnsupportedEncodingException;
+import java.net.URLEncoder;
+import java.util.function.Consumer;
+
+import org.apache.jackrabbit.oak.api.Blob;
+import org.apache.jackrabbit.oak.api.CommitFailedException;
+import org.apache.jackrabbit.oak.api.PropertyState;
+import org.apache.jackrabbit.oak.plugins.memory.EmptyNodeState;
+import org.apache.jackrabbit.oak.spi.commit.CommitHook;
+import org.apache.jackrabbit.oak.spi.commit.CommitInfo;
+import org.apache.jackrabbit.oak.spi.state.NodeState;
+import org.apache.jackrabbit.oak.spi.state.NodeStateDiff;
+import org.jetbrains.annotations.NotNull;
+
+public class LoggingHook implements CommitHook, NodeStateDiff {
+
+ private final Consumer<String> writer;
+
+ private LoggingHook(final Consumer<String> writer) {
+ this.writer = writer;
+ }
+
+ public static LoggingHook newLoggingHook(final Consumer<String> writer) {
+ return new LoggingHook(writer);
+ }
+
+ public void enter(NodeState before, NodeState after) {
+ // do nothing
+ }
+
+ public void leave(NodeState before, NodeState after) {
+ log("n!");
+ }
+
+ @Override
+ public boolean propertyAdded(PropertyState after) {
+ log("p+ " + toString(after));
+ return true;
+ }
+
+ @Override
+ public boolean propertyChanged(PropertyState before, PropertyState after) {
+ log("p^ " + toString(after));
+ return true;
+ }
+
+ @Override
+ public boolean propertyDeleted(PropertyState before) {
+ log("p- " + toString(before));
+ return true;
+ }
+
+ @Override
+ public boolean childNodeAdded(String name, NodeState after) {
+ log("n+ " + urlEncode(name));
+ this.enter(null, after);
+ boolean ret = after.compareAgainstBaseState(EmptyNodeState.EMPTY_NODE, this);
+ this.leave(null, after);
+ return ret;
+ }
+
+ @Override
+ public boolean childNodeChanged(String name, NodeState before, NodeState after) {
+ log("n^ " + urlEncode(name));
+ this.enter(before, after);
+ boolean ret = after.compareAgainstBaseState(before, this);
+ this.leave(before, after);
+ return ret;
+ }
+
+ @Override
+ public boolean childNodeDeleted(String name, NodeState before) {
+ log("n- " + urlEncode(name));
+ return true;
+ }
+
+ private static String toString(final PropertyState ps) {
+ final StringBuilder val = new StringBuilder(); // TODO: an output stream would certainly be better
+ val.append(urlEncode(ps.getName()));
+ val.append(" <");
+ val.append(ps.getType());
+ val.append("> ");
+ if (ps.getType() == BINARY) {
+ val.append("= ");
+ final Blob blob = ps.getValue(BINARY);
+ appendBlob(val, blob);
+ } else if (ps.getType() == BINARIES) {
+ val.append("= [");
+ ps.getValue(BINARIES).forEach((Blob b) -> {
+ appendBlob(val, b);
+ val.append(',');
+ });
+ replaceOrAppendLastChar(val, ',', ']');
+ } else if (ps.isArray()) {
+ val.append("= [");
+ ps.getValue(STRINGS).forEach((String s) -> {
+ val.append(urlEncode(s));
+ val.append(',');
+ });
+ replaceOrAppendLastChar(val, ',', ']');
+ } else {
+ val.append("= ").append(urlEncode(ps.getValue(STRING)));
+ }
+ return val.toString();
+ }
+
+ private static String urlEncode(String s) {
+ String ret;
+ try {
+ ret = URLEncoder.encode(s, "UTF-8").replace("%2F", "/").replace("%3A", ":");
+ } catch (UnsupportedEncodingException ex) {
+ ret = "ERROR: " + ex.toString();
+ }
+ return ret;
+ }
+
+ private static void replaceOrAppendLastChar(StringBuilder b, char oldChar, char newChar) {
+ if (b.charAt(b.length() - 1) == oldChar) {
+ b.setCharAt(b.length() - 1, newChar);
+ } else {
+ b.append(newChar);
+ }
+ }
+
+ private void log(String s) {
+ writer.accept(System.currentTimeMillis() + " " + urlEncode(Thread.currentThread().getName()) + " " + s);
+ }
+
+ private static void appendBlob(StringBuilder sb, Blob blob) {
+ final InputStream is = blob.getNewStream();
+ final char[] hex = "0123456789ABCDEF".toCharArray();
+ int b;
+ try {
+ while ((b = is.read()) >= 0) {
+ sb.append(hex[b >> 4]);
+ sb.append(hex[b & 0x0f]);
+ }
+ } catch (IOException ex) {
+ throw new IllegalStateException(ex);
+ }
+ }
+
+ @NotNull
+ @Override
+ public NodeState processCommit(NodeState before, NodeState after, CommitInfo info) throws CommitFailedException {
+ this.enter(before, after);
+ after.compareAgainstBaseState(before, this);
+ this.leave(before, after);
+ return after;
+ }
+}
Propchange: jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/tool/LoggingHook.java
------------------------------------------------------------------------------
svn:eol-style = native