blob: 0581cad02bd5dd592a9803e3aa6652c7bde8d05d [file] [log] [blame]
/*
* 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.plugins.document.mongo;
import org.apache.jackrabbit.oak.api.CommitFailedException;
import org.apache.jackrabbit.oak.plugins.document.AbstractMongoConnectionTest;
import org.apache.jackrabbit.oak.plugins.document.DocumentMK;
import org.apache.jackrabbit.oak.plugins.document.DocumentNodeStore;
import org.apache.jackrabbit.oak.plugins.document.LeaseCheckMode;
import org.apache.jackrabbit.oak.plugins.document.MongoUtils;
import org.apache.jackrabbit.oak.plugins.document.NodeDocument;
import org.apache.jackrabbit.oak.plugins.document.Revision;
import org.apache.jackrabbit.oak.plugins.document.util.MongoConnection;
import org.apache.jackrabbit.oak.plugins.document.util.Utils;
import org.apache.jackrabbit.oak.spi.commit.CommitInfo;
import org.apache.jackrabbit.oak.spi.commit.EmptyHook;
import org.apache.jackrabbit.oak.spi.state.NodeBuilder;
import org.apache.jackrabbit.oak.spi.state.NodeStore;
import org.junit.After;
import org.junit.Test;
import static org.apache.jackrabbit.oak.plugins.document.Collection.NODES;
import static org.apache.jackrabbit.oak.plugins.document.NodeDocument.COLLISIONS;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.fail;
/**
* Test for OAK-3344
*/
public class CollisionMarkerTest extends AbstractMongoConnectionTest {
private DocumentNodeStore ns1;
private DocumentNodeStore ns2;
@Override
public void setUpConnection() throws Exception {
mongoConnection = connectionFactory.getConnection();
MongoUtils.dropCollections(mongoConnection.getDBName());
mk = newDocumentMK(mongoConnection, 2);
ns1 = mk.getNodeStore();
}
@After
public void tearDown() {
ns2.dispose();
}
@Test
public void conditionalCollisionUpdate() throws Exception {
NodeBuilder b1 = ns1.getRoot().builder();
b1.child("test");
b1.child("node");
merge(ns1, b1);
ns1.runBackgroundOperations();
// initialize second node store after background ops
// on ns1. this makes sure ns2 sees all changes done so far
ns2 = newDocumentMK(connectionFactory.getConnection(), 3).getNodeStore();
b1 = ns1.getRoot().builder();
b1.child("node").child("foo");
b1.child("test").setProperty("p", 1);
merge(ns1, b1);
Revision head = ns1.getHeadRevision().getRevision(ns1.getClusterId());
NodeBuilder b2 = ns2.getRoot().builder();
b2.child("node").child("bar");
b2.child("test").setProperty("p", 2);
try {
merge(ns2, b2);
fail("must fail with CommitFailedException");
} catch (CommitFailedException e) {
// expected
}
String rootId = Utils.getIdFromPath("/");
NodeDocument root = ns2.getDocumentStore().find(NODES, rootId);
assertFalse("root document must not have a collision marker for a" +
" committed revision", root.getValueMap(COLLISIONS).containsKey(head));
}
private static DocumentMK newDocumentMK(MongoConnection c, int clusterId) {
DocumentMK mk = new DocumentMK.Builder().setAsyncDelay(0)
.setLeaseCheckMode(LeaseCheckMode.DISABLED)
.setMongoDB(c.getMongoClient(), c.getDBName())
.setClusterId(clusterId)
.open();
// do not retry on conflicts
mk.getNodeStore().setMaxBackOffMillis(0);
return mk;
}
private static void merge(NodeStore store, NodeBuilder builder)
throws CommitFailedException {
store.merge(builder, EmptyHook.INSTANCE, CommitInfo.EMPTY);
}
}