Search in sources :

Example 1 with CommitHook

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
    }
}
Also used : NodeState(org.apache.jackrabbit.oak.spi.state.NodeState) Nonnull(javax.annotation.Nonnull) CommitHook(org.apache.jackrabbit.oak.spi.commit.CommitHook) DocumentNodeStore(org.apache.jackrabbit.oak.plugins.document.DocumentNodeStore) CommitInfo(org.apache.jackrabbit.oak.spi.commit.CommitInfo) NodeBuilder(org.apache.jackrabbit.oak.spi.state.NodeBuilder) CommitFailedException(org.apache.jackrabbit.oak.api.CommitFailedException) Test(org.junit.Test) AbstractMongoConnectionTest(org.apache.jackrabbit.oak.plugins.document.AbstractMongoConnectionTest)

Example 2 with CommitHook

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"));
}
Also used : NodeState(org.apache.jackrabbit.oak.spi.state.NodeState) Nonnull(javax.annotation.Nonnull) CommitHook(org.apache.jackrabbit.oak.spi.commit.CommitHook) List(java.util.List) CommitInfo(org.apache.jackrabbit.oak.spi.commit.CommitInfo) NodeBuilder(org.apache.jackrabbit.oak.spi.state.NodeBuilder) CommitFailedException(org.apache.jackrabbit.oak.api.CommitFailedException) Test(org.junit.Test)

Example 3 with CommitHook

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;
        }
    }
}
Also used : CompositeHook(org.apache.jackrabbit.oak.spi.commit.CompositeHook) AnnotatingConflictHandler(org.apache.jackrabbit.oak.plugins.commit.AnnotatingConflictHandler) NodeState(org.apache.jackrabbit.oak.spi.state.NodeState) CommitHook(org.apache.jackrabbit.oak.spi.commit.CommitHook) EditorHook(org.apache.jackrabbit.oak.spi.commit.EditorHook) ConflictHook(org.apache.jackrabbit.oak.plugins.commit.ConflictHook) CommitInfo(org.apache.jackrabbit.oak.spi.commit.CommitInfo) ConflictValidatorProvider(org.apache.jackrabbit.oak.plugins.commit.ConflictValidatorProvider) EditorProvider(org.apache.jackrabbit.oak.spi.commit.EditorProvider) CompositeEditorProvider(org.apache.jackrabbit.oak.spi.commit.CompositeEditorProvider) CommitFailedException(org.apache.jackrabbit.oak.api.CommitFailedException)

Example 4 with CommitHook

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);
}
Also used : CommitHook(org.apache.jackrabbit.oak.spi.commit.CommitHook) EditorHook(org.apache.jackrabbit.oak.spi.commit.EditorHook) ArrayList(java.util.ArrayList) Lists.newArrayList(com.google.common.collect.Lists.newArrayList) PostValidationHook(org.apache.jackrabbit.oak.spi.commit.PostValidationHook) SecurityConfiguration(org.apache.jackrabbit.oak.spi.security.SecurityConfiguration)

Example 5 with CommitHook

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));
        }
    }
}
Also used : CommitHook(org.apache.jackrabbit.oak.spi.commit.CommitHook) NodeBuilder(org.apache.jackrabbit.oak.spi.state.NodeBuilder) CommitFailedException(org.apache.jackrabbit.oak.api.CommitFailedException) PropertyState(org.apache.jackrabbit.oak.api.PropertyState) Test(org.junit.Test)

Aggregations

CommitHook (org.apache.jackrabbit.oak.spi.commit.CommitHook)21 Test (org.junit.Test)12 NodeBuilder (org.apache.jackrabbit.oak.spi.state.NodeBuilder)10 CommitInfo (org.apache.jackrabbit.oak.spi.commit.CommitInfo)9 EditorHook (org.apache.jackrabbit.oak.spi.commit.EditorHook)9 NodeState (org.apache.jackrabbit.oak.spi.state.NodeState)9 Nonnull (javax.annotation.Nonnull)8 CommitFailedException (org.apache.jackrabbit.oak.api.CommitFailedException)8 OakBaseTest (org.apache.jackrabbit.oak.OakBaseTest)5 ConflictHook (org.apache.jackrabbit.oak.plugins.commit.ConflictHook)4 ConflictValidatorProvider (org.apache.jackrabbit.oak.plugins.commit.ConflictValidatorProvider)4 ArrayList (java.util.ArrayList)3 IndexEditorProvider (org.apache.jackrabbit.oak.plugins.index.IndexEditorProvider)3 CompositeEditorProvider (org.apache.jackrabbit.oak.spi.commit.CompositeEditorProvider)3 CompositeHook (org.apache.jackrabbit.oak.spi.commit.CompositeHook)3 EditorProvider (org.apache.jackrabbit.oak.spi.commit.EditorProvider)3 Lists.newArrayList (com.google.common.collect.Lists.newArrayList)2 Calendar (java.util.Calendar)2 CompositeIndexEditorProvider (org.apache.jackrabbit.oak.plugins.index.CompositeIndexEditorProvider)2 PropertyIndexEditorProvider (org.apache.jackrabbit.oak.plugins.index.property.PropertyIndexEditorProvider)2