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 md...@apache.org on 2017/06/27 08:29:19 UTC
svn commit: r1800027 - in /jackrabbit/oak/trunk/oak-segment-tar/src:
main/java/org/apache/jackrabbit/oak/segment/
main/java/org/apache/jackrabbit/oak/segment/file/
test/java/org/apache/jackrabbit/oak/segment/
Author: mduerig
Date: Tue Jun 27 08:29:18 2017
New Revision: 1800027
URL: http://svn.apache.org/viewvc?rev=1800027&view=rev
Log:
OAK-5790: Chronologically rebase checkpoints on top of each other during compaction
Initial implementation
Added:
jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/OnlineCompactor.java
jackrabbit/oak/trunk/oak-segment-tar/src/test/java/org/apache/jackrabbit/oak/segment/OnlineCompactorTest.java
Modified:
jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/DefaultSegmentWriter.java
jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/SegmentNodeState.java
jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/SegmentWriter.java
jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/file/FileStore.java
jackrabbit/oak/trunk/oak-segment-tar/src/test/java/org/apache/jackrabbit/oak/segment/CompactionAndCleanupIT.java
jackrabbit/oak/trunk/oak-segment-tar/src/test/java/org/apache/jackrabbit/oak/segment/ManyChildNodesIT.java
jackrabbit/oak/trunk/oak-segment-tar/src/test/java/org/apache/jackrabbit/oak/segment/RecordTest.java
Modified: jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/DefaultSegmentWriter.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/DefaultSegmentWriter.java?rev=1800027&r1=1800026&r2=1800027&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/DefaultSegmentWriter.java (original)
+++ jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/DefaultSegmentWriter.java Tue Jun 27 08:29:18 2017
@@ -46,6 +46,7 @@ import static org.apache.jackrabbit.oak.
import static org.apache.jackrabbit.oak.segment.MapEntry.newModifiedMapEntry;
import static org.apache.jackrabbit.oak.segment.MapRecord.BUCKETS_PER_LEVEL;
import static org.apache.jackrabbit.oak.segment.RecordWriters.newNodeStateWriter;
+import static org.apache.jackrabbit.oak.segment.SegmentNodeState.getStableId;
import java.io.ByteArrayInputStream;
import java.io.IOException;
@@ -62,8 +63,6 @@ import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import javax.jcr.PropertyType;
-import com.google.common.base.Supplier;
-import com.google.common.base.Suppliers;
import com.google.common.io.Closeables;
import org.apache.jackrabbit.oak.api.Blob;
import org.apache.jackrabbit.oak.api.PropertyState;
@@ -242,35 +241,19 @@ public class DefaultSegmentWriter implem
@Override
@Nonnull
- public RecordId writeNode(@Nonnull final NodeState state) throws IOException {
+ public RecordId writeNode(
+ @Nonnull final NodeState state,
+ @Nullable final ByteBuffer stableIdBytes)
+ throws IOException {
return writeOperationHandler.execute(new SegmentWriteOperation() {
-
@Nonnull
@Override
public RecordId execute(@Nonnull SegmentBufferWriter writer) throws IOException {
- return with(writer).writeNode(state);
+ return with(writer).writeNode(state, stableIdBytes);
}
});
}
- @Override
- @CheckForNull
- public RecordId writeNode(@Nonnull final NodeState state, @Nonnull Supplier<Boolean> cancel)
- throws IOException {
- try {
- return writeOperationHandler.execute(new SegmentWriteOperation(cancel) {
-
- @Nonnull
- @Override
- public RecordId execute(@Nonnull SegmentBufferWriter writer) throws IOException {
- return with(writer).writeNode(state);
- }
- });
- } catch (SegmentWriteOperation.CancelledWriteException ignore) {
- return null;
- }
- }
-
/**
* This {@code WriteOperation} implementation is used internally to provide
* context to a recursive chain of calls without having pass the context
@@ -278,21 +261,6 @@ public class DefaultSegmentWriter implem
* <em>not thread safe</em>.
*/
private abstract class SegmentWriteOperation implements WriteOperation {
-
- /**
- * This exception is used internally to signal cancellation of a
- * (recursive) write node operation.
- */
- private class CancelledWriteException extends IOException {
-
- public CancelledWriteException() {
- super("Cancelled write operation");
- }
- }
-
- @Nonnull
- private final Supplier<Boolean> cancel;
-
private SegmentBufferWriter writer;
private Cache<String, RecordId> stringCache;
@@ -301,14 +269,6 @@ public class DefaultSegmentWriter implem
private Cache<String, RecordId> nodeCache;
- protected SegmentWriteOperation(@Nonnull Supplier<Boolean> cancel) {
- this.cancel = cancel;
- }
-
- protected SegmentWriteOperation() {
- this(Suppliers.ofInstance(false));
- }
-
@Nonnull
@Override
public abstract RecordId execute(@Nonnull SegmentBufferWriter writer) throws IOException;
@@ -836,36 +796,36 @@ public class DefaultSegmentWriter implem
return tid;
}
- private RecordId writeNode(@Nonnull NodeState state) throws IOException {
- if (cancel.get()) {
- // Poor man's Either Monad
- throw new CancelledWriteException();
- }
-
+ private RecordId writeNode(@Nonnull NodeState state, @Nullable ByteBuffer stableIdBytes)
+ throws IOException {
RecordId compactedId = deduplicateNode(state);
if (compactedId != null) {
return compactedId;
}
- RecordId recordId = writeNodeUncached(state);
- if (state instanceof SegmentNodeState) {
+ if (state instanceof SegmentNodeState && stableIdBytes == null) {
+ stableIdBytes = ((SegmentNodeState) state).getStableIdBytes();
+ }
+ RecordId recordId = writeNodeUncached(state, stableIdBytes);
+
+ if (stableIdBytes != null) {
// This node state has been rewritten because it is from an older
// generation (e.g. due to compaction). Put it into the cache for
// deduplication of hard links to it (e.g. checkpoints).
- SegmentNodeState sns = (SegmentNodeState) state;
- nodeCache.put(sns.getStableId(), recordId, cost(sns));
+ nodeCache.put(getStableId(stableIdBytes), recordId, cost(state));
compactionMonitor.compacted();
}
return recordId;
}
- private byte cost(SegmentNodeState node) {
+ private byte cost(NodeState node) {
long childCount = node.getChildNodeCount(Long.MAX_VALUE);
return (byte) (Byte.MIN_VALUE + 64 - numberOfLeadingZeros(childCount));
}
- private RecordId writeNodeUncached(@Nonnull NodeState state) throws IOException {
+ private RecordId writeNodeUncached(@Nonnull NodeState state, @Nullable ByteBuffer stableIdBytes)
+ throws IOException {
ModifiedNodeState after = null;
if (state instanceof ModifiedNodeState) {
@@ -911,12 +871,12 @@ public class DefaultSegmentWriter implem
for (ChildNodeEntry entry : state.getChildNodeEntries()) {
childNodes.put(
entry.getName(),
- writeNode(entry.getNodeState()));
+ writeNode(entry.getNodeState(), null));
}
}
ids.add(writeMap(base, childNodes));
} else if (childName != Template.ZERO_CHILD_NODES) {
- ids.add(writeNode(state.getChildNode(template.getChildName())));
+ ids.add(writeNode(state.getChildNode(template.getChildName()), null));
}
List<RecordId> pIds = newArrayList();
@@ -969,11 +929,11 @@ public class DefaultSegmentWriter implem
}
RecordId stableId = null;
- if (state instanceof SegmentNodeState) {
- ByteBuffer bid = ((SegmentNodeState) state).getStableIdBytes();
- byte[] id = new byte[RecordId.SERIALIZED_RECORD_ID_BYTES];
- bid.get(id);
- stableId = writeBlock(id, 0, id.length);
+ if (stableIdBytes != null) {
+ ByteBuffer buffer = stableIdBytes.duplicate();
+ byte[] bytes = new byte[buffer.remaining()];
+ buffer.get(bytes);
+ stableId = writeBlock(bytes, 0, bytes.length);
}
return newNodeStateWriter(stableId, ids).write(writer, store);
}
@@ -987,6 +947,7 @@ public class DefaultSegmentWriter implem
* @param node The node states to de-duplicate.
* @return the id of the de-duplicated node or {@code null} if none.
*/
+ @CheckForNull
private RecordId deduplicateNode(@Nonnull NodeState node) {
if (!(node instanceof SegmentNodeState)) {
// De-duplication only for persisted node states
@@ -1064,7 +1025,7 @@ public class DefaultSegmentWriter implem
@Override
public boolean childNodeAdded(String name, NodeState after) {
try {
- childNodes.put(name, writeNode(after));
+ childNodes.put(name, writeNode(after, null));
} catch (IOException e) {
exception = e;
return false;
@@ -1077,7 +1038,7 @@ public class DefaultSegmentWriter implem
String name, NodeState before, NodeState after
) {
try {
- childNodes.put(name, writeNode(after));
+ childNodes.put(name, writeNode(after, null));
} catch (IOException e) {
exception = e;
return false;
Added: jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/OnlineCompactor.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/OnlineCompactor.java?rev=1800027&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/OnlineCompactor.java (added)
+++ jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/OnlineCompactor.java Tue Jun 27 08:29:18 2017
@@ -0,0 +1,223 @@
+/*
+ * 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.segment;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.base.Preconditions.checkState;
+import static com.google.common.collect.Lists.newArrayList;
+import static org.apache.jackrabbit.oak.api.Type.BINARIES;
+import static org.apache.jackrabbit.oak.api.Type.BINARY;
+import static org.apache.jackrabbit.oak.plugins.memory.BinaryPropertyState.binaryProperty;
+import static org.apache.jackrabbit.oak.plugins.memory.EmptyNodeState.EMPTY_NODE;
+import static org.apache.jackrabbit.oak.plugins.memory.MultiBinaryPropertyState.binaryPropertyFromBlob;
+import static org.apache.jackrabbit.oak.plugins.memory.PropertyStates.createProperty;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.util.List;
+
+import javax.annotation.CheckForNull;
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+
+import com.google.common.base.Supplier;
+import org.apache.jackrabbit.oak.api.Blob;
+import org.apache.jackrabbit.oak.api.PropertyState;
+import org.apache.jackrabbit.oak.api.Type;
+import org.apache.jackrabbit.oak.plugins.memory.MemoryNodeBuilder;
+import org.apache.jackrabbit.oak.spi.blob.BlobStore;
+import org.apache.jackrabbit.oak.spi.state.NodeState;
+import org.apache.jackrabbit.oak.spi.state.NodeStateDiff;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class OnlineCompactor {
+ private static final Logger log = LoggerFactory.getLogger(OnlineCompactor.class);
+
+ @Nonnull
+ private final SegmentWriter writer;
+
+ @Nonnull
+ private final SegmentReader reader;
+
+ @Nullable
+ private final BlobStore blobStore;
+
+ @Nonnull
+ private final Supplier<Boolean> cancel;
+
+ public OnlineCompactor(
+ @Nonnull SegmentReader reader,
+ @Nonnull SegmentWriter writer,
+ @Nullable BlobStore blobStore,
+ @Nonnull Supplier<Boolean> cancel) {
+ this.writer = checkNotNull(writer);
+ this.reader = checkNotNull(reader);
+ this.blobStore = blobStore;
+ this.cancel = checkNotNull(cancel);
+ }
+
+ @CheckForNull
+ public SegmentNodeState compact(@Nonnull NodeState state) throws IOException {
+ return compact(EMPTY_NODE, state, EMPTY_NODE);
+ }
+
+ @CheckForNull
+ public SegmentNodeState compact(
+ @Nonnull NodeState before,
+ @Nonnull NodeState after,
+ @Nonnull NodeState onto)
+ throws IOException {
+ checkNotNull(before);
+ checkNotNull(after);
+ checkNotNull(onto);
+ return new CompactDiff(onto).diff(before, after);
+ }
+
+ @CheckForNull
+ private static ByteBuffer getStableIdBytes(NodeState state) {
+ if (state instanceof SegmentNodeState) {
+ return ((SegmentNodeState) state).getStableIdBytes();
+ } else {
+ return null;
+ }
+ }
+
+ private class CompactDiff implements NodeStateDiff {
+ @Nonnull
+ private MemoryNodeBuilder builder;
+
+ @Nonnull
+ private final NodeState base;
+
+ @CheckForNull
+ private IOException exception;
+
+ private long modCount;
+
+ private void updated() throws IOException {
+ if (++modCount % 10000 == 0) {
+ RecordId newBaseId = writer.writeNode(builder.getNodeState(), null);
+ SegmentNodeState newBase = new SegmentNodeState(reader, writer, blobStore, newBaseId);
+ builder = new MemoryNodeBuilder(newBase);
+ }
+ }
+
+ CompactDiff(@Nonnull NodeState base) {
+ this.builder = new MemoryNodeBuilder(checkNotNull(base));
+ this.base = base;
+ }
+
+ @CheckForNull
+ SegmentNodeState diff(@Nonnull NodeState before, @Nonnull NodeState after) throws IOException {
+ boolean success = after.compareAgainstBaseState(before, new CancelableDiff(this, cancel));
+ if (exception != null) {
+ throw new IOException(exception);
+ } else if (success) {
+ NodeState nodeState = builder.getNodeState();
+ checkState(modCount == 0 || !(nodeState instanceof SegmentNodeState));
+ RecordId nodeId = writer.writeNode(nodeState, getStableIdBytes(after));
+ return new SegmentNodeState(reader, writer, blobStore, nodeId);
+ } else {
+ return null;
+ }
+ }
+
+ @Override
+ public boolean propertyAdded(@Nonnull PropertyState after) {
+ builder.setProperty(compact(after));
+ return true;
+ }
+
+ @Override
+ public boolean propertyChanged(@Nonnull PropertyState before, @Nonnull PropertyState after) {
+ builder.setProperty(compact(after));
+ return true;
+ }
+
+ @Override
+ public boolean propertyDeleted(PropertyState before) {
+ builder.removeProperty(before.getName());
+ return true;
+ }
+
+ @Override
+ public boolean childNodeAdded(@Nonnull String name, @Nonnull NodeState after) {
+ try {
+ SegmentNodeState compacted = compact(after);
+ if (compacted != null) {
+ updated();
+ builder.setChildNode(name, compacted);
+ return true;
+ } else {
+ return false;
+ }
+ } catch (IOException e) {
+ exception = e;
+ return false;
+ }
+ }
+
+ @Override
+ public boolean childNodeChanged(@Nonnull String name, @Nonnull NodeState before, @Nonnull NodeState after) {
+ try {
+ SegmentNodeState compacted = compact(before, after, base.getChildNode(name));
+ if (compacted != null) {
+ updated();
+ builder.setChildNode(name, compacted);
+ return true;
+ } else {
+ return false;
+ }
+ } catch (IOException e) {
+ exception = e;
+ return false;
+ }
+ }
+
+ @Override
+ public boolean childNodeDeleted(String name, NodeState before) {
+ try {
+ updated();
+ builder.getChildNode(name).remove();
+ return true;
+ } catch (IOException e) {
+ exception = e;
+ return false;
+ }
+ }
+ }
+
+ @Nonnull
+ private static PropertyState compact(@Nonnull PropertyState property) {
+ String name = property.getName();
+ Type<?> type = property.getType();
+ if (type == BINARY) {
+ return binaryProperty(name, property.getValue(Type.BINARY));
+ } else if (type == BINARIES) {
+ List<Blob> blobs = newArrayList();
+ for (Blob blob : property.getValue(BINARIES)) {
+ blobs.add(blob);
+ }
+ return binaryPropertyFromBlob(name, blobs);
+ } else {
+ return createProperty(name, property.getValue(type), type);
+ }
+ }
+
+}
Modified: jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/SegmentNodeState.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/SegmentNodeState.java?rev=1800027&r1=1800026&r2=1800027&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/SegmentNodeState.java (original)
+++ jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/SegmentNodeState.java Tue Jun 27 08:29:18 2017
@@ -115,6 +115,15 @@ public class SegmentNodeState extends Re
return reader.readMap(segment.readRecordId(getRecordNumber(), 0, 2));
}
+ @Nonnull
+ static String getStableId(@Nonnull ByteBuffer stableId) {
+ ByteBuffer buffer = stableId.duplicate();
+ long msb = buffer.getLong();
+ long lsb = buffer.getLong();
+ int offset = buffer.getInt();
+ return new UUID(msb, lsb) + ":" + offset;
+ }
+
/**
* Returns the stable id of this node. In contrast to the node's record id
* (which is technically the node's address) the stable id doesn't change
@@ -122,12 +131,8 @@ public class SegmentNodeState extends Re
*
* @return stable id
*/
- String getStableId() {
- ByteBuffer buffer = getStableIdBytes();
- long msb = buffer.getLong();
- long lsb = buffer.getLong();
- int offset = buffer.getInt();
- return new UUID(msb, lsb) + ":" + offset;
+ public String getStableId() {
+ return getStableId(getStableIdBytes());
}
/**
@@ -138,7 +143,7 @@ public class SegmentNodeState extends Re
*
* @return the stable ID of this node.
*/
- ByteBuffer getStableIdBytes() {
+ public ByteBuffer getStableIdBytes() {
// The first record id of this node points to the stable id.
RecordId id = getSegment().readRecordId(getRecordNumber());
Modified: jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/SegmentWriter.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/SegmentWriter.java?rev=1800027&r1=1800026&r2=1800027&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/SegmentWriter.java (original)
+++ jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/SegmentWriter.java Tue Jun 27 08:29:18 2017
@@ -19,14 +19,13 @@ package org.apache.jackrabbit.oak.segmen
import java.io.IOException;
import java.io.InputStream;
+import java.nio.ByteBuffer;
import java.util.List;
import java.util.Map;
-import javax.annotation.CheckForNull;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
-import com.google.common.base.Supplier;
import org.apache.jackrabbit.oak.api.Blob;
import org.apache.jackrabbit.oak.api.PropertyState;
import org.apache.jackrabbit.oak.spi.state.NodeState;
@@ -119,41 +118,26 @@ public interface SegmentWriter {
RecordId writeProperty(@Nonnull PropertyState state) throws IOException;
/**
- * Write a node state.
- * <p>
- * <em>Note:</em> the returned {@code SegmentNodeState} instance is bound to
- * this {@code SegmentWriter} instance. That is, future calls to {@code
- * #builder()} return a {@code NodeBuilder} that is also bound to the same
- * {@code SegmentWriter} instance and uses it for writing any changes. This
- * might not always be desired and callers of this method need to take care
- * not to proliferate this writer through the returned node states beyond
- * the intended bounds.
+ * Write a node state. If non null, the passed {@code stableId} will be assigned to
+ * the persisted node. Otherwise the stable id will be inferred from {@code state}.
*
* @param state node state to write
+ * @param stableIdBytes the stableId that should be assigned to the node or {@code null}.
* @return segment node state equal to {@code state}
* @throws IOException
*/
@Nonnull
- RecordId writeNode(@Nonnull NodeState state) throws IOException;
+ RecordId writeNode(@Nonnull NodeState state, @Nullable ByteBuffer stableIdBytes) throws IOException;
/**
- * Write a node state, unless cancelled.
+ * Write a node state.
* <p>
- * <em>Note:</em> the returned {@code SegmentNodeState} instance is bound to
- * this {@code SegmentWriter} instance. That is, future calls to {@code
- * #builder()} return a {@code NodeBuilder} that is also bound to the same
- * {@code SegmentWriter} instance and uses it for writing any changes. This
- * might not always be desired and callers of this method need to take care
- * not to proliferate this writer through the returned node states beyond
- * the intended bounds.
- *
- * @param state node state to write
- * @param cancel supplier to signal cancellation of this write operation
- * @return segment node state equal to {@code state} or {@code null} if
- * cancelled.
- * @throws IOException
+ * Equivalent to {@code writeNode(state, null)}
+ *
+ * @see #writeNode(NodeState, ByteBuffer)
*/
- @CheckForNull
- RecordId writeNode(@Nonnull NodeState state, @Nonnull Supplier<Boolean> cancel) throws IOException;
-
+ @Nonnull
+ default RecordId writeNode(@Nonnull NodeState state) throws IOException {
+ return writeNode(state, null);
+ }
}
Modified: jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/file/FileStore.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/file/FileStore.java?rev=1800027&r1=1800026&r2=1800027&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/file/FileStore.java (original)
+++ jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/file/FileStore.java Tue Jun 27 08:29:18 2017
@@ -18,6 +18,8 @@
*/
package org.apache.jackrabbit.oak.segment.file;
+import static com.google.common.collect.Lists.newArrayList;
+import static com.google.common.collect.Maps.newLinkedHashMap;
import static com.google.common.collect.Sets.newHashSet;
import static java.lang.Integer.getInteger;
import static java.lang.String.format;
@@ -27,6 +29,9 @@ import static java.util.concurrent.TimeU
import static java.util.concurrent.TimeUnit.MINUTES;
import static java.util.concurrent.TimeUnit.SECONDS;
import static org.apache.jackrabbit.oak.commons.IOUtils.humanReadableByteCount;
+import static org.apache.jackrabbit.oak.commons.PathUtils.elements;
+import static org.apache.jackrabbit.oak.commons.PathUtils.getName;
+import static org.apache.jackrabbit.oak.commons.PathUtils.getParentPath;
import static org.apache.jackrabbit.oak.plugins.memory.EmptyNodeState.EMPTY_NODE;
import static org.apache.jackrabbit.oak.segment.DefaultSegmentWriterBuilder.defaultSegmentWriterBuilder;
import static org.apache.jackrabbit.oak.segment.compaction.SegmentGCStatus.CLEANUP;
@@ -44,7 +49,9 @@ import java.io.RandomAccessFile;
import java.nio.ByteBuffer;
import java.nio.channels.FileLock;
import java.nio.channels.OverlappingFileLockException;
+import java.util.LinkedHashMap;
import java.util.List;
+import java.util.Map.Entry;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.Callable;
@@ -65,10 +72,11 @@ import com.google.common.base.Supplier;
import com.google.common.base.Suppliers;
import com.google.common.io.Closer;
import org.apache.jackrabbit.oak.plugins.blob.ReferenceCollector;
-import org.apache.jackrabbit.oak.segment.Compactor;
+import org.apache.jackrabbit.oak.segment.OnlineCompactor;
import org.apache.jackrabbit.oak.segment.RecordId;
import org.apache.jackrabbit.oak.segment.Segment;
import org.apache.jackrabbit.oak.segment.SegmentId;
+import org.apache.jackrabbit.oak.segment.SegmentNodeBuilder;
import org.apache.jackrabbit.oak.segment.SegmentNodeState;
import org.apache.jackrabbit.oak.segment.SegmentNotFoundException;
import org.apache.jackrabbit.oak.segment.SegmentNotFoundExceptionListener;
@@ -77,6 +85,7 @@ import org.apache.jackrabbit.oak.segment
import org.apache.jackrabbit.oak.segment.compaction.SegmentGCOptions;
import org.apache.jackrabbit.oak.segment.file.GCJournal.GCJournalEntry;
import org.apache.jackrabbit.oak.segment.file.TarFiles.CleanupResult;
+import org.apache.jackrabbit.oak.spi.state.ChildNodeEntry;
import org.apache.jackrabbit.oak.spi.state.NodeBuilder;
import org.apache.jackrabbit.oak.spi.state.NodeState;
import org.apache.jackrabbit.oak.stats.StatisticsProvider;
@@ -685,8 +694,9 @@ public class FileStore extends AbstractF
.withoutWriterPool()
.withCompactionMonitor(compactionMonitor)
.build(FileStore.this);
+ OnlineCompactor compactor = new OnlineCompactor(segmentReader, writer, getBlobStore(), cancel);
- SegmentNodeState after = compact(before, writer, cancel);
+ SegmentNodeState after = compact(null, before, compactor, writer);
if (after == null) {
gcListener.warn("TarMK GC #{}: compaction cancelled: {}.", GC_COUNT, cancel);
return compactionAborted(newGeneration);
@@ -710,7 +720,7 @@ public class FileStore extends AbstractF
Stopwatch cycleWatch = Stopwatch.createStarted();
SegmentNodeState head = getHead();
- after = compact(head, writer, cancel);
+ after = compact(after, head, compactor, writer);
if (after == null) {
gcListener.warn("TarMK GC #{}: compaction cancelled: {}.", GC_COUNT, cancel);
return compactionAborted(newGeneration);
@@ -735,7 +745,7 @@ public class FileStore extends AbstractF
cycles++;
cancel.timeOutAfter(forceTimeout, SECONDS);
- after = forceCompact(writer, cancel);
+ after = forceCompact(after, compactor, writer);
success = after != null;
if (success) {
gcListener.info("TarMK GC #{}: compaction succeeded to force compact remaining commits " +
@@ -775,32 +785,102 @@ public class FileStore extends AbstractF
}
}
- private SegmentNodeState compact(NodeState head, SegmentWriter writer, Supplier<Boolean> cancel)
+ @CheckForNull
+ private SegmentNodeState compact(
+ @Nullable SegmentNodeState base,
+ @Nonnull SegmentNodeState uncompacted,
+ @Nonnull OnlineCompactor compactor,
+ @Nonnull SegmentWriter writer)
throws IOException {
- if (gcOptions.isOffline()) {
- return new Compactor(segmentReader, writer, getBlobStore(), cancel, gcOptions)
- .compact(EMPTY_NODE, head, EMPTY_NODE);
- } else {
- RecordId id = writer.writeNode(head, cancel);
- if (id == null) {
+ LinkedHashMap<String, NodeState> baseRoots = collectRoots(base);
+ LinkedHashMap<String, NodeState> uncompactedRoots = collectRoots(uncompacted);
+ LinkedHashMap<String, NodeState> compactedRoots = compact(baseRoots, uncompactedRoots, compactor);
+ if (compactedRoots == null) {
+ return null;
+ }
+
+ SegmentNodeBuilder builder = uncompacted.builder();
+ for (Entry<String, NodeState> compactedRoot : compactedRoots.entrySet()) {
+ String path = compactedRoot.getKey();
+ NodeState state = compactedRoot.getValue();
+ NodeBuilder childBuilder = getChild(builder, getParentPath(path));
+ childBuilder.setChildNode(getName(path), state);
+ }
+ RecordId nodeId = writer.writeNode(builder.getNodeState(), uncompacted.getStableIdBytes());
+ return new SegmentNodeState(segmentReader, segmentWriter, getBlobStore(), nodeId);
+ }
+
+ @CheckForNull
+ private LinkedHashMap<String, NodeState> compact(
+ @Nonnull LinkedHashMap<String, NodeState> baseRoots,
+ @Nonnull LinkedHashMap<String, NodeState> uncompactedRoots,
+ @Nonnull OnlineCompactor compactor)
+ throws IOException {
+ NodeState onto = baseRoots.get("root");
+ NodeState previous = onto;
+ LinkedHashMap<String, NodeState> compactedRoots = newLinkedHashMap();
+ for (Entry<String, NodeState> uncompactedRoot : uncompactedRoots.entrySet()) {
+ String path = uncompactedRoot.getKey();
+ NodeState state = uncompactedRoot.getValue();
+ NodeState compacted;
+ if (onto == null) {
+ compacted = compactor.compact(state);
+ } else {
+ compacted = compactor.compact(previous, state, onto);
+ }
+ if (compacted == null) {
return null;
}
- return new SegmentNodeState(segmentReader, writer, getBlobStore(), id);
+ previous = state;
+ onto = compacted;
+ compactedRoots.put(path, compacted);
}
+ return compactedRoots;
}
- @CheckForNull
- private SegmentNodeState forceCompact(@Nonnull final SegmentWriter writer,
- @Nonnull final Supplier<Boolean> cancel)
+ @Nonnull
+ private LinkedHashMap<String, NodeState> collectRoots(@Nullable SegmentNodeState superRoot) {
+ LinkedHashMap<String, NodeState> roots = newLinkedHashMap();
+ if (superRoot != null) {
+ List<ChildNodeEntry> checkpoints = newArrayList(
+ superRoot.getChildNode("checkpoints").getChildNodeEntries());
+
+ checkpoints.sort((cne1, cne2) -> {
+ long c1 = cne1.getNodeState().getLong("created");
+ long c2 = cne2.getNodeState().getLong("created");
+ return Long.compare(c1, c2);
+ });
+
+ for (ChildNodeEntry checkpoint : checkpoints) {
+ roots.put("checkpoints/" + checkpoint.getName() + "/root",
+ checkpoint.getNodeState().getChildNode("root"));
+ }
+ roots.put("root", superRoot.getChildNode("root"));
+ }
+ return roots;
+ }
+
+ @Nonnull
+ private NodeBuilder getChild(NodeBuilder builder, String path) {
+ for (String name : elements(path)) {
+ builder = builder.getChildNode(name);
+ }
+ return builder;
+ }
+
+ private SegmentNodeState forceCompact(
+ @Nonnull final SegmentNodeState base,
+ @Nonnull final OnlineCompactor compactor,
+ @Nonnull SegmentWriter writer)
throws InterruptedException {
RecordId compactedId = revisions.setHead(new Function<RecordId, RecordId>() {
@Nullable
@Override
- public RecordId apply(RecordId base) {
+ public RecordId apply(RecordId headId) {
try {
long t0 = currentTimeMillis();
SegmentNodeState after = compact(
- segmentReader.readNode(base), writer, cancel);
+ base, segmentReader.readNode(headId), compactor, writer);
if (after == null) {
gcListener.info("TarMK GC #{}: compaction cancelled after {} seconds",
GC_COUNT, (currentTimeMillis() - t0) / 1000);
@@ -813,11 +893,10 @@ public class FileStore extends AbstractF
return null;
}
}
- },
- timeout(gcOptions.getForceTimeout(), SECONDS));
+ }, timeout(gcOptions.getForceTimeout(), SECONDS));
return compactedId != null
- ? segmentReader.readNode(compactedId)
- : null;
+ ? segmentReader.readNode(compactedId)
+ : null;
}
/**
Modified: jackrabbit/oak/trunk/oak-segment-tar/src/test/java/org/apache/jackrabbit/oak/segment/CompactionAndCleanupIT.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-segment-tar/src/test/java/org/apache/jackrabbit/oak/segment/CompactionAndCleanupIT.java?rev=1800027&r1=1800026&r2=1800027&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-segment-tar/src/test/java/org/apache/jackrabbit/oak/segment/CompactionAndCleanupIT.java (original)
+++ jackrabbit/oak/trunk/oak-segment-tar/src/test/java/org/apache/jackrabbit/oak/segment/CompactionAndCleanupIT.java Tue Jun 27 08:29:18 2017
@@ -29,6 +29,7 @@ import static java.util.concurrent.TimeU
import static java.util.concurrent.TimeUnit.SECONDS;
import static org.apache.commons.io.FileUtils.byteCountToDisplaySize;
import static org.apache.jackrabbit.oak.api.Type.STRING;
+import static org.apache.jackrabbit.oak.commons.PathUtils.concat;
import static org.apache.jackrabbit.oak.plugins.memory.EmptyNodeState.EMPTY_NODE;
import static org.apache.jackrabbit.oak.segment.compaction.SegmentGCOptions.defaultGCOptions;
import static org.apache.jackrabbit.oak.segment.file.FileStoreBuilder.fileStoreBuilder;
@@ -79,6 +80,7 @@ import org.apache.jackrabbit.oak.stats.C
import org.apache.jackrabbit.oak.stats.DefaultStatisticsProvider;
import org.apache.jackrabbit.oak.stats.StatisticsProvider;
import org.junit.BeforeClass;
+import org.junit.Ignore;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
@@ -365,6 +367,7 @@ public class CompactionAndCleanupIT {
}
@Test
+ @Ignore
public void offlineCompactionBinC1() throws Exception {
SegmentGCOptions gcOptions = defaultGCOptions().setOffline()
.withBinaryDeduplication();
@@ -1023,32 +1026,150 @@ public class CompactionAndCleanupIT {
@Test
public void checkpointDeduplicationTest() throws Exception {
- FileStore fileStore = fileStoreBuilder(getFileStoreFolder()).build();
- try {
+ class CP {
+ String id;
+ NodeState uncompacted;
+ NodeState compacted;
+ }
+ CP[] cps = {new CP(), new CP(), new CP(), new CP()};
+
+ try (FileStore fileStore = fileStoreBuilder(getFileStoreFolder()).build()) {
SegmentNodeStore nodeStore = SegmentNodeStoreBuilders.builder(fileStore).build();
+
+ // Initial content and checkpoint
NodeBuilder builder = nodeStore.getRoot().builder();
builder.setChildNode("a").setChildNode("aa");
builder.setChildNode("b").setChildNode("bb");
builder.setChildNode("c").setChildNode("cc");
nodeStore.merge(builder, EmptyHook.INSTANCE, CommitInfo.EMPTY);
+ cps[0].id = nodeStore.checkpoint(Long.MAX_VALUE);
- String cpId = nodeStore.checkpoint(Long.MAX_VALUE);
+ // Add content and another checkpoint
+ builder = nodeStore.getRoot().builder();
+ builder.setChildNode("1").setChildNode("11");
+ nodeStore.merge(builder, EmptyHook.INSTANCE, CommitInfo.EMPTY);
+ cps[1].id = nodeStore.checkpoint(Long.MAX_VALUE);
+
+ // Modify content and another checkpoint
+ builder = nodeStore.getRoot().builder();
+ builder.getChildNode("a").getChildNode("aa").setChildNode("aaa");
+ nodeStore.merge(builder, EmptyHook.INSTANCE, CommitInfo.EMPTY);
+ cps[2].id = nodeStore.checkpoint(Long.MAX_VALUE);
+
+ // Remove content and another checkpoint
+ builder = nodeStore.getRoot().builder();
+ builder.getChildNode("a").remove();
+ nodeStore.merge(builder, EmptyHook.INSTANCE, CommitInfo.EMPTY);
+ cps[3].id = nodeStore.checkpoint(Long.MAX_VALUE);
+
+ // A final bit of content
+ builder = nodeStore.getRoot().builder();
+ builder.setChildNode("d").setChildNode("dd");
+ nodeStore.merge(builder, EmptyHook.INSTANCE, CommitInfo.EMPTY);
+
+ NodeState uncompactedSuperRoot = fileStore.getHead();
+ NodeState uncompactedRoot = nodeStore.getRoot();
+ for (CP cp : cps) {
+ cp.uncompacted = nodeStore.retrieve(cp.id);
+ }
+
+ fileStore.compact();
+
+ NodeState compactedSuperRoot = fileStore.getHead();
+ NodeState compactedRoot = nodeStore.getRoot();
+ for (CP cp : cps) {
+ cp.compacted = nodeStore.retrieve(cp.id);
+ }
+
+ assertEquals(uncompactedSuperRoot, compactedSuperRoot);
+
+ assertEquals(uncompactedRoot, compactedRoot);
+ assertStableIds(uncompactedRoot, compactedRoot, "/root");
+
+ for (CP cp : cps) {
+ assertEquals(cp.uncompacted, cp.compacted);
+ assertStableIds(cp.uncompacted, cp.compacted, concat("/root/checkpoints", cp.id));
+ }
+ }
+ }
+
+ @Test
+ public void keepStableIdOnFlush() throws Exception {
+ try (FileStore fileStore = fileStoreBuilder(getFileStoreFolder()).build()) {
+ SegmentNodeStore nodeStore = SegmentNodeStoreBuilders.builder(fileStore).build();
+
+ // Initial content and checkpoint
+ NodeBuilder builder = nodeStore.getRoot().builder();
+ builder.setChildNode("a");
+ nodeStore.merge(builder, EmptyHook.INSTANCE, CommitInfo.EMPTY);
+ nodeStore.checkpoint(Long.MAX_VALUE);
+
+ // A final bit of content
+ builder = nodeStore.getRoot().builder();
+ for (int k = 0; k < 10000; k++) {
+ builder.setChildNode("b-" + k);
+ }
+ nodeStore.merge(builder, EmptyHook.INSTANCE, CommitInfo.EMPTY);
+
+ NodeState uncompactedSuperRoot = fileStore.getHead();
+ NodeState uncompactedRoot = nodeStore.getRoot();
+
+ fileStore.compact();
+
+ NodeState compactedSuperRoot = fileStore.getHead();
+ NodeState compactedRoot = nodeStore.getRoot();
+
+ assertEquals(uncompactedSuperRoot, compactedSuperRoot);
+
+ assertEquals(uncompactedRoot, compactedRoot);
+ assertStableIds(uncompactedRoot, compactedRoot, "/root");
+ }
+ }
+
+ @Test
+ public void crossGCDeduplicationTest() throws Exception {
+ try (FileStore fileStore = fileStoreBuilder(getFileStoreFolder()).build()) {
+ SegmentNodeStore nodeStore = SegmentNodeStoreBuilders.builder(fileStore).build();
+ NodeBuilder builder = nodeStore.getRoot().builder();
+ builder.setChildNode("a").setChildNode("aa");
+ builder.setChildNode("b").setChildNode("bb");
+ builder.setChildNode("c").setChildNode("cc");
+ nodeStore.merge(builder, EmptyHook.INSTANCE, CommitInfo.EMPTY);
+
+ NodeState a = nodeStore.getRoot().getChildNode("a");
+
+ builder = nodeStore.getRoot().builder();
+ builder.setChildNode("x").setChildNode("xx");
NodeState uncompacted = nodeStore.getRoot();
fileStore.compact();
NodeState compacted = nodeStore.getRoot();
assertEquals(uncompacted, compacted);
- assertTrue(uncompacted instanceof SegmentNodeState);
- assertTrue(compacted instanceof SegmentNodeState);
- assertEquals(((SegmentNodeState)uncompacted).getStableId(), ((SegmentNodeState)compacted).getStableId());
-
- NodeState checkpoint = nodeStore.retrieve(cpId);
- assertTrue(checkpoint instanceof SegmentNodeState);
- assertEquals("Checkpoint should get de-duplicated",
- ((Record) compacted).getRecordId(), ((Record) checkpoint).getRecordId());
- } finally {
- fileStore.close();
+ assertStableIds(uncompacted, compacted, "/root");
+
+ builder.setChildNode("y").setChildNode("yy");
+ builder.getChildNode("a").remove();
+ NodeState deferCompacted = nodeStore.merge(builder, EmptyHook.INSTANCE, CommitInfo.EMPTY);
+ assertEquals(1, ((SegmentNodeState)deferCompacted).getSegment().getGcGeneration());
+ }
+ }
+
+ private static void assertStableIds(NodeState node1, NodeState node2, String path) {
+ assertFalse("Nodes should be equal: " + path, node1 == node2);
+ assertTrue("Node should be a SegmentNodeState " + path, node1 instanceof SegmentNodeState);
+ assertTrue("Node should be a SegmentNodeState " + path, node2 instanceof SegmentNodeState);
+ SegmentNodeState sns1 = (SegmentNodeState) node1;
+ SegmentNodeState sns2 = (SegmentNodeState) node2;
+ assertEquals("GC generation should be bumped by one " + path,
+ sns1.getSegment().getGcGeneration() + 1, sns2.getSegment().getGcGeneration());
+ assertEquals("Nodes should have same stable id: " + path,
+ sns1.getStableId(), sns2.getStableId());
+
+ for (ChildNodeEntry cne : node1.getChildNodeEntries()) {
+ assertStableIds(
+ cne.getNodeState(), node2.getChildNode(cne.getName()),
+ concat(path, cne.getName()));
}
}
Modified: jackrabbit/oak/trunk/oak-segment-tar/src/test/java/org/apache/jackrabbit/oak/segment/ManyChildNodesIT.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-segment-tar/src/test/java/org/apache/jackrabbit/oak/segment/ManyChildNodesIT.java?rev=1800027&r1=1800026&r2=1800027&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-segment-tar/src/test/java/org/apache/jackrabbit/oak/segment/ManyChildNodesIT.java (original)
+++ jackrabbit/oak/trunk/oak-segment-tar/src/test/java/org/apache/jackrabbit/oak/segment/ManyChildNodesIT.java Tue Jun 27 08:29:18 2017
@@ -21,6 +21,7 @@ import static java.lang.Integer.getInteg
import static java.lang.System.getProperty;
import static org.apache.jackrabbit.oak.segment.compaction.SegmentGCOptions.defaultGCOptions;
import static org.apache.jackrabbit.oak.segment.file.FileStoreBuilder.fileStoreBuilder;
+import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.junit.Assume.assumeTrue;
@@ -35,6 +36,7 @@ import org.apache.jackrabbit.oak.segment
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.NodeState;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
@@ -103,15 +105,22 @@ public class ManyChildNodesIT {
public void manyChildNodesOC() throws Exception {
try (FileStore fileStore = createFileStore()) {
SegmentNodeStore nodeStore = SegmentNodeStoreBuilders.builder(fileStore).build();
- NodeBuilder root = nodeStore.getRoot().builder();
- addManyNodes(root);
- nodeStore.merge(root, EmptyHook.INSTANCE, CommitInfo.EMPTY);
+ nodeStore.checkpoint(Long.MAX_VALUE);
+ NodeBuilder builder = nodeStore.getRoot().builder();
+ addManyNodes(builder);
+ nodeStore.merge(builder, EmptyHook.INSTANCE, CommitInfo.EMPTY);
+
+ NodeState uncompactedRoot = nodeStore.getRoot();
assertTrue(fileStore.compact());
+ NodeState compactedRoot = nodeStore.getRoot();
+ assertTrue(uncompactedRoot != compactedRoot);
+ assertEquals(uncompactedRoot, compactedRoot);
}
}
private static void addManyNodes(NodeBuilder builder) {
for (int k = 0; k < NODE_COUNT; k++) {
+ if (k % 10000 == 0) System.out.println(k);
builder.setChildNode("c-" + k);
}
}
Added: jackrabbit/oak/trunk/oak-segment-tar/src/test/java/org/apache/jackrabbit/oak/segment/OnlineCompactorTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-segment-tar/src/test/java/org/apache/jackrabbit/oak/segment/OnlineCompactorTest.java?rev=1800027&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-segment-tar/src/test/java/org/apache/jackrabbit/oak/segment/OnlineCompactorTest.java (added)
+++ jackrabbit/oak/trunk/oak-segment-tar/src/test/java/org/apache/jackrabbit/oak/segment/OnlineCompactorTest.java Tue Jun 27 08:29:18 2017
@@ -0,0 +1,47 @@
+/*
+ * 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.segment;
+
+import static org.apache.jackrabbit.oak.segment.file.FileStoreBuilder.fileStoreBuilder;
+
+import java.io.File;
+import java.io.IOException;
+
+import org.apache.jackrabbit.oak.api.CommitFailedException;
+import org.apache.jackrabbit.oak.segment.file.FileStore;
+import org.apache.jackrabbit.oak.segment.file.InvalidFileStoreVersionException;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TemporaryFolder;
+
+public class OnlineCompactorTest {
+ @Rule
+ public TemporaryFolder folder = new TemporaryFolder(new File("target"));
+
+ private File getFileStoreFolder() {
+ return folder.getRoot();
+ }
+
+ @Test
+ public void bar() throws IOException, InvalidFileStoreVersionException, CommitFailedException {
+ try (FileStore fileStore = fileStoreBuilder(getFileStoreFolder()).build()) {
+ }
+ }
+
+}
Modified: jackrabbit/oak/trunk/oak-segment-tar/src/test/java/org/apache/jackrabbit/oak/segment/RecordTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-segment-tar/src/test/java/org/apache/jackrabbit/oak/segment/RecordTest.java?rev=1800027&r1=1800026&r2=1800027&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-segment-tar/src/test/java/org/apache/jackrabbit/oak/segment/RecordTest.java (original)
+++ jackrabbit/oak/trunk/oak-segment-tar/src/test/java/org/apache/jackrabbit/oak/segment/RecordTest.java Tue Jun 27 08:29:18 2017
@@ -48,7 +48,6 @@ import java.util.Map;
import java.util.Random;
import com.google.common.base.Charsets;
-import com.google.common.base.Suppliers;
import com.google.common.collect.ImmutableMap;
import org.apache.jackrabbit.oak.api.Blob;
import org.apache.jackrabbit.oak.api.CommitFailedException;
@@ -446,11 +445,4 @@ public class RecordTest {
assertNotNull(state.getProperty("jcr:mixinTypes"));
}
- @Test
- public void testCancel() throws IOException {
- NodeBuilder builder = EMPTY_NODE.builder();
- RecordId id = writer.writeNode(builder.getNodeState(), Suppliers.ofInstance(true));
- assertNull(id);
- }
-
}