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 mr...@apache.org on 2017/03/20 15:50:06 UTC

svn commit: r1787796 - in /jackrabbit/oak/trunk/oak-core/src: main/java/org/apache/jackrabbit/oak/plugins/document/ test/java/org/apache/jackrabbit/oak/plugins/document/

Author: mreutegg
Date: Mon Mar 20 15:50:05 2017
New Revision: 1787796

URL: http://svn.apache.org/viewvc?rev=1787796&view=rev
Log:
OAK-4529: DocumentNodeStore does not have a repository software version range check

Added:
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/FormatVersion.java   (with props)
    jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/FormatVersionTest.java   (with props)
Modified:
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStore.java
    jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStoreTest.java

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStore.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStore.java?rev=1787796&r1=1787795&r2=1787796&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStore.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStore.java Mon Mar 20 15:50:05 2017
@@ -126,6 +126,7 @@ import org.apache.jackrabbit.oak.spi.sta
 import org.apache.jackrabbit.oak.spi.state.NodeStore;
 import org.apache.jackrabbit.oak.stats.Clock;
 import org.apache.jackrabbit.oak.stats.StatisticsProvider;
+import org.apache.jackrabbit.oak.util.OakVersion;
 import org.apache.jackrabbit.oak.util.PerfLogger;
 import org.apache.jackrabbit.stats.TimeSeriesStatsUtil;
 import org.slf4j.Logger;
@@ -142,6 +143,8 @@ public final class DocumentNodeStore
     private static final PerfLogger PERFLOG = new PerfLogger(
             LoggerFactory.getLogger(DocumentNodeStore.class.getName() + ".perf"));
 
+    public static final FormatVersion VERSION = FormatVersion.V1_8;
+
     /**
      * Do not cache more than this number of children for a document.
      */
@@ -492,6 +495,7 @@ public final class DocumentNodeStore
         } else {
             readOnlyMode = false;
         }
+        checkVersion(s, readOnlyMode);
         this.executor = builder.getExecutor();
         this.clock = builder.getClock();
 
@@ -2237,7 +2241,43 @@ public final class DocumentNodeStore
 
     //-----------------------------< internal >---------------------------------
 
-    void pushJournalEntry(Revision r) {
+    /**
+     * Checks if this node store can operate on the data in the given document
+     * store.
+     *
+     * @param store the document store.
+     * @param readOnlyMode whether this node store is in read-only mode.
+     * @throws DocumentStoreException if the versions are incompatible given the
+     *      access mode (read-write vs. read-only).
+     */
+    private static void checkVersion(DocumentStore store, boolean readOnlyMode)
+            throws DocumentStoreException {
+        FormatVersion storeVersion = FormatVersion.versionOf(store);
+        if (!VERSION.canRead(storeVersion)) {
+            throw new DocumentStoreException("Cannot open DocumentNodeStore. " +
+                    "Existing data in DocumentStore was written with more " +
+                    "recent version. Store version: " + storeVersion +
+                    ", this version: " + VERSION);
+        }
+        if (!readOnlyMode) {
+            if (storeVersion == FormatVersion.V0) {
+                // no version present. set to current version
+                VERSION.writeTo(store);
+                LOG.info("FormatVersion set to {}", VERSION);
+            } else if (!VERSION.equals(storeVersion)) {
+                // version does not match. fail the check and
+                // require a manual upgrade first
+                throw new DocumentStoreException("Cannot open DocumentNodeStore " +
+                        "in read-write mode. Existing data in DocumentStore " +
+                        "was written with older version. Store version: " +
+                        storeVersion + ", this version: " + VERSION + ". Use " +
+                        "the oak-run-" + OakVersion.getVersion() + ".jar tool " +
+                        "with the unlockUpgrade command first.");
+            }
+        }
+    }
+
+    private void pushJournalEntry(Revision r) {
         if (!changes.hasChanges()) {
             LOG.debug("Not pushing journal as there are no changes");
         } else if (store.create(JOURNAL, singletonList(changes.asUpdateOp(r)))) {

Added: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/FormatVersion.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/FormatVersion.java?rev=1787796&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/FormatVersion.java (added)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/FormatVersion.java Mon Mar 20 15:50:05 2017
@@ -0,0 +1,277 @@
+/*
+ * 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;
+
+import java.util.List;
+
+import javax.annotation.Nonnull;
+
+import com.google.common.collect.ComparisonChain;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Lists;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static org.apache.jackrabbit.oak.plugins.document.Collection.SETTINGS;
+
+/**
+ * The format version currently in use by the DocumentNodeStore and written
+ * to the underlying DocumentStore. A version {@link #canRead} the current or
+ * older versions.
+ */
+public final class FormatVersion implements Comparable<FormatVersion> {
+
+    /**
+     * A dummy version when none is available.
+     */
+    static final FormatVersion V0 = new FormatVersion(0, 0, 0);
+
+    /**
+     * Format version for Oak 1.0.
+     */
+    static final FormatVersion V1_0 = new FormatVersion(1, 0, 0);
+
+    /**
+     * Format version for Oak 1.2.
+     * <p>
+     * Changes introduced with this version:
+     * <ul>
+     *     <li>_lastRev entries are only updated for implicit changes (OAK-2131)</li>
+     * </ul>
+     */
+    static final FormatVersion V1_2 = new FormatVersion(1, 2, 0);
+
+    /**
+     * Format version for Oak 1.4.
+     * <p>
+     * Changes introduced with this version:
+     * <ul>
+     *     <li>journalGC in settings collection (OAK-4528)</li>
+     *     <li>startTime in clusterNode entries, revision vector in checkpoint (OAK-3646)</li>
+     *     <li>discovery lite with clusterView in settings collection (OAK-2844)</li>
+     * </ul>
+     */
+    static final FormatVersion V1_4 = new FormatVersion(1, 4, 0);
+
+    /**
+     * Format version for Oak 1.6.
+     * <p>
+     * Changes introduced with this version:
+     * <ul>
+     *     <li>bundle nodes into document (OAK-1312)</li>
+     *     <li>journal entries with change set summary for JCR observation (OAK-5101)</li>
+     * </ul>
+     */
+    static final FormatVersion V1_6 = new FormatVersion(1, 6, 0);
+
+    /**
+     * Format version for Oak 1.8.
+     * <p>
+     * Changes introduced with this version:
+     * <ul>
+     *     <li>SplitDocType.DEFAULT_NO_BRANCH (OAK-5869)</li>
+     * </ul>
+     */
+    static final FormatVersion V1_8 = new FormatVersion(1, 8, 0);
+
+    /**
+     * The ID of the document in the settings collection that contains the
+     * version information.
+     */
+    private static final String VERSION_ID = "version";
+
+    /**
+     * @return well known format versions.
+     */
+    public static Iterable<FormatVersion> values() {
+        return ImmutableList.of(V0, V1_0, V1_2, V1_4, V1_6, V1_8);
+    }
+
+    /**
+     * Name of the version property.
+     */
+    private static final String PROP_VERSION = "_v";
+
+    private final int major, minor, micro;
+
+    private FormatVersion(int major, int minor, int micro) {
+        this.major = major;
+        this.minor = minor;
+        this.micro = micro;
+    }
+
+    /**
+     * Returns {@code true} if {@code this} version can read data written by the
+     * {@code other} version.
+     *
+     * @param other the version the data was written in.
+     * @return {@code true} if this version can read, {@code false} otherwise.
+     */
+    public boolean canRead(FormatVersion other) {
+        return compareTo(checkNotNull(other)) >= 0;
+    }
+
+    /**
+     * Reads the {@link FormatVersion} from the given store. This method
+     * returns {@link FormatVersion#V0} if the store currently does not have a
+     * version set.
+     *
+     * @param store the store to read from.
+     * @return the format version of the store.
+     * @throws DocumentStoreException if an error occurs while reading from the
+     *          store.
+     */
+    @Nonnull
+    public static FormatVersion versionOf(@Nonnull DocumentStore store)
+            throws DocumentStoreException {
+        checkNotNull(store);
+        FormatVersion v = V0;
+        Document d = store.find(SETTINGS, VERSION_ID);
+        if (d != null) {
+            Object p = d.get(PROP_VERSION);
+            if (p != null) {
+                try {
+                    v = valueOf(p.toString());
+                } catch (IllegalArgumentException e) {
+                    throw new DocumentStoreException(e);
+                }
+            }
+        }
+        return v;
+    }
+
+    /**
+     * Writes this version to the given document store. The write operation will
+     * fail with a {@link DocumentStoreException} if the version change is
+     * considered incompatible or cannot be applied for some other reason. This
+     * includes:
+     * <ul>
+     *     <li>An attempt to downgrade the existing version</li>
+     *     <li>There are active cluster nodes using an existing version</li>
+     *     <li>The version was changed concurrently</li>
+     * </ul>
+     *
+     * @param store the document store.
+     * @return {@code true} if the version in the store was updated,
+     *      {@code false} otherwise. This method will also return {@code false}
+     *      if the version in the store equals this version and now update was
+     *      required.
+     * @throws DocumentStoreException if the write operation fails. Reasons
+     *      include: 1) an attempt to downgrade the existing version, 2) there
+     *      are active cluster nodes using an existing version, 3) the version
+     *      was changed concurrently.
+     */
+    public boolean writeTo(@Nonnull DocumentStore store)
+            throws DocumentStoreException {
+        checkNotNull(store);
+        FormatVersion v = versionOf(store);
+        if (v == this) {
+            // already on this version
+            return false;
+        }
+        if (!canRead(v)) {
+            // never downgrade
+            throw unableToWrite("Version " + this + " cannot read " + v);
+        }
+        List<Integer> active = Lists.newArrayList();
+        for (ClusterNodeInfoDocument d : ClusterNodeInfoDocument.all(store)) {
+            if (d.isActive()) {
+                active.add(d.getClusterId());
+            }
+        }
+        if (!active.isEmpty() && v != V0) {
+            throw unableToWrite("There are active cluster nodes: " + active);
+        }
+        if (v == V0) {
+            UpdateOp op = new UpdateOp(VERSION_ID, true);
+            op.set(PROP_VERSION, toString());
+            if (!store.create(SETTINGS, Lists.newArrayList(op))) {
+                throw concurrentUpdate();
+            }
+        } else {
+            UpdateOp op = new UpdateOp(VERSION_ID, false);
+            op.equals(PROP_VERSION, v.toString());
+            op.set(PROP_VERSION, toString());
+            if (store.findAndUpdate(SETTINGS, op) == null) {
+                throw concurrentUpdate();
+            }
+        }
+        return true;
+    }
+
+    /**
+     * Returns a format version for the given String representation. This method
+     * either returns one of the well known versions or an entirely new version
+     * if the version is not well known.
+     *
+     * @param s the String representation of a format version.
+     * @return the parsed format version.
+     * @throws IllegalArgumentException if the string is malformed.
+     */
+    public static FormatVersion valueOf(String s)
+            throws IllegalArgumentException {
+        String[] parts = s.split("\\.");
+        if (parts.length != 3) {
+            throw new IllegalArgumentException(s);
+        }
+        int[] elements = new int[parts.length];
+        for (int i = 0; i < parts.length; i++) {
+            try {
+                elements[i] = Integer.parseInt(parts[i]);
+            } catch (NumberFormatException e) {
+                throw new IllegalArgumentException(s);
+            }
+        }
+        FormatVersion v = new FormatVersion(elements[0], elements[1], elements[2]);
+        for (FormatVersion known : values()) {
+            if (v.equals(known)) {
+                v = known;
+                break;
+            }
+        }
+        return v;
+    }
+
+    @Override
+    public String toString() {
+        return major + "." + minor + "." + micro;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        return obj instanceof FormatVersion
+                && compareTo((FormatVersion) obj) == 0;
+    }
+
+    @Override
+    public int compareTo(@Nonnull FormatVersion other) {
+        checkNotNull(other);
+        return ComparisonChain.start()
+                .compare(major, other.major)
+                .compare(minor, other.minor)
+                .compare(micro, other.micro)
+                .result();
+    }
+
+    private static DocumentStoreException concurrentUpdate() {
+        return unableToWrite("Version was updated concurrently");
+    }
+
+    private static DocumentStoreException unableToWrite(String reason) {
+        return new DocumentStoreException(
+                "Unable to write format version. " + reason);
+    }
+}

Propchange: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/FormatVersion.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStoreTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStoreTest.java?rev=1787796&r1=1787795&r2=1787796&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStoreTest.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStoreTest.java Mon Mar 20 15:50:05 2017
@@ -19,6 +19,7 @@ package org.apache.jackrabbit.oak.plugin
 import static java.util.concurrent.TimeUnit.SECONDS;
 import static org.apache.jackrabbit.oak.api.CommitFailedException.CONSTRAINT;
 import static org.apache.jackrabbit.oak.plugins.document.Collection.NODES;
+import static org.apache.jackrabbit.oak.plugins.document.Collection.SETTINGS;
 import static org.apache.jackrabbit.oak.plugins.document.NodeDocument.MODIFIED_IN_SECS;
 import static org.apache.jackrabbit.oak.plugins.document.NodeDocument.MODIFIED_IN_SECS_RESOLUTION;
 import static org.apache.jackrabbit.oak.plugins.document.NodeDocument.NUM_REVS_THRESHOLD;
@@ -2942,6 +2943,53 @@ public class DocumentNodeStoreTest {
         assertNotNull(doc);
     }
 
+    @Test
+    public void readWriteOldVersion() throws Exception {
+        DocumentStore store = new MemoryDocumentStore();
+        FormatVersion.V1_0.writeTo(store);
+        try {
+            new DocumentMK.Builder().setDocumentStore(store).getNodeStore();
+            fail("must fail with " + DocumentStoreException.class.getSimpleName());
+        } catch (Exception e) {
+            // expected
+        }
+    }
+
+    @Test
+    public void readOnlyOldVersion() throws Exception {
+        DocumentStore store = new MemoryDocumentStore();
+        FormatVersion.V1_0.writeTo(store);
+        // initialize store with root node
+        Revision r = Revision.newRevision(1);
+        UpdateOp op = new UpdateOp(Utils.getIdFromPath("/"), true);
+        NodeDocument.setModified(op, r);
+        NodeDocument.setDeleted(op, r, false);
+        NodeDocument.setRevision(op, r, "c");
+        NodeDocument.setLastRev(op, r);
+        store.create(NODES, Lists.newArrayList(op));
+        // initialize checkpoints document
+        op = new UpdateOp("checkpoint", true);
+        store.create(SETTINGS, Lists.newArrayList(op));
+        // initialize version GC status in settings
+        op = new UpdateOp("versionGC", true);
+        store.create(SETTINGS, Lists.newArrayList(op));
+        // now try to open in read-only mode with more recent version
+        builderProvider.newBuilder().setReadOnlyMode().setDocumentStore(store).getNodeStore();
+    }
+
+    @Test
+    public void readMoreRecentVersion() throws Exception {
+        DocumentStore store = new MemoryDocumentStore();
+        FormatVersion futureVersion = FormatVersion.valueOf("999.9.9");
+        futureVersion.writeTo(store);
+        try {
+            new DocumentMK.Builder().setDocumentStore(store).getNodeStore();
+            fail("must fail with " + DocumentStoreException.class.getSimpleName());
+        } catch (DocumentStoreException e) {
+            // expected
+        }
+    }
+
     private static class WriteCountingStore extends MemoryDocumentStore {
         private final ThreadLocal<Boolean> createMulti = new ThreadLocal<>();
         int count;

Added: jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/FormatVersionTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/FormatVersionTest.java?rev=1787796&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/FormatVersionTest.java (added)
+++ jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/FormatVersionTest.java Mon Mar 20 15:50:05 2017
@@ -0,0 +1,162 @@
+/*
+ * 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;
+
+import java.util.List;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import com.google.common.collect.ImmutableList;
+
+import org.apache.jackrabbit.oak.plugins.document.memory.MemoryDocumentStore;
+import org.junit.Test;
+
+import static org.apache.jackrabbit.oak.plugins.document.Collection.SETTINGS;
+import static org.apache.jackrabbit.oak.plugins.document.FormatVersion.V0;
+import static org.apache.jackrabbit.oak.plugins.document.FormatVersion.V1_0;
+import static org.apache.jackrabbit.oak.plugins.document.FormatVersion.V1_2;
+import static org.apache.jackrabbit.oak.plugins.document.FormatVersion.V1_4;
+import static org.apache.jackrabbit.oak.plugins.document.FormatVersion.V1_6;
+import static org.apache.jackrabbit.oak.plugins.document.FormatVersion.V1_8;
+import static org.apache.jackrabbit.oak.plugins.document.FormatVersion.valueOf;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertTrue;
+
+public class FormatVersionTest {
+
+    @Test
+    public void canRead() {
+        assertTrue(V1_8.canRead(V1_8));
+        assertTrue(V1_8.canRead(V1_6));
+        assertTrue(V1_8.canRead(V1_4));
+        assertTrue(V1_8.canRead(V1_2));
+        assertTrue(V1_8.canRead(V1_0));
+        assertTrue(V1_8.canRead(V0));
+        assertFalse(V1_6.canRead(V1_8));
+        assertTrue(V1_6.canRead(V1_6));
+        assertTrue(V1_6.canRead(V1_4));
+        assertTrue(V1_6.canRead(V1_2));
+        assertTrue(V1_6.canRead(V1_0));
+        assertTrue(V1_6.canRead(V0));
+        assertFalse(V1_4.canRead(V1_8));
+        assertFalse(V1_4.canRead(V1_6));
+        assertTrue(V1_4.canRead(V1_4));
+        assertTrue(V1_4.canRead(V1_2));
+        assertTrue(V1_4.canRead(V1_0));
+        assertTrue(V1_4.canRead(V0));
+        assertFalse(V1_2.canRead(V1_8));
+        assertFalse(V1_2.canRead(V1_6));
+        assertFalse(V1_2.canRead(V1_4));
+        assertTrue(V1_2.canRead(V1_2));
+        assertTrue(V1_2.canRead(V1_0));
+        assertTrue(V1_2.canRead(V0));
+        assertFalse(V1_0.canRead(V1_8));
+        assertFalse(V1_0.canRead(V1_6));
+        assertFalse(V1_0.canRead(V1_4));
+        assertFalse(V1_0.canRead(V1_2));
+        assertTrue(V1_0.canRead(V1_0));
+        assertTrue(V1_0.canRead(V0));
+    }
+
+    @Test
+    public void toStringValueOf() {
+        for (FormatVersion v : FormatVersion.values()) {
+            String s = v.toString();
+            assertSame(v, valueOf(s));
+        }
+    }
+
+    @Test
+    public void valueOfUnknown() {
+        String s = "0.9.7";
+        FormatVersion v = valueOf(s);
+        assertEquals(s, v.toString());
+    }
+
+    @Test
+    public void versionOf() throws Exception {
+        DocumentStore store = new MemoryDocumentStore();
+        FormatVersion v = FormatVersion.versionOf(store);
+        assertSame(V0, v);
+    }
+
+    @Test
+    public void writeTo() throws Exception {
+        DocumentStore store = new MemoryDocumentStore();
+        // must not write dummy version
+        assertFalse(V0.writeTo(store));
+        // upgrade
+        for (FormatVersion v : ImmutableList.of(V1_0, V1_2, V1_4, V1_6, V1_8)) {
+            assertTrue(v.writeTo(store));
+            assertSame(v, FormatVersion.versionOf(store));
+        }
+    }
+
+    @Test(expected = DocumentStoreException.class)
+    public void downgrade() throws Exception {
+        DocumentStore store = new MemoryDocumentStore();
+        assertTrue(V1_4.writeTo(store));
+        // must not downgrade
+        V1_2.writeTo(store);
+    }
+
+    @Test(expected = DocumentStoreException.class)
+    public void activeClusterNodes() throws Exception {
+        DocumentStore store = new MemoryDocumentStore();
+        V1_0.writeTo(store);
+        ClusterNodeInfo info = ClusterNodeInfo.getInstance(store, 1);
+        info.renewLease();
+        V1_2.writeTo(store);
+    }
+
+    @Test(expected = DocumentStoreException.class)
+    public void concurrentUpdate1() throws Exception {
+        DocumentStore store = new MemoryDocumentStore() {
+            private final AtomicBoolean once = new AtomicBoolean(false);
+            @Override
+            public <T extends Document> T findAndUpdate(Collection<T> collection,
+                                                        UpdateOp update) {
+                if (collection == SETTINGS
+                        && !once.getAndSet(true)) {
+                    V1_2.writeTo(this);
+                }
+                return super.findAndUpdate(collection, update);
+            }
+        };
+        V1_0.writeTo(store);
+        V1_2.writeTo(store);
+    }
+
+    @Test(expected = DocumentStoreException.class)
+    public void concurrentUpdate2() throws Exception {
+        DocumentStore store = new MemoryDocumentStore() {
+            private final AtomicBoolean once = new AtomicBoolean(false);
+
+            @Override
+            public <T extends Document> boolean create(Collection<T> collection,
+                                                       List<UpdateOp> updateOps) {
+                if (collection == SETTINGS
+                        && !once.getAndSet(true)) {
+                    V1_0.writeTo(this);
+                }
+                return super.create(collection, updateOps);
+            }
+        };
+        V1_0.writeTo(store);
+    }
+}

Propchange: jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/FormatVersionTest.java
------------------------------------------------------------------------------
    svn:eol-style = native



Re: svn commit: r1787796 - in /jackrabbit/oak/trunk/oak-core/src: main/java/org/apache/jackrabbit/oak/plugins/document/ test/java/org/apache/jackrabbit/oak/plugins/document/

Posted by Julian Reschke <ju...@gmx.de>.
On 2017-03-21 05:49, Chetan Mehrotra wrote:
> On Mon, Mar 20, 2017 at 9:20 PM,  <mr...@apache.org> wrote:
>> +     */
>> +    private static void checkVersion(DocumentStore store, boolean readOnlyMode)
>> +            throws DocumentStoreException {
>> +        FormatVersion storeVersion = FormatVersion.versionOf(store);
>
> Would be good to also log the current FormatVersion on system startup
> at info level

yes, and maybe even at shutdown time. This helps when looking a log file 
that contains just a shutdown/startup message.

Best regards, Julian


Re: svn commit: r1787796 - in /jackrabbit/oak/trunk/oak-core/src: main/java/org/apache/jackrabbit/oak/plugins/document/ test/java/org/apache/jackrabbit/oak/plugins/document/

Posted by Chetan Mehrotra <ch...@gmail.com>.
On Mon, Mar 20, 2017 at 9:20 PM,  <mr...@apache.org> wrote:
> +     */
> +    private static void checkVersion(DocumentStore store, boolean readOnlyMode)
> +            throws DocumentStoreException {
> +        FormatVersion storeVersion = FormatVersion.versionOf(store);

Would be good to also log the current FormatVersion on system startup
at info level

Chetan Mehrotra