use of org.apache.jackrabbit.oak.spi.commit.CommitHook in project jackrabbit-oak by apache.
the class ClusterConflictTest method mergeRetryWhileBackgroundRead.
// OAK-3433
@Test
public void mergeRetryWhileBackgroundRead() throws Exception {
DocumentNodeStore ns1 = mk.getNodeStore();
NodeBuilder b1 = ns1.getRoot().builder();
b1.child("a").child("b").child("c").child("foo");
merge(ns1, b1);
ns1.runBackgroundOperations();
ns2.runBackgroundOperations();
NodeBuilder b2 = ns2.getRoot().builder();
// force cache fill
assertNodeExists(b2, "/a/b/c/foo");
// remove /a/b/c on ns1
b1 = ns1.getRoot().builder();
b1.child("a").child("b").child("c").remove();
merge(ns1, b1);
// perform some change on ns2
b2.child("z");
merge(ns2, b2);
runBackgroundUpdate(ns2);
// this will pickup changes done by ns2 and update
// the head revision
runBackgroundRead(ns1);
// the next step is where the issue described
// in OAK-3433 occurs.
// the journal entry with changes done on ns1 is pushed
// with the current head revision, which is newer
// than the most recent change in the journal entry
runBackgroundUpdate(ns1);
// perform a background read after the rebase
// the first merge attempt will fail with a conflict
// because /a/b/c is seen as changed in the future
// without the fix for OAK-3433:
// the second merge attempt succeeds because now the
// /a/b/c change revision is visible and happened before the commit
// revision but before the base revision
b2 = ns2.getRoot().builder();
b2.child("z").setProperty("q", "v");
try {
ns2.merge(b2, new CommitHook() {
@Nonnull
@Override
public NodeState processCommit(NodeState before, NodeState after, CommitInfo info) throws CommitFailedException {
runBackgroundRead(ns2);
NodeBuilder builder = after.builder();
if (builder.getChildNode("a").getChildNode("b").hasChildNode("c")) {
builder.child("a").child("b").child("c").child("bar");
} else {
throw new CommitFailedException(CommitFailedException.OAK, 0, "/a/b/c does not exist anymore");
}
return builder.getNodeState();
}
}, CommitInfo.EMPTY);
fail("Merge must fail with CommitFailedException");
} catch (CommitFailedException e) {
// expected
}
}
use of org.apache.jackrabbit.oak.spi.commit.CommitHook in project jackrabbit-oak by apache.
the class NodeStoreDiffTest method testDiff.
/**
* This testcase demonstrates that diff logic in merge part traverses node path
* which are not affected by the commit
* @throws Exception
*/
@Test
public void testDiff() throws Exception {
createNodes("/oak:index/prop-a", "/oak:index/prop-b", "/etc/workflow");
//1. Make some other changes so as to bump root rev=3
createNodes("/fake/a");
createNodes("/fake/b");
//2 - Start change
NodeBuilder b2 = ns.getRoot().builder();
createNodes(b2, "/etc/workflow/instance1");
tds.reset();
//3. Merge which does a rebase
ns.merge(b2, new CommitHook() {
@Nonnull
public NodeState processCommit(NodeState before, NodeState after, CommitInfo info) throws CommitFailedException {
NodeBuilder rb = after.builder();
createNodes(rb, "/oak:index/prop-a/a1");
//2.1 Commit some change under prop-
//This cause diff in lastRev of base node state in ModifiedNodeState for
//oak:index due to which when the base state is compared in ModifiedNodeState
//then it fetches the new DocumentNodeState whose lastRev is greater than this.base.lastRev
//but less then lastRev of the of readRevision. Where readRevision is the rev of root node when
//rebase was performed
// remember paths accessed so far
List<String> paths = Lists.newArrayList(tds.paths);
//This is not to be done in actual cases as CommitHooks are invoked in critical sections
//and creating nodes from within CommitHooks would cause deadlock. This is done here to ensure
//that changes are done when rebase has been performed and merge is about to happen
createNodes("/oak:index/prop-b/b1");
// reset accessed paths
tds.reset();
tds.paths.addAll(paths);
return rb.getNodeState();
}
}, CommitInfo.EMPTY);
//Assert that diff logic does not traverse to /oak:index/prop-b/b1 as
//its not part of commit
assertFalse(tds.paths.contains("/oak:index/prop-b/b1"));
}
use of org.apache.jackrabbit.oak.spi.commit.CommitHook in project jackrabbit-oak by apache.
the class AsyncIndexUpdate method mergeWithConcurrencyCheck.
private static void mergeWithConcurrencyCheck(final NodeStore store, List<ValidatorProvider> validatorProviders, NodeBuilder builder, final String checkpoint, final Long lease, final String name) throws CommitFailedException {
CommitHook concurrentUpdateCheck = new CommitHook() {
@Override
@Nonnull
public NodeState processCommit(NodeState before, NodeState after, CommitInfo info) throws CommitFailedException {
// check for concurrent updates by this async task
NodeState async = before.getChildNode(ASYNC);
if ((checkpoint == null || Objects.equal(checkpoint, async.getString(name))) && (lease == null || lease == async.getLong(leasify(name)))) {
return after;
} else {
throw newConcurrentUpdateException();
}
}
};
List<EditorProvider> editorProviders = Lists.newArrayList();
editorProviders.add(new ConflictValidatorProvider());
editorProviders.addAll(validatorProviders);
CompositeHook hooks = new CompositeHook(ResetCommitAttributeHook.INSTANCE, new ConflictHook(new AnnotatingConflictHandler()), new EditorHook(CompositeEditorProvider.compose(editorProviders)), concurrentUpdateCheck);
try {
store.merge(builder, hooks, createCommitInfo());
} catch (CommitFailedException ex) {
// OAK-2961
if (ex.isOfType(CommitFailedException.STATE) && ex.getCode() == 1) {
throw newConcurrentUpdateException();
} else {
throw ex;
}
}
}
use of org.apache.jackrabbit.oak.spi.commit.CommitHook in project jackrabbit-oak by apache.
the class MutableRoot method getCommitHook.
/**
* Combine the globally defined commit hook(s) and the hooks and validators defined by the
* various security related configurations.
*
* @return A commit hook combining repository global commit hook(s) with the pluggable hooks
* defined with the security modules and the padded {@code hooks}.
*/
private CommitHook getCommitHook() {
List<CommitHook> hooks = newArrayList();
hooks.add(ResetCommitAttributeHook.INSTANCE);
hooks.add(hook);
List<CommitHook> postValidationHooks = new ArrayList<CommitHook>();
for (SecurityConfiguration sc : securityProvider.getConfigurations()) {
for (CommitHook ch : sc.getCommitHooks(workspaceName)) {
if (ch instanceof PostValidationHook) {
postValidationHooks.add(ch);
} else if (ch != EmptyHook.INSTANCE) {
hooks.add(ch);
}
}
List<? extends ValidatorProvider> validators = sc.getValidators(workspaceName, subject.getPrincipals(), moveTracker);
if (!validators.isEmpty()) {
hooks.add(new EditorHook(CompositeEditorProvider.compose(validators)));
}
}
hooks.addAll(postValidationHooks);
return CompositeHook.compose(hooks);
}
use of org.apache.jackrabbit.oak.spi.commit.CommitHook in project jackrabbit-oak by apache.
the class DocumentNodeStoreTest method commitHookChangesOnBranch.
@Test
public void commitHookChangesOnBranch() throws Exception {
final int NUM_NODES = DocumentMK.UPDATE_LIMIT / 2;
final int NUM_PROPS = 10;
DocumentNodeStore ns = builderProvider.newBuilder().getNodeStore();
NodeBuilder builder = ns.getRoot().builder();
for (int i = 0; i < NUM_NODES; i++) {
NodeBuilder c = builder.child("n" + i);
for (int j = 0; j < NUM_PROPS; j++) {
c.setProperty("q" + j, "value");
c.setProperty("p" + j, "value");
}
}
try {
ns.merge(builder, CompositeHook.compose(Arrays.asList(new TestHook("p"), new TestHook("q"), FAILING_HOOK)), CommitInfo.EMPTY);
fail("merge must fail and reset changes done by commit hooks");
} catch (CommitFailedException e) {
// expected
}
for (int i = 0; i < NUM_NODES; i++) {
NodeBuilder c = builder.getChildNode("n" + i);
assertTrue(c.exists());
for (int j = 0; j < NUM_PROPS; j++) {
PropertyState p = c.getProperty("p" + j);
assertNotNull(p);
// must still see initial values before failed merge
assertEquals("value", p.getValue(Type.STRING));
// same for property 'qX'
p = c.getProperty("q" + j);
assertNotNull(p);
// must still see initial values before failed merge
assertEquals("value", p.getValue(Type.STRING));
}
}
ns.merge(builder, CompositeHook.compose(Arrays.<CommitHook>asList(new TestHook("p"), new TestHook("q"))), CommitInfo.EMPTY);
builder = ns.getRoot().builder();
// must see properties changed by commit hook
for (int i = 0; i < NUM_NODES; i++) {
NodeBuilder c = builder.getChildNode("n" + i);
assertTrue(c.exists());
for (int j = 0; j < NUM_PROPS; j++) {
PropertyState p = c.getProperty("p" + j);
assertNotNull(p);
assertEquals("test", p.getValue(Type.STRING));
p = c.getProperty("q" + j);
assertNotNull(p);
assertEquals("test", p.getValue(Type.STRING));
}
}
}
Aggregations