You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jackrabbit.apache.org by th...@apache.org on 2012/02/10 16:09:42 UTC

svn commit: r1242809 - in /jackrabbit/sandbox/microkernel/src: main/java/org/apache/jackrabbit/mk/blobs/ test/java/org/apache/jackrabbit/mk/blobs/

Author: thomasm
Date: Fri Feb 10 15:09:42 2012
New Revision: 1242809

URL: http://svn.apache.org/viewvc?rev=1242809&view=rev
Log:
Data store garbage collection.

Modified:
    jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/blobs/AbstractBlobStore.java
    jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/blobs/DbBlobStore.java
    jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/blobs/FileBlobStore.java
    jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/blobs/MemoryBlobStore.java
    jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/blobs/MongoBlobStore.java
    jackrabbit/sandbox/microkernel/src/test/java/org/apache/jackrabbit/mk/blobs/DbBlobStoreTest.java
    jackrabbit/sandbox/microkernel/src/test/java/org/apache/jackrabbit/mk/blobs/MongoBlobStoreTest.java

Modified: jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/blobs/AbstractBlobStore.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/blobs/AbstractBlobStore.java?rev=1242809&r1=1242808&r2=1242809&view=diff
==============================================================================
--- jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/blobs/AbstractBlobStore.java (original)
+++ jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/blobs/AbstractBlobStore.java Fri Feb 10 15:09:42 2012
@@ -26,9 +26,14 @@ import java.io.ByteArrayInputStream;
 import java.io.ByteArrayOutputStream;
 import java.io.IOException;
 import java.io.InputStream;
+import java.lang.ref.WeakReference;
 import java.security.DigestOutputStream;
 import java.security.MessageDigest;
+import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.Collections;
+import java.util.Map;
+import java.util.WeakHashMap;
 
 /**
  * An abstract data store that splits the binaries in relatively small blocks,
@@ -65,8 +70,11 @@ public abstract class AbstractBlobStore 
     protected static final int TYPE_HASH = 1;
     protected static final int TYPE_HASH_COMPRESSED = 2;
 
+    protected Map<String, WeakReference<String>> inUse =
+        Collections.synchronizedMap(new WeakHashMap<String, WeakReference<String>>());
+
     /**
-     * The minimum size of a block. Smaller blocks are stored (the data store id
+     * The minimum size of a block. Smaller blocks are inlined (the data store id
      * is the data itself).
      */
     private int blockSizeMin = 256;
@@ -83,6 +91,10 @@ public abstract class AbstractBlobStore 
         this.blockSizeMin = x;
     }
 
+    public long getBlockSizeMin() {
+        return blockSizeMin;
+    }
+
     public void setBlockSize(int x) {
         this.blockSize = x;
     }
@@ -111,12 +123,31 @@ public abstract class AbstractBlobStore 
             convertBlobToId(in, idStream, 0, 0);
             byte[] id = idStream.toByteArray();
             // System.out.println("    write blob " +  StringUtils.convertBytesToHex(id));
-            return StringUtils.convertBytesToHex(id);
+            String blobId = StringUtils.convertBytesToHex(id);
+            usesBlobId(blobId);
+            return blobId;
         } catch (Exception e) {
+            try {
+                in.close();
+            } catch (IOException e1) {
+                // ignore
+            }
             throw ExceptionFactory.convert(e);
         }
     }
 
+    protected void usesBlobId(String blobId) {
+        inUse.put(blobId, new WeakReference<String>(blobId));
+    }
+
+    public void clearInUse() {
+        inUse.clear();
+    }
+
+    public void clearCache() {
+        cache.clear();
+    }
+
     private void convertBlobToId(InputStream in, ByteArrayOutputStream idStream, int level, long totalLength) throws Exception {
         byte[] block = new byte[blockSize];
         int count = 0;
@@ -170,8 +201,25 @@ public abstract class AbstractBlobStore 
 
     protected abstract void storeBlock(byte[] digest, int level, byte[] data) throws Exception;
 
+    public abstract void startMark() throws Exception;
+
+    public abstract int sweep() throws Exception;
+
+    protected abstract boolean isMarkEnabled();
+
+    protected abstract void mark(BlockId id) throws Exception;
+
+    protected void markInUse() throws Exception {
+        for (String id : new ArrayList<String>(inUse.keySet())) {
+            mark(id);
+        }
+    }
+
     public int readBlob(String blobId, long pos, byte[] buff, int off, int length) {
         try {
+            if (isMarkEnabled()) {
+                mark(blobId);
+            }
             byte[] id = StringUtils.convertHexToBytes(blobId);
             ByteArrayInputStream idStream = new ByteArrayInputStream(id);
             while (true) {
@@ -240,6 +288,9 @@ public abstract class AbstractBlobStore 
 
     public long getBlobLength(String blobId) {
         try {
+            if (isMarkEnabled()) {
+                mark(blobId);
+            }
             byte[] id = StringUtils.convertHexToBytes(blobId);
             ByteArrayInputStream idStream = new ByteArrayInputStream(id);
             long totalLength = 0;
@@ -271,6 +322,48 @@ public abstract class AbstractBlobStore 
         }
     }
 
+    protected void mark(String blobId) throws IOException {
+        try {
+            byte[] id = StringUtils.convertHexToBytes(blobId);
+            ByteArrayInputStream idStream = new ByteArrayInputStream(id);
+            mark(idStream);
+        } catch (Exception e) {
+            throw new IOException("Mark failed for blob " + blobId, e);
+        }
+    }
+
+    private void mark(ByteArrayInputStream idStream) throws Exception {
+        while (true) {
+            int type = idStream.read();
+            if (type == -1) {
+                return;
+            } else if (type == TYPE_DATA) {
+                int len = IOUtils.readVarInt(idStream);
+                IOUtils.skipFully(idStream, (int) len);
+            } else if (type == TYPE_HASH) {
+                int level = IOUtils.readVarInt(idStream);
+                // totalLength
+                IOUtils.readVarLong(idStream);
+                if (level > 0) {
+                    // block length (ignored)
+                    IOUtils.readVarLong(idStream);
+                }
+                byte[] digest = new byte[IOUtils.readVarInt(idStream)];
+                IOUtils.readFully(idStream, digest, 0, digest.length);
+                if (level > 0) {
+                    byte[] block = readBlock(digest, 0);
+                    idStream = new ByteArrayInputStream(block);
+                    mark(idStream);
+                } else {
+                    BlockId id = new BlockId(digest, 0);
+                    mark(id);
+                }
+            } else {
+                throw new IOException("Unknown blobs id type " + type);
+            }
+        }
+    }
+
     public void close() {
         // ignore
     }

Modified: jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/blobs/DbBlobStore.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/blobs/DbBlobStore.java?rev=1242809&r1=1242808&r2=1242809&view=diff
==============================================================================
--- jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/blobs/DbBlobStore.java (original)
+++ jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/blobs/DbBlobStore.java Fri Feb 10 15:09:42 2012
@@ -25,6 +25,7 @@ import java.sql.PreparedStatement;
 import java.sql.ResultSet;
 import java.sql.SQLException;
 import java.sql.Statement;
+import java.util.ArrayList;
 
 /**
  * A database blob store.
@@ -32,6 +33,7 @@ import java.sql.Statement;
 public class DbBlobStore extends AbstractBlobStore {
 
     private JdbcConnectionPool cp;
+    private long minLastModified;
 
     public void setConnectionPool(JdbcConnectionPool cp) throws SQLException {
         this.cp = cp;
@@ -63,11 +65,10 @@ public class DbBlobStore extends Abstrac
             if (count == 0) {
                 try {
                     prep = conn.prepareStatement(
-                            "insert into datastore_meta(id, level, lastMod) values(?, ?, ?)");
+                            "insert into datastore_data(id, data) values(?, ?)");
                     try {
                         prep.setString(1, id);
-                        prep.setInt(2, level);
-                        prep.setLong(3, now);
+                        prep.setBytes(2, data);
                         prep.execute();
                     } finally {
                         prep.close();
@@ -77,10 +78,11 @@ public class DbBlobStore extends Abstrac
                 }
                 try {
                     prep = conn.prepareStatement(
-                            "insert into datastore_data(id, data) values(?, ?)");
+                            "insert into datastore_meta(id, level, lastMod) values(?, ?, ?)");
                     try {
                         prep.setString(1, id);
-                        prep.setBytes(2, data);
+                        prep.setInt(2, level);
+                        prep.setLong(3, now);
                         prep.execute();
                     } finally {
                         prep.close();
@@ -127,4 +129,65 @@ public class DbBlobStore extends Abstrac
         }
     }
 
+    @Override
+    public void startMark() throws Exception {
+        minLastModified = System.currentTimeMillis();
+        markInUse();
+    }
+
+    @Override
+    protected boolean isMarkEnabled() {
+        return minLastModified != 0;
+    }
+
+    @Override
+    protected void mark(BlockId blockId) throws Exception {
+        if (minLastModified == 0) {
+            return;
+        }
+        Connection conn = cp.getConnection();
+        try {
+            String id = StringUtils.convertBytesToHex(blockId.digest);
+            PreparedStatement prep = conn.prepareStatement(
+                    "update datastore_meta set lastMod = ? where id = ? and lastMod < ?");
+            prep.setLong(1, System.currentTimeMillis());
+            prep.setString(2, id);
+            prep.setLong(3, minLastModified);
+            prep.executeUpdate();
+        } finally {
+            conn.close();
+        }
+    }
+
+    @Override
+    public int sweep() throws Exception {
+        int count = 0;
+        Connection conn = cp.getConnection();
+        try {
+            PreparedStatement prep = conn.prepareStatement(
+                    "select id from datastore_meta where lastMod < ?");
+            prep.setLong(1, minLastModified);
+            ResultSet rs = prep.executeQuery();
+            ArrayList<String> ids = new ArrayList<String>();
+            while (rs.next()) {
+                ids.add(rs.getString(1));
+            }
+            prep = conn.prepareStatement(
+                "delete from datastore_meta where id = ?");
+            PreparedStatement prepData = conn.prepareStatement(
+                "delete from datastore_data where id = ?");
+            for (String id : ids) {
+                prep.setString(1, id);
+                prep.execute();
+                prepData.setString(1, id);
+                prepData.execute();
+                count++;
+            }
+        } finally {
+            conn.close();
+        }
+        minLastModified = 0;
+        return count;
+    }
+
 }

Modified: jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/blobs/FileBlobStore.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/blobs/FileBlobStore.java?rev=1242809&r1=1242808&r2=1242809&view=diff
==============================================================================
--- jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/blobs/FileBlobStore.java (original)
+++ jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/blobs/FileBlobStore.java Fri Feb 10 15:09:42 2012
@@ -16,26 +16,28 @@
  */
 package org.apache.jackrabbit.mk.blobs;
 
-import org.apache.jackrabbit.mk.fs.FilePath;
-import org.apache.jackrabbit.mk.fs.FileUtils;
-import org.apache.jackrabbit.mk.util.ExceptionFactory;
-import org.apache.jackrabbit.mk.util.IOUtils;
-import org.apache.jackrabbit.mk.util.StringUtils;
-
 import java.io.ByteArrayOutputStream;
+import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
-import java.io.IOException;
 import java.security.DigestInputStream;
 import java.security.MessageDigest;
+import org.apache.jackrabbit.mk.fs.FilePath;
+import org.apache.jackrabbit.mk.fs.FileUtils;
+import org.apache.jackrabbit.mk.util.ExceptionFactory;
+import org.apache.jackrabbit.mk.util.IOUtils;
+import org.apache.jackrabbit.mk.util.StringUtils;
 
 /**
  * A file blob store.
  */
 public class FileBlobStore extends AbstractBlobStore {
 
+    private static final String OLD_SUFFIX = "_old";
+
     private final FilePath baseDir;
     private final byte[] buffer = new byte[16 * 1024];
+    private boolean mark;
 
     public FileBlobStore(String dir) throws IOException {
         baseDir = FilePath.get(dir);
@@ -65,7 +67,7 @@ public class FileBlobStore extends Abstr
             IOUtils.writeVarInt(idStream, 0);
             IOUtils.writeVarLong(idStream, length);
             byte[] digest = messageDigest.digest();
-            FilePath f = getFile(digest);
+            FilePath f = getFile(digest, false);
             if (f.exists()) {
                 file.delete();
             } else {
@@ -78,7 +80,9 @@ public class FileBlobStore extends Abstr
             IOUtils.writeVarInt(idStream, digest.length);
             idStream.write(digest);
             byte[] id = idStream.toByteArray();
-            return StringUtils.convertBytesToHex(id);
+            String blobId = StringUtils.convertBytesToHex(id);
+            usesBlobId(blobId);
+            return blobId;
         } catch (Exception e) {
             throw ExceptionFactory.convert(e);
         }
@@ -86,7 +90,7 @@ public class FileBlobStore extends Abstr
 
     @Override
     protected synchronized void storeBlock(byte[] digest, int level, byte[] data) throws IOException {
-        FilePath f = getFile(digest);
+        FilePath f = getFile(digest, false);
         if (f.exists()) {
             return;
         }
@@ -101,15 +105,24 @@ public class FileBlobStore extends Abstr
         temp.moveTo(f);
     }
 
-    private FilePath getFile(byte[] digest) {
+    private FilePath getFile(byte[] digest, boolean old) {
         String id = StringUtils.convertBytesToHex(digest);
         String sub = id.substring(id.length() - 2);
+        if (old) {
+            sub += OLD_SUFFIX;
+        }
         return baseDir.resolve(sub).resolve(id + ".dat");
     }
 
     @Override
     protected byte[] readBlockFromBackend(BlockId id) throws IOException {
-        FilePath f = getFile(id.digest);
+        FilePath f = getFile(id.digest, false);
+        if (!f.exists()) {
+            FilePath old = getFile(id.digest, true);
+            f.getParent().createDirectory();
+            old.moveTo(f);
+            f = getFile(id.digest, false);
+        }
         int length = (int) Math.min(f.size(), getBlockSize());
         byte[] data = new byte[length];
         InputStream in = f.newInputStream();
@@ -122,4 +135,62 @@ public class FileBlobStore extends Abstr
         return data;
     }
 
+    @Override
+    public void startMark() throws Exception {
+        mark = true;
+        for (int i = 0; i < 256; i++) {
+            String sub = StringUtils.convertBytesToHex(new byte[] { (byte) i });
+            FilePath d = baseDir.resolve(sub);
+            FilePath old = baseDir.resolve(sub + OLD_SUFFIX);
+            if (d.exists()) {
+                if (old.exists()) {
+                    for (FilePath p : d.newDirectoryStream()) {
+                        String name = p.getName();
+                        FilePath newName = old.resolve(name);
+                        p.moveTo(newName);
+                    }
+                } else {
+                    d.moveTo(old);
+                }
+            }
+        }
+        markInUse();
+    }
+
+    @Override
+    protected boolean isMarkEnabled() {
+        return mark;
+    }
+
+    @Override
+    protected void mark(BlockId id) throws IOException {
+        FilePath f = getFile(id.digest, false);
+        if (!f.exists()) {
+            FilePath old = getFile(id.digest, true);
+            f.getParent().createDirectory();
+            old.moveTo(f);
+            f = getFile(id.digest, false);
+        }
+    }
+
+    @Override
+    public int sweep() throws IOException {
+        int count = 0;
+        for (int i = 0; i < 256; i++) {
+            String sub = StringUtils.convertBytesToHex(new byte[] { (byte) i });
+            FilePath old = baseDir.resolve(sub + OLD_SUFFIX);
+            if (old.exists()) {
+                for (FilePath p : old.newDirectoryStream()) {
+                    String name = p.getName();
+                    FilePath file = old.resolve(name);
+                    file.delete();
+                    count++;
+                }
+                old.delete();
+            }
+        }
+        mark = false;
+        return count;
+    }
+
 }
\ No newline at end of file

Modified: jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/blobs/MemoryBlobStore.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/blobs/MemoryBlobStore.java?rev=1242809&r1=1242808&r2=1242809&view=diff
==============================================================================
--- jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/blobs/MemoryBlobStore.java (original)
+++ jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/blobs/MemoryBlobStore.java Fri Feb 10 15:09:42 2012
@@ -24,6 +24,8 @@ import java.util.HashMap;
 public class MemoryBlobStore extends AbstractBlobStore {
 
     private HashMap<BlockId, byte[]> map = new HashMap<BlockId, byte[]>();
+    private HashMap<BlockId, byte[]> old = new HashMap<BlockId, byte[]>();
+    private boolean mark;
 
     @Override
     protected byte[] readBlockFromBackend(BlockId id) {
@@ -35,4 +37,36 @@ public class MemoryBlobStore extends Abs
         map.put(new BlockId(digest, 0), data);
     }
 
+    @Override
+    public void startMark() throws Exception {
+        mark = true;
+        old = map;
+        map = new HashMap<BlockId, byte[]>();
+        markInUse();
+    }
+
+    @Override
+    protected boolean isMarkEnabled() {
+        return mark;
+    }
+
+    @Override
+    protected void mark(BlockId id) throws Exception {
+        byte[] data = map.get(id);
+        if (data == null) {
+            data = old.get(id);
+            if (data != null) {
+                map.put(id, data);
+            }
+        }
+    }
+
+    @Override
+    public int sweep() {
+        int count = old.size();
+        old.clear();
+        mark = false;
+        return count;
+    }
+
 }

Modified: jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/blobs/MongoBlobStore.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/blobs/MongoBlobStore.java?rev=1242809&r1=1242808&r2=1242809&view=diff
==============================================================================
--- jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/blobs/MongoBlobStore.java (original)
+++ jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/blobs/MongoBlobStore.java Fri Feb 10 15:09:42 2012
@@ -72,4 +72,27 @@ public class MongoBlobStore extends Abst
         con.close();
     }
 
+    @Override
+    public void startMark() throws Exception {
+        // TODO
+        markInUse();
+    }
+
+    @Override
+    protected boolean isMarkEnabled() {
+        // TODO
+        return false;
+    }
+
+    @Override
+    protected void mark(BlockId id) throws Exception {
+        // TODO
+    }
+
+    @Override
+    public int sweep() throws Exception {
+        // TODO
+        return 0;
+    }
+
 }

Modified: jackrabbit/sandbox/microkernel/src/test/java/org/apache/jackrabbit/mk/blobs/DbBlobStoreTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/microkernel/src/test/java/org/apache/jackrabbit/mk/blobs/DbBlobStoreTest.java?rev=1242809&r1=1242808&r2=1242809&view=diff
==============================================================================
--- jackrabbit/sandbox/microkernel/src/test/java/org/apache/jackrabbit/mk/blobs/DbBlobStoreTest.java (original)
+++ jackrabbit/sandbox/microkernel/src/test/java/org/apache/jackrabbit/mk/blobs/DbBlobStoreTest.java Fri Feb 10 15:09:42 2012
@@ -33,6 +33,8 @@ import java.io.InputStream;
 import java.io.OutputStream;
 import java.sql.Connection;
 import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
 import java.util.Random;
 import java.util.concurrent.atomic.AtomicBoolean;
 
@@ -78,6 +80,12 @@ public class DbBlobStoreTest extends Tes
             store.readBlob(s, i, buff, 0, 1);
             assertEquals(data[i], buff[0]);
         }
+        try {
+            store.addBlob(tempFileName + "_wrong");
+            fail();
+        } catch (Exception e) {
+            // expected
+        }
     }
 
     public void testCombinedIdentifier() throws Exception {
@@ -108,6 +116,26 @@ public class DbBlobStoreTest extends Tes
         assertTrue(closed.get());
     }
 
+    public void testExceptionWhileReading() throws Exception {
+        final AtomicBoolean closed = new AtomicBoolean();
+        InputStream in = new InputStream() {
+            public void close() {
+                closed.set(true);
+            }
+            public int read() throws IOException {
+                throw new RuntimeException("abc");
+            }
+        };
+        try {
+            store.writeBlob(in);
+        } catch (Exception e) {
+            String msg = e.getMessage();
+            assertTrue(msg, msg.indexOf("abc") >= 0);
+        }
+        assertTrue(closed.get());
+    }
+
+
     public void testIllegalIdentifier() throws Exception {
         byte[] data = new byte[1];
         try {
@@ -122,6 +150,12 @@ public class DbBlobStoreTest extends Tes
         } catch (MicroKernelException e) {
             // expected
         }
+        try {
+            store.mark("ff");
+            fail();
+        } catch (Exception e) {
+            // expected
+        }
     }
 
     public void testSmall() throws Exception {
@@ -136,6 +170,69 @@ public class DbBlobStoreTest extends Tes
         doTest(1000, 10);
     }
 
+    public void testGarbageCollection() throws Exception {
+        HashMap<String, byte[]> map = new HashMap<String, byte[]>();
+        ArrayList<String> mem = new ArrayList<String>();
+        int count;
+        for (int i = 1; i < 10000; i += (i + 1) * 10) {
+            byte[] data = new byte[i];
+            String id;
+            id = store.writeBlob(new ByteArrayInputStream(data));
+            // copy the id so the string is not in the weak hash map
+            map.put(new String(id), data);
+            mem.add(id);
+            data = new byte[i];
+            Arrays.fill(data, (byte) 1);
+            id = store.writeBlob(new ByteArrayInputStream(data));
+            // copy the id so the string is not in the weak hash map
+            map.put(new String(id), data);
+            mem.add(id);
+        }
+        store.startMark();
+        store.sweep();
+        for (String id : map.keySet()) {
+            byte[] test = readFully(id);
+            assertTrue(Arrays.equals(map.get(id), test));
+        }
+
+        mem.clear();
+
+        store.clearInUse();
+        store.startMark();
+        for (String id : map.keySet()) {
+            byte[] d = map.get(id);
+            if (d[0] != 0) {
+                continue;
+            }
+            store.mark(id);
+        }
+        store.sweep();
+
+        store.clearInUse();
+        store.clearCache();
+        store.startMark();
+        count = store.sweep();
+        assertTrue("count: " + count, count > 0);
+        int failedCount = 0;
+        for (String id : map.keySet()) {
+            long length = store.getBlobLength(id);
+            try {
+                readFully(id);
+            } catch (Exception e) {
+                assertTrue(id + ":" + length, length > store.getBlockSizeMin());
+                failedCount++;
+            }
+        }
+        assertTrue("failedCount: " + failedCount, failedCount > 0);
+
+
+//        try {
+//            Thread.sleep(10);
+//        } catch (InterruptedException e) {
+//
+//        }
+    }
+
     private void doTest(int maxLength, int count) throws Exception {
         String[] s = new String[count * 2];
         Random r = new Random(0);

Modified: jackrabbit/sandbox/microkernel/src/test/java/org/apache/jackrabbit/mk/blobs/MongoBlobStoreTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/microkernel/src/test/java/org/apache/jackrabbit/mk/blobs/MongoBlobStoreTest.java?rev=1242809&r1=1242808&r2=1242809&view=diff
==============================================================================
--- jackrabbit/sandbox/microkernel/src/test/java/org/apache/jackrabbit/mk/blobs/MongoBlobStoreTest.java (original)
+++ jackrabbit/sandbox/microkernel/src/test/java/org/apache/jackrabbit/mk/blobs/MongoBlobStoreTest.java Fri Feb 10 15:09:42 2012
@@ -26,4 +26,8 @@ public class MongoBlobStoreTest extends 
         // store = new MongoBlobStore();
     }
 
+    public void testGarbageCollection() throws Exception {
+        // TODO
+    }
+
 }