Author: adulceanu
Date: Thu Sep 14 15:06:43 2017
New Revision: 1808355
URL: http://svn.apache.org/viewvc?rev=1808355&view=rev
Log:
OAK-6659 - Cold standby should fail loudly when a big blob can't be timely
transferred
Restructured StandbyDiff to transparently load all blobs before doing any other
processing
Added failed sync test case in ExternalPrivateStoreIT
Modified:
jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/standby/client/StandbyDiff.java
jackrabbit/oak/trunk/oak-segment-tar/src/test/java/org/apache/jackrabbit/oak/segment/standby/ExternalPrivateStoreIT.java
Modified:
jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/standby/client/StandbyDiff.java
URL:
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/standby/client/StandbyDiff.java?rev=1808355&r1=1808354&r2=1808355&view=diff
==============================================================================
---
jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/standby/client/StandbyDiff.java
(original)
+++
jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/standby/client/StandbyDiff.java
Thu Sep 14 15:06:43 2017
@@ -63,7 +63,7 @@ class StandbyDiff implements NodeStateDi
* missing binaries can be sync'ed if needed
*/
private final boolean logOnly;
-
+
StandbyDiff(NodeBuilder builder, FileStore store, StandbyClient client,
Supplier<Boolean> running) {
this(builder, store, client, "/", false, running);
}
@@ -87,13 +87,11 @@ class StandbyDiff implements NodeStateDi
if (stop()) {
return false;
}
-
- if (logOnly) {
- binaryCheck(after);
- } else {
- builder.setProperty(binaryCheck(after));
+
+ if (!logOnly) {
+ builder.setProperty(after);
}
-
+
return true;
}
@@ -102,13 +100,11 @@ class StandbyDiff implements NodeStateDi
if (stop()) {
return false;
}
-
- if (logOnly) {
- binaryCheck(after);
- } else {
- builder.setProperty(binaryCheck(after));
+
+ if (!logOnly) {
+ builder.setProperty(after);
}
-
+
return true;
}
@@ -121,10 +117,70 @@ class StandbyDiff implements NodeStateDi
if (!logOnly) {
builder.removeProperty(before.getName());
}
+
+ return true;
+ }
+
+ @Override
+ public boolean childNodeAdded(String name, NodeState after) {
+ return process(name, "childNodeAdded", EmptyNodeState.EMPTY_NODE,
after);
+ }
+
+ @Override
+ public boolean childNodeChanged(String name, NodeState before, NodeState
after) {
+ return process(name, "childNodeChanged", before, after);
+ }
+
+ @Override
+ public boolean childNodeDeleted(String name, NodeState before) {
+ log.trace("childNodeDeleted {}, RO:{}", path + name, logOnly);
+
+ if (!logOnly) {
+ builder.getChildNode(name).remove();
+ }
return true;
}
+ private boolean process(String name, String op, NodeState before,
NodeState after) {
+ if (stop()) {
+ return false;
+ }
+
+ if (after instanceof SegmentNodeState) {
+ if (log.isTraceEnabled()) {
+ log.trace("{} {}, readonly binary check {}", op, path + name,
logOnly);
+ }
+
+ if (!logOnly) {
+ RecordId id = ((SegmentNodeState) after).getRecordId();
+ builder.setChildNode(name, store.getReader().readNode(id));
+ }
+
+ if ("checkpoints".equals(name)) {
+ // if we're on the /checkpoints path, there's no need for a
deep
+ // traversal to verify binaries
+ return true;
+ }
+
+ if (!hasDataStore) {
+ return true;
+ }
+
+ // has external data store, we need a deep
+ // traversal to verify binaries
+
+ for (PropertyState propertyState : after.getProperties()) {
+ binaryCheck(propertyState);
+ }
+
+ return after.compareAgainstBaseState(before,
+ new StandbyDiff(builder.getChildNode(name), store, client,
path + name + "/", true, running));
+ }
+
+ return false;
+ }
+
private PropertyState binaryCheck(PropertyState property) {
Type<?> type = property.getType();
@@ -162,7 +218,7 @@ class StandbyDiff implements NodeStateDi
}
}
}
-
+
private void readBlob(String blobId, String pName) throws
InterruptedException {
InputStream in = client.getBlob(blobId);
@@ -180,67 +236,4 @@ class StandbyDiff implements NodeStateDi
}
}
- @Override
- public boolean childNodeAdded(String name, NodeState after) {
- return process(name, "childNodeAdded", EmptyNodeState.EMPTY_NODE,
after);
- }
-
- @Override
- public boolean childNodeChanged(String name, NodeState before, NodeState
after) {
- try {
- return process(name, "childNodeChanged", before, after);
- } catch (RuntimeException e) {
- log.trace("Check binaries for node {} and retry to process
childNodeChanged", name);
- // Attempt to load the binaries and retry, see OAK-4969
- for (PropertyState propertyState : after.getProperties()) {
- binaryCheck(propertyState);
- }
- return process(name, "childNodeChanged", before, after);
- }
- }
-
- private boolean process(String name, String op, NodeState before,
NodeState after) {
- if (stop()) {
- return false;
- }
-
- if (after instanceof SegmentNodeState) {
- if (log.isTraceEnabled()) {
- log.trace("{} {}, readonly binary check {}", op, path + name,
logOnly);
- }
-
- if (!logOnly) {
- RecordId id = ((SegmentNodeState) after).getRecordId();
- builder.setChildNode(name, store.getReader().readNode(id));
- }
-
- if ("checkpoints".equals(name)) {
- // if we're on the /checkpoints path, there's no need for a
deep
- // traversal to verify binaries
- return true;
- }
-
- if (!hasDataStore) {
- return true;
-
- }
- // has external datastore, we need a deep
- // traversal to verify binaries
- return after.compareAgainstBaseState(before, new
StandbyDiff(builder.getChildNode(name), store, client, path + name + "/", true,
running));
- }
-
- return false;
- }
-
- @Override
- public boolean childNodeDeleted(String name, NodeState before) {
- log.trace("childNodeDeleted {}, RO:{}", path + name, logOnly);
-
- if (!logOnly) {
- builder.getChildNode(name).remove();
- }
-
- return true;
- }
-
}
Modified:
jackrabbit/oak/trunk/oak-segment-tar/src/test/java/org/apache/jackrabbit/oak/segment/standby/ExternalPrivateStoreIT.java
URL:
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-segment-tar/src/test/java/org/apache/jackrabbit/oak/segment/standby/ExternalPrivateStoreIT.java?rev=1808355&r1=1808354&r2=1808355&view=diff
==============================================================================
---
jackrabbit/oak/trunk/oak-segment-tar/src/test/java/org/apache/jackrabbit/oak/segment/standby/ExternalPrivateStoreIT.java
(original)
+++
jackrabbit/oak/trunk/oak-segment-tar/src/test/java/org/apache/jackrabbit/oak/segment/standby/ExternalPrivateStoreIT.java
Thu Sep 14 15:06:43 2017
@@ -18,12 +18,20 @@
*/
package org.apache.jackrabbit.oak.segment.standby;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotEquals;
+
import java.io.File;
+import org.apache.jackrabbit.oak.segment.SegmentNodeStoreBuilders;
import org.apache.jackrabbit.oak.segment.file.FileStore;
+import org.apache.jackrabbit.oak.segment.standby.client.StandbyClientSync;
+import org.apache.jackrabbit.oak.segment.standby.server.StandbyServerSync;
import org.apache.jackrabbit.oak.segment.test.TemporaryBlobStore;
import org.apache.jackrabbit.oak.segment.test.TemporaryFileStore;
+import org.apache.jackrabbit.oak.spi.state.NodeStore;
import org.junit.Rule;
+import org.junit.Test;
import org.junit.rules.RuleChain;
import org.junit.rules.TemporaryFolder;
@@ -61,4 +69,23 @@ public class ExternalPrivateStoreIT exte
return false;
}
+ @Test
+ public void testSyncFailingDueToTooShortTimeout() throws Exception {
+ final int blobSize = 5 * MB;
+ FileStore primary = getPrimary();
+ FileStore secondary = getSecondary();
+
+ NodeStore store = SegmentNodeStoreBuilders.builder(primary).build();
+ addTestContent(store, "server", blobSize);
+ try (
+ StandbyServerSync serverSync = new
StandbyServerSync(serverPort.getPort(), primary, 1 * MB);
+ StandbyClientSync cl = newStandbyClientSync(secondary,
serverPort.getPort(), false, 60)
+ ) {
+ serverSync.start();
+ primary.flush();
+ cl.run();
+ assertNotEquals(primary.getHead(), secondary.getHead());
+ assertEquals(1, cl.getFailedRequests());
+ }
+ }
}