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
+ }
+
}