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 ju...@apache.org on 2013/03/04 15:07:05 UTC

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

Author: jukka
Date: Mon Mar  4 14:07:04 2013
New Revision: 1452313

URL: http://svn.apache.org/r1452313
Log:
OAK-654: MapBranch size preconditions can fail

Add a test case and fix the problem.

Modified:
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/segment/MapRecord.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/segment/SegmentWriter.java
    jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/segment/RecordTest.java

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/segment/MapRecord.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/segment/MapRecord.java?rev=1452313&r1=1452312&r2=1452313&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/segment/MapRecord.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/segment/MapRecord.java Mon Mar  4 14:07:04 2013
@@ -24,8 +24,6 @@ import static java.lang.Integer.numberOf
 
 import java.util.UUID;
 
-import com.google.common.base.Preconditions;
-
 abstract class MapRecord extends Record {
 
     /**

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/segment/SegmentWriter.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/segment/SegmentWriter.java?rev=1452313&r1=1452312&r2=1452313&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/segment/SegmentWriter.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/segment/SegmentWriter.java Mon Mar  4 14:07:04 2013
@@ -48,6 +48,7 @@ import org.apache.jackrabbit.oak.spi.sta
 import org.apache.jackrabbit.oak.spi.state.NodeState;
 
 import com.google.common.base.Charsets;
+import com.google.common.collect.Iterables;
 import com.google.common.collect.Lists;
 import com.google.common.collect.Maps;
 import com.google.common.io.ByteStreams;
@@ -290,19 +291,42 @@ public class SegmentWriter {
                 }
 
                 int newSize = 0;
+                List<MapRecord> newBuckets = Lists.newArrayList();
                 RecordId[] bucketIds = ((MapBranch) base).getBuckets();
                 for (int i = 0; i < BUCKETS_PER_LEVEL; i++) {
                     MapRecord newBucket = writeMapBucket(
                             bucketIds[i], buckets.get(i), level + 1);
                     if (newBucket != null) {
+                        newBuckets.add(newBucket);
                         bucketIds[i] = newBucket.getRecordId();
                         newSize += newBucket.size();
                     } else {
                         bucketIds[i] = null;
                     }
                 }
-                
-                return writeMapBranch(level, newSize, bucketIds);
+
+                // OAK-654: what if the updated map is smaller?
+                if (newSize > MapRecord.BUCKETS_PER_LEVEL) {
+                    return writeMapBranch(level, newSize, bucketIds);
+                } else if (newSize == 0) {
+                    if (level == 0) {
+                        RecordId id = prepare(4);
+                        writeInt(0);
+                        return new MapLeaf(store, id, 0, 0);
+                    } else {
+                        return null;
+                    }
+                } else if (newBuckets.size() == 1) {
+                    return newBuckets.iterator().next();
+                } else {
+                    // FIXME: ugly hack, flush() shouldn't be needed here
+                    flush();
+                    List<MapEntry> list = Lists.newArrayList();
+                    for (MapRecord record : newBuckets) {
+                        Iterables.addAll(list, record.getEntries());
+                    }
+                    return writeMapLeaf(level, list);
+                }
             }
         } else if (entries.size() <= MapRecord.BUCKETS_PER_LEVEL
                 || level == MapRecord.MAX_NUMBER_OF_LEVELS) {

Modified: jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/segment/RecordTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/segment/RecordTest.java?rev=1452313&r1=1452312&r2=1452313&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/segment/RecordTest.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/segment/RecordTest.java Mon Mar  4 14:07:04 2013
@@ -294,4 +294,23 @@ public class RecordTest {
         assertEquals(before, after);
     }
 
+    @Test
+    public void testManyMapDeletes() {
+        NodeBuilder builder = MemoryNodeState.EMPTY_NODE.builder();
+        for (int i = 0; i < 1000; i++) {
+            builder.child("test" + i);
+        }
+        NodeState before = writer.writeNode(builder.getNodeState());
+        writer.flush();
+        assertEquals(builder.getNodeState(), before);
+
+        builder = before.builder();
+        for (int i = 0; i < 900; i++) {
+            builder.removeNode("test" + i);
+        }
+        NodeState after = writer.writeNode(builder.getNodeState());
+        writer.flush();
+        assertEquals(builder.getNodeState(), after);
+    }
+
 }