jackrabbit-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From thom...@apache.org
Subject svn commit: r727402 - in /jackrabbit/trunk/jackrabbit-core/src: main/java/org/apache/jackrabbit/core/data/FileDataStore.java main/java/org/apache/jackrabbit/core/data/db/DbDataStore.java test/java/org/apache/jackrabbit/core/data/GarbageCollectorTest.java
Date Wed, 17 Dec 2008 14:44:20 GMT
Author: thomasm
Date: Wed Dec 17 06:44:20 2008
New Revision: 727402

URL: http://svn.apache.org/viewvc?rev=727402&view=rev
Log:
JCR-1838 Garbage collection deletes temporary files in DataStore

Modified:
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/data/FileDataStore.java
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/data/db/DbDataStore.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=727402&r1=727401&r2=727402&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 Dec 17 06:44:20 2008
@@ -165,6 +165,8 @@
         File temporary = null;
         try {
             temporary = newTemporaryFile();
+            DataIdentifier tempId = new DataIdentifier(temporary.getName());
+            usesIdentifier(tempId);
             // Copy the stream to the temporary file and calculate the
             // stream length and the message digest of the stream
             long length = 0;
@@ -211,7 +213,9 @@
                     throw new IOException(DIGEST + " collision: " + file);
                 }
             }
-
+            // this will also make sure that
+            // tempId is not garbage collected until here
+            inUse.remove(tempId);
             return new FileDataRecord(identifier, file);
         } catch (NoSuchAlgorithmException e) {
             throw new DataStoreException(DIGEST + " not available", e);
@@ -275,8 +279,9 @@
         int count = 0;
         if (file.isFile() && file.exists() && file.canWrite()) {
             synchronized (this) {
+                String fileName = file.getName();
                 if (file.lastModified() < min) {
-                    DataIdentifier id = new DataIdentifier(file.getName());
+                    DataIdentifier id = new DataIdentifier(fileName);
                     if (!inUse.containsKey(id)) {
                         file.delete();
                         count++;

Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/data/db/DbDataStore.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/data/db/DbDataStore.java?rev=727402&r1=727401&r2=727402&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/data/db/DbDataStore.java
(original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/data/db/DbDataStore.java
Wed Dec 17 06:44:20 2008
@@ -43,6 +43,7 @@
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.Iterator;
+import java.util.List;
 import java.util.Map;
 import java.util.Properties;
 import java.util.WeakHashMap;
@@ -282,6 +283,11 @@
      * All data identifiers that are currently in use are in this set until they are garbage
collected.
      */
     protected Map inUse = Collections.synchronizedMap(new WeakHashMap());
+    
+    /**
+     * The temporary identifiers that are currently in use.
+     */
+    protected List temporaryInUse = Collections.synchronizedList(new ArrayList());
 
     /**
      * {@inheritDoc}
@@ -290,8 +296,8 @@
         ResultSet rs = null;
         TempFileInputStream fileInput = null;
         ConnectionRecoveryManager conn = getConnection();
+        String id = null, tempId = null;
         try {
-            String id = null, tempId = null;
             long now;
             for (int i = 0; i < ConnectionRecoveryManager.TRIALS; i++) {
                 try {
@@ -315,6 +321,7 @@
                 log.error(msg);
                 throw new DataStoreException(msg);
             }
+            temporaryInUse.add(tempId);
             MessageDigest digest = getDigest();
             DigestInputStream dIn = new DigestInputStream(stream, digest);
             TrackingInputStream in = new TrackingInputStream(dIn);
@@ -372,6 +379,9 @@
         } catch (Exception e) {
             throw convert("Can not insert new record", e);
         } finally {
+            if (tempId != null) {
+                temporaryInUse.remove(tempId);
+            }
             DatabaseHelper.closeSilently(rs);
             putBack(conn);
             if (fileInput != null) {
@@ -404,13 +414,19 @@
     public synchronized int deleteAllOlderThan(long min) throws DataStoreException {
         ConnectionRecoveryManager conn = getConnection();
         try {
-            Iterator it = new ArrayList(inUse.keySet()).iterator();
-            while (it.hasNext()) {
+            ArrayList touch = new ArrayList();
+            for (Iterator it = new ArrayList(inUse.keySet()).iterator(); it.hasNext();) {
                 DataIdentifier identifier = (DataIdentifier) it.next();
                 if (identifier != null) {
-                    touch(identifier, 0);
+                    touch.add(identifier.toString());
                 }
             }
+            touch.addAll(temporaryInUse);
+            Iterator it = touch.iterator();
+            while (it.hasNext()) {
+                String key = (String) it.next();
+                updateLastModifiedDate(key, 0);
+            }
             // DELETE FROM DATASTORE WHERE LAST_MODIFIED<?
             PreparedStatement prep = conn.executeStmt(deleteOlderSQL, new Long[]{new Long(min)});
             return prep.getUpdateCount();
@@ -677,6 +693,10 @@
      */
     long touch(DataIdentifier identifier, long lastModified) throws DataStoreException {
         usesIdentifier(identifier);
+        return updateLastModifiedDate(identifier.toString(), lastModified);
+    }
+
+    private long updateLastModifiedDate(String key, long lastModified) throws DataStoreException
{
         if (lastModified < minModifiedDate) {
             long now = System.currentTimeMillis();
             Long n = new Long(now);
@@ -684,7 +704,7 @@
             try {
                 // UPDATE DATASTORE SET LAST_MODIFIED = ? WHERE ID = ? AND LAST_MODIFIED
< ?
                 conn.executeStmt(updateLastModifiedSQL, new Object[]{
-                        n, identifier.toString(), n
+                        n, key, n
                 });
                 return now;
             } catch (Exception e) {

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=727402&r1=727401&r2=727402&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 Dec 17 06:44:20 2008
@@ -22,11 +22,11 @@
 import org.apache.jackrabbit.test.AbstractJCRTest;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
+import EDU.oswego.cs.dl.util.concurrent.SynchronousChannel;
 
 import java.io.IOException;
 import java.io.InputStream;
 import java.util.Iterator;
-
 import javax.jcr.Credentials;
 import javax.jcr.Node;
 import javax.jcr.NodeIterator;
@@ -41,6 +41,61 @@
     /** logger instance */
     private static final Logger LOG = LoggerFactory.getLogger(GarbageCollectorTest.class);
 
+    public void testConcurrentGC() throws Exception {
+        Node root = testRootNode;
+        Session session = root.getSession();
+        RepositoryImpl rep = (RepositoryImpl) session.getRepository();
+        if (rep.getDataStore() == null) {
+            LOG.info("testConcurrentGC skipped. Data store is not used.");
+            return;
+        }
+        final SynchronousChannel sync = new SynchronousChannel();
+        final Node node = root.addNode("slowBlob");
+        new Thread() {
+            public void run() {
+                try {
+                    node.setProperty("slowBlob", new InputStream() {
+                        int pos = 0;
+                        public int read() throws IOException {
+                            pos++;
+                            if (pos < 10000) {
+                                return pos % 80 == 0 ? '\n' : '.';
+                            } else if (pos == 10000) {
+                                try {
+                                    sync.put("x");
+                                    // deleted
+                                    sync.take();
+                                } catch (InterruptedException e) {
+                                    e.printStackTrace();
+                                }
+                                return 'x';
+                            }
+                            return -1;
+                        }
+                    });
+                    node.getSession().save();
+                    sync.put("saved");
+                } catch (Exception e) {
+                    e.printStackTrace();
+                }
+            }
+        }.start();
+        assertEquals("x", sync.take());
+        GarbageCollector gc = ((SessionImpl) session).createDataStoreGarbageCollector();
+        gc.scan();
+        gc.stopScan();
+        gc.deleteUnused();
+        sync.put("deleted");
+        assertEquals("saved", sync.take());
+        InputStream in = node.getProperty("slowBlob").getStream();
+        for (int pos = 1; pos < 10000; pos++) {
+            int expected = pos % 80 == 0 ? '\n' : '.';
+            assertEquals(expected, in.read());
+        }
+        assertEquals('x', in.read());
+        in.close();
+    }
+
     public void testGC() throws Exception {
         Node root = testRootNode;
         Session session = root.getSession();



Mime
View raw message