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