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 2007/10/10 11:50:39 UTC
svn commit: r583413 - in /jackrabbit/trunk/jackrabbit-core/src:
main/java/org/apache/jackrabbit/core/data/FileDataStore.java
test/java/org/apache/jackrabbit/core/data/GarbageCollectorTest.java
Author: thomasm
Date: Wed Oct 10 02:50:38 2007
New Revision: 583413
URL: http://svn.apache.org/viewvc?rev=583413&view=rev
Log:
JCR-1138: Data store garbage collection deleted transient objects
Modified:
jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/data/FileDataStore.java
jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/data/GarbageCollectorTest.java
Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/data/FileDataStore.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/data/FileDataStore.java?rev=583413&r1=583412&r2=583413&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/data/FileDataStore.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/data/FileDataStore.java Wed Oct 10 02:50:38 2007
@@ -21,11 +21,13 @@
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
+import java.lang.ref.WeakReference;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
+import java.util.WeakHashMap;
/**
* Simple file-based data store. Data records are stored as normal files
@@ -88,6 +90,11 @@
* The minimum size of an object that should be stored in this data store.
*/
private int minRecordLength = DEFAULT_MIN_RECORD_LENGTH;
+
+ /**
+ * All data identifiers that are currently in use are in this set until they are garbage collected.
+ */
+ private WeakHashMap inUse = new WeakHashMap();
/**
* Creates a uninitialized data store.
@@ -127,8 +134,13 @@
file.setLastModified(System.currentTimeMillis());
}
}
+ usesIdentifier(identifier);
return new FileDataRecord(identifier, file);
}
+
+ private void usesIdentifier(DataIdentifier identifier) {
+ inUse.put(identifier, new WeakReference(identifier));
+ }
/**
* Creates a new data record.
@@ -164,6 +176,7 @@
// Check if the same record already exists, or
// move the temporary file in place if needed
DataIdentifier identifier = new DataIdentifier(digest.digest());
+ usesIdentifier(identifier);
File file = getFile(identifier);
File parent = file.getParentFile();
if (!parent.isDirectory()) {
@@ -208,6 +221,7 @@
* @return identified file
*/
private File getFile(DataIdentifier identifier) {
+ usesIdentifier(identifier);
String string = identifier.toString();
File file = directory;
file = new File(file, string.substring(0, 2));
@@ -249,8 +263,11 @@
int count = 0;
if (file.isFile() && file.exists() && file.canWrite()) {
if (file.lastModified() < min) {
- file.delete();
- count++;
+ DataIdentifier id = new DataIdentifier(file.getName());
+ if (!inUse.containsKey(id)) {
+ file.delete();
+ count++;
+ }
}
} else if (file.isDirectory()) {
File[] list = file.listFiles();
@@ -289,6 +306,14 @@
}
}
return identifiers.iterator();
+ }
+
+ /**
+ * Clear the in-use list. This is only used for testing to make the the garbage collection
+ * think that objects are no longer in use.
+ */
+ public void clearInUse() {
+ inUse.clear();
}
/**
Modified: jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/data/GarbageCollectorTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/data/GarbageCollectorTest.java?rev=583413&r1=583412&r2=583413&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/data/GarbageCollectorTest.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/data/GarbageCollectorTest.java Wed Oct 10 02:50:38 2007
@@ -22,8 +22,10 @@
import org.slf4j.LoggerFactory;
import java.io.IOException;
+import java.io.InputStream;
import java.util.Iterator;
+import javax.jcr.Credentials;
import javax.jcr.Node;
import javax.jcr.NodeIterator;
import javax.jcr.RepositoryException;
@@ -48,8 +50,8 @@
}
deleteMyNodes();
- runGC(session);
- runGC(session);
+ runGC(session, true);
+ runGC(session, true);
root.addNode("node1");
Node node2 = root.addNode("node2");
@@ -61,16 +63,18 @@
n.remove();
session.save();
+ Thread.sleep(1000);
GarbageCollector gc = new GarbageCollector(this, 0);
- gc.setTestDelay(100);
+ gc.setTestDelay(1000);
LOG.debug("scanning...");
gc.scan(session);
int count = listIdentifiers(gc);
- LOG.debug("stop scanning...");
+ LOG.debug("stop scanning; currently " + count + " identifiers");
gc.stopScan();
LOG.debug("deleting...");
+ ((FileDataStore) gc.getDataStore()).clearInUse();
assertTrue(gc.deleteUnused() > 0);
int count2 = listIdentifiers(gc);
assertEquals(count - 1, count2);
@@ -78,11 +82,14 @@
deleteMyNodes();
}
- private void runGC(Session session) throws RepositoryException, IOException {
+ private void runGC(Session session, boolean all) throws RepositoryException, IOException {
GarbageCollector gc = new GarbageCollector(this, 0);
- gc.setTestDelay(100);
+ gc.setTestDelay(1000);
gc.scan(session);
gc.stopScan();
+ if (all) {
+ ((FileDataStore) gc.getDataStore()).clearInUse();
+ }
gc.deleteUnused();
}
@@ -96,6 +103,47 @@
count++;
}
return count;
+ }
+
+ public void testTransientObjects() throws Exception {
+
+ Node root = testRootNode;
+ Session session = root.getSession();
+
+ RepositoryImpl rep = (RepositoryImpl) session.getRepository();
+ if (rep.getDataStore() == null) {
+ LOG.info("testTransientObjects skipped. Data store is not used.");
+ return;
+ }
+
+ deleteMyNodes();
+ runGC(session, true);
+ runGC(session, true);
+
+ Credentials cred = helper.getSuperuserCredentials();
+ Session s2 = helper.getRepository().login(cred);
+ root = s2.getRootNode();
+ Node node2 = root.addNode("node3");
+ Node n = node2.addNode("nodeWithBlob");
+ n.setProperty("test", new RandomInputStream(10, 10000));
+ Thread.sleep(1000);
+
+ runGC(session, false);
+
+ s2.save();
+
+ InputStream in = n.getProperty("test").getStream();
+ InputStream in2 = new RandomInputStream(10, 10000);
+ while (true) {
+ int a = in.read();
+ int b = in2.read();
+ assertEquals(a, b);
+ if (a < 0) {
+ break;
+ }
+ }
+
+ deleteMyNodes();
}
public void afterScanning(Node n) throws RepositoryException {