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 md...@apache.org on 2019/03/01 07:20:15 UTC
svn commit: r1854559 - in /jackrabbit/oak/branches/1.10: ./
oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/
oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/scheduler/
Author: mduerig
Date: Fri Mar 1 07:20:15 2019
New Revision: 1854559
URL: http://svn.apache.org/viewvc?rev=1854559&view=rev
Log:
OAK-8071: Logging to detect commits carrying over from previous GC generation can block other threads from committing
Merged r1854515
Modified:
jackrabbit/oak/branches/1.10/ (props changed)
jackrabbit/oak/branches/1.10/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/Record.java
jackrabbit/oak/branches/1.10/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/scheduler/Commit.java
jackrabbit/oak/branches/1.10/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/scheduler/LockBasedScheduler.java
Propchange: jackrabbit/oak/branches/1.10/
------------------------------------------------------------------------------
--- svn:mergeinfo (original)
+++ svn:mergeinfo Fri Mar 1 07:20:15 2019
@@ -1,3 +1,3 @@
/jackrabbit/oak/branches/1.0:1665962
-/jackrabbit/oak/trunk:1850874,1850882,1851236,1851253,1851451,1852052,1852084,1852120,1852451,1852492-1852493,1852528,1852582,1852584,1852601,1852920,1853141,1853229,1853393,1853429,1853433,1853441,1853866,1853868,1853870,1853893,1853969,1853997,1854034,1854044,1854058,1854113,1854373,1854377,1854380,1854385,1854401,1854403,1854462,1854466,1854468
+/jackrabbit/oak/trunk:1850874,1850882,1851236,1851253,1851451,1852052,1852084,1852120,1852451,1852492-1852493,1852528,1852582,1852584,1852601,1852920,1853141,1853229,1853393,1853429,1853433,1853441,1853866,1853868,1853870,1853893,1853969,1853997,1854034,1854044,1854058,1854113,1854373,1854377,1854380,1854385,1854401,1854403,1854462,1854466,1854468,1854515
/jackrabbit/trunk:1345480
Modified: jackrabbit/oak/branches/1.10/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/Record.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/branches/1.10/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/Record.java?rev=1854559&r1=1854558&r2=1854559&view=diff
==============================================================================
--- jackrabbit/oak/branches/1.10/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/Record.java (original)
+++ jackrabbit/oak/branches/1.10/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/Record.java Fri Mar 1 07:20:15 2019
@@ -18,6 +18,7 @@
*/
package org.apache.jackrabbit.oak.segment;
+import org.apache.jackrabbit.oak.segment.file.tar.GCGeneration;
import org.jetbrains.annotations.NotNull;
/**
@@ -83,6 +84,16 @@ class Record {
return new RecordId(segmentId, recordNumber);
}
+ /**
+ * Get the underlying segment's gc generation. Might cause the segment to
+ * get loaded if the generation info is missing
+ * @return the segment's gc generation
+ */
+ @NotNull
+ public GCGeneration getGcGeneration() {
+ return segmentId.getGcGeneration();
+ }
+
//------------------------------------------------------------< Object >--
@Override
Modified: jackrabbit/oak/branches/1.10/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/scheduler/Commit.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/branches/1.10/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/scheduler/Commit.java?rev=1854559&r1=1854558&r2=1854559&view=diff
==============================================================================
--- jackrabbit/oak/branches/1.10/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/scheduler/Commit.java (original)
+++ jackrabbit/oak/branches/1.10/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/scheduler/Commit.java Fri Mar 1 07:20:15 2019
@@ -23,12 +23,14 @@ import static com.google.common.base.Pre
import org.apache.jackrabbit.oak.api.CommitFailedException;
import org.apache.jackrabbit.oak.segment.SegmentNodeBuilder;
import org.apache.jackrabbit.oak.segment.SegmentNodeState;
+import org.apache.jackrabbit.oak.segment.file.tar.GCGeneration;
import org.apache.jackrabbit.oak.spi.commit.CommitHook;
import org.apache.jackrabbit.oak.spi.commit.CommitInfo;
import org.apache.jackrabbit.oak.spi.state.ConflictAnnotatingRebaseDiff;
import org.apache.jackrabbit.oak.spi.state.NodeBuilder;
import org.apache.jackrabbit.oak.spi.state.NodeState;
import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
/**
* A {@code Commit} instance represents a set of related changes, which when
@@ -41,6 +43,8 @@ public class Commit {
private final CommitHook hook;
private final CommitInfo info;
+ private volatile GCGeneration gcGeneration;
+
public Commit(@NotNull NodeBuilder changes, @NotNull CommitHook hook, @NotNull CommitInfo info) {
checkNotNull(changes);
checkArgument(changes instanceof SegmentNodeBuilder);
@@ -51,6 +55,30 @@ public class Commit {
}
/**
+ * This method makes a best effort on getting the gc generation of the current commit.
+ * However it avoids causing a write ahead action by calling {@link NodeBuilder#getName(String)}
+ * on the changes in this commit.
+ *
+ * @return the gc generation of this commit or {@code null} if not yet available.
+ */
+ @Nullable
+ public GCGeneration getGCGeneration() {
+ return gcGeneration;
+ }
+
+ @NotNull
+ private NodeState getBeforeState() {
+ return changes.getBaseState();
+ }
+
+ @NotNull
+ private SegmentNodeState getAfterState() {
+ SegmentNodeState after = changes.getNodeState();
+ gcGeneration = after.getGcGeneration();
+ return after;
+ }
+
+ /**
* Apply the changes represented by this commit to the passed {@code base}
* node state.
*
@@ -63,19 +91,19 @@ public class Commit {
*/
public SegmentNodeState apply(SegmentNodeState base) throws CommitFailedException {
SegmentNodeBuilder builder = base.builder();
- if (SegmentNodeState.fastEquals(changes.getBaseState(), base.getChildNode(ROOT))) {
+ if (SegmentNodeState.fastEquals(getBeforeState(), base.getChildNode(ROOT))) {
// use a shortcut when there are no external changes
- NodeState before = changes.getBaseState();
- NodeState after = changes.getNodeState();
+ NodeState before = getBeforeState();
+ NodeState after = getAfterState();
builder.setChildNode(ROOT, hook.processCommit(before, after, info));
} else {
// there were some external changes, so do the full rebase
ConflictAnnotatingRebaseDiff diff = new ConflictAnnotatingRebaseDiff(builder.child(ROOT));
- changes.getNodeState().compareAgainstBaseState(changes.getBaseState(), diff);
+ getAfterState().compareAgainstBaseState(getBeforeState(), diff);
// apply commit hooks on the rebased changes
builder.setChildNode(ROOT, hook.processCommit(builder.getBaseState().getChildNode(ROOT),
- builder.getNodeState().getChildNode(ROOT), info));
+ builder.getNodeState().getChildNode(ROOT), info));
}
return builder.getNodeState();
}
@@ -94,11 +122,11 @@ public class Commit {
* the same semantics as
* {@link SegmentNodeState#fastEquals(NodeState, NodeState)}, which cannot
* guarantee against false negatives.
- *
+ *
* @return {@code true}, if the commit has changes.
*/
public boolean hasChanges() {
- return !SegmentNodeState.fastEquals(changes.getBaseState(), changes.getNodeState());
+ return !SegmentNodeState.fastEquals(getBeforeState(), getAfterState());
}
public CommitInfo info() {
Modified: jackrabbit/oak/branches/1.10/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/scheduler/LockBasedScheduler.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/branches/1.10/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/scheduler/LockBasedScheduler.java?rev=1854559&r1=1854558&r2=1854559&view=diff
==============================================================================
--- jackrabbit/oak/branches/1.10/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/scheduler/LockBasedScheduler.java (original)
+++ jackrabbit/oak/branches/1.10/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/scheduler/LockBasedScheduler.java Fri Mar 1 07:20:15 2019
@@ -45,6 +45,7 @@ import org.apache.jackrabbit.oak.segment
import org.apache.jackrabbit.oak.segment.SegmentNodeStoreStats;
import org.apache.jackrabbit.oak.segment.SegmentOverflowException;
import org.apache.jackrabbit.oak.segment.SegmentReader;
+import org.apache.jackrabbit.oak.segment.file.tar.GCGeneration;
import org.apache.jackrabbit.oak.spi.commit.ChangeDispatcher;
import org.apache.jackrabbit.oak.spi.commit.CommitInfo;
import org.apache.jackrabbit.oak.spi.commit.Observable;
@@ -52,8 +53,10 @@ import org.apache.jackrabbit.oak.spi.com
import org.apache.jackrabbit.oak.spi.state.NodeBuilder;
import org.apache.jackrabbit.oak.spi.state.NodeState;
import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+
public class LockBasedScheduler implements Scheduler {
public static class LockBasedSchedulerBuilder {
@@ -111,6 +114,13 @@ public class LockBasedScheduler implemen
*/
private static final double SCHEDULER_FETCH_COMMIT_DELAY_QUANTILE = Double
.parseDouble(System.getProperty("oak.scheduler.fetch.commitDelayQuantile", "0.5"));
+
+ /**
+ * Flag controlling the number of milliseconds after which warnings are logged
+ * when threads ready to commit have to wait for a commit in progress.
+ */
+ private static final int COMMIT_WAIT_WARN_MILLIS = Integer
+ .getInteger("oak.segmentNodeStore.commitWaitWarnMillis", 60000);
/**
* Maximum number of milliseconds to wait before re-attempting to update the current
@@ -147,6 +157,50 @@ public class LockBasedScheduler implemen
private final Random random = new Random();
+ private final CommitSemaphoreLogging commitSemaphoreLogging = new CommitSemaphoreLogging();
+
+ /*
+ * Logging of commits that are either blocked for longer than COMMIT_WAIT_WARN_MILLIS
+ * or on a commit that crossed the gc boundary. See OAK-8071.
+ */
+ private class CommitSemaphoreLogging {
+
+ @Nullable
+ private volatile Commit commit;
+
+ private volatile long timeStamp;
+
+ public void commitStarted(@NotNull Commit commit) {
+ this.commit = commit;
+ this.timeStamp = System.currentTimeMillis();
+ }
+
+ public void commitEnded() {
+ this.commit = null;
+ }
+
+ public void warnOnBlockingCommit() {
+ Commit currentCommit = commit;
+ GCGeneration headGeneration = head.get().getGcGeneration();
+ GCGeneration commitGeneration = currentCommit == null
+ ? null
+ : currentCommit.getGCGeneration();
+ long dt = System.currentTimeMillis() - timeStamp;
+ boolean isBlocking = currentCommit != null && dt > COMMIT_WAIT_WARN_MILLIS;
+ boolean isOldGeneration = commitGeneration != null
+ && headGeneration.getFullGeneration() > commitGeneration.getFullGeneration();
+
+ if (isBlocking) {
+ log.warn("This commit is blocked by a commit that is in progress since {} ms", dt);
+ }
+
+ if (isOldGeneration) {
+ log.warn("The commit in progress is from an old GC generation {}. Head is at {}",
+ commitGeneration, headGeneration);
+ }
+ }
+ }
+
public LockBasedScheduler(LockBasedSchedulerBuilder builder) {
if (COMMIT_FAIR_LOCK) {
log.info("Initializing SegmentNodeStore with the commitFairLock option enabled.");
@@ -202,6 +256,8 @@ public class LockBasedScheduler implemen
boolean queued = false;
try {
+ commitSemaphoreLogging.warnOnBlockingCommit();
+
long queuedTime = -1;
if (commitSemaphore.availablePermits() < 1) {
@@ -211,6 +267,7 @@ public class LockBasedScheduler implemen
}
commitSemaphore.acquire();
+ commitSemaphoreLogging.commitStarted(commit);
try {
if (queued) {
long dequeuedTime = System.nanoTime();
@@ -228,6 +285,7 @@ public class LockBasedScheduler implemen
return merged;
} finally {
+ commitSemaphoreLogging.commitEnded();
commitSemaphore.release();
}
} catch (InterruptedException e) {