jackrabbit-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From shash...@apache.org
Subject svn commit: r1677956 - in /jackrabbit/trunk/jackrabbit-data/src: main/java/org/apache/jackrabbit/core/data/ test/java/org/apache/jackrabbit/core/data/ test/resources/
Date Wed, 06 May 2015 10:28:58 GMT
Author: shashank
Date: Wed May  6 10:28:57 2015
New Revision: 1677956

URL: http://svn.apache.org/r1677956
Log:
JCR-3873 CachingDataStore not safe against crashes, corrupted uploads file will prevent system
startup

Fix is to reset AsyncUploadCache and reload all local files to S3. 
Test case TestCachingFDS#testAsyncUploadCacheCorruption added. 

Modified:
    jackrabbit/trunk/jackrabbit-data/src/main/java/org/apache/jackrabbit/core/data/AsyncUploadCache.java
    jackrabbit/trunk/jackrabbit-data/src/main/java/org/apache/jackrabbit/core/data/CachingDataStore.java
    jackrabbit/trunk/jackrabbit-data/src/main/java/org/apache/jackrabbit/core/data/FSBackend.java
    jackrabbit/trunk/jackrabbit-data/src/test/java/org/apache/jackrabbit/core/data/TestCachingFDS.java
    jackrabbit/trunk/jackrabbit-data/src/test/resources/fs.properties

Modified: jackrabbit/trunk/jackrabbit-data/src/main/java/org/apache/jackrabbit/core/data/AsyncUploadCache.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-data/src/main/java/org/apache/jackrabbit/core/data/AsyncUploadCache.java?rev=1677956&r1=1677955&r2=1677956&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-data/src/main/java/org/apache/jackrabbit/core/data/AsyncUploadCache.java
(original)
+++ jackrabbit/trunk/jackrabbit-data/src/main/java/org/apache/jackrabbit/core/data/AsyncUploadCache.java
Wed May  6 10:28:57 2015
@@ -33,6 +33,7 @@ import java.util.HashSet;
 import java.util.Map;
 import java.util.Set;
 
+import org.apache.commons.io.IOUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -239,6 +240,7 @@ public class AsyncUploadCache {
             "AsynWriteCache:homeDir=[{}], path=[{}], asyncUploadLimit=[{}].",
             new Object[] { homeDir, path, asyncUploadLimit });
         pendingUploads = new File(homeDir + "/" + PENDIND_UPLOAD_FILE);
+        toBeDeletedUploads = new File(homeDir + "/" + TO_BE_DELETED_UPLOAD_FILE);
         if (pendingUploads.exists()) {
             deserializeAsyncUploadMap();
         } else {
@@ -246,7 +248,7 @@ public class AsyncUploadCache {
             asyncUploadMap = new HashMap<String, Long>();
             serializeAsyncUploadMap();
         }
-        toBeDeletedUploads = new File(homeDir + "/" + TO_BE_DELETED_UPLOAD_FILE);
+        
         if (toBeDeletedUploads.exists()) {
             deserializeToBeDeleted();
         } else {
@@ -262,22 +264,15 @@ public class AsyncUploadCache {
      */
     public synchronized void reset() throws IOException {
         String filePath = pendingUploads.getAbsolutePath();
-        if (pendingUploads.exists()) {
-            if (!pendingUploads.delete()) {
-                throw new IOException("Failed to delete file [" + filePath
-                    + "]");
-            }
+        if (!pendingUploads.exists()) {
+            pendingUploads.createNewFile();
         }
         pendingUploads.createNewFile();
         asyncUploadMap = new HashMap<String, Long>();
         serializeAsyncUploadMap();
 
-        filePath = toBeDeletedUploads.getAbsolutePath();
-        if (toBeDeletedUploads.exists()) {
-            if (!toBeDeletedUploads.delete()) {
-                throw new IOException("Failed to delete file [" + filePath
-                    + "]");
-            }
+        if (!toBeDeletedUploads.exists()) {
+            toBeDeletedUploads.createNewFile();
         }
         toBeDeletedUploads.createNewFile();
         toBeDeleted = new HashSet<String>();
@@ -295,8 +290,11 @@ public class AsyncUploadCache {
         ObjectOutput output = new ObjectOutputStream(buffer);
         try {
             output.writeObject(asyncUploadMap);
+            output.flush();
         } finally {
             output.close();
+            IOUtils.closeQuietly(buffer);
+            
         }
     }
 
@@ -311,9 +309,9 @@ public class AsyncUploadCache {
         ObjectInput input = new ObjectInputStream(buffer);
         try {
             asyncUploadMap = (Map<String, Long>) input.readObject();
-            // display its data
         } finally {
             input.close();
+            IOUtils.closeQuietly(buffer);
         }
     }
 
@@ -328,8 +326,10 @@ public class AsyncUploadCache {
         ObjectOutput output = new ObjectOutputStream(buffer);
         try {
             output.writeObject(toBeDeleted);
+            output.flush();
         } finally {
             output.close();
+            IOUtils.closeQuietly(buffer);
         }
     }
 
@@ -346,6 +346,7 @@ public class AsyncUploadCache {
             toBeDeleted = (Set<String>) input.readObject();
         } finally {
             input.close();
+            IOUtils.closeQuietly(buffer);
         }
     }
 }

Modified: jackrabbit/trunk/jackrabbit-data/src/main/java/org/apache/jackrabbit/core/data/CachingDataStore.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-data/src/main/java/org/apache/jackrabbit/core/data/CachingDataStore.java?rev=1677956&r1=1677955&r2=1677956&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-data/src/main/java/org/apache/jackrabbit/core/data/CachingDataStore.java
(original)
+++ jackrabbit/trunk/jackrabbit-data/src/main/java/org/apache/jackrabbit/core/data/CachingDataStore.java
Wed May  6 10:28:57 2015
@@ -273,14 +273,18 @@ public abstract class CachingDataStore e
                 FileUtils.cleanDirectory(tmpDir);
                 LOG.info("tmp=[{}] cleaned.", tmpDir.getPath());
             }
-
-            asyncWriteCache = new AsyncUploadCache();
-            asyncWriteCache.init(homeDir, path, asyncUploadLimit);
-
+            boolean asyncWriteCacheInitStatus = true;
+            try {
+                asyncWriteCache = new AsyncUploadCache();
+                asyncWriteCache.init(homeDir, path, asyncUploadLimit);
+            } catch (Exception e) {
+                LOG.warn("Failed to initialize asyncWriteCache", e);
+                asyncWriteCacheInitStatus = false;
+            }
             backend = createBackend();
             backend.init(this, path, config);
             String markerFileName = getMarkerFile();
-            if (markerFileName != null) {
+            if (markerFileName != null && !"".equals(markerFileName.trim())) {
                 // create marker file in homeDir to avoid deletion in cache
                 // cleanup.
                 File markerFile = new File(homeDir, markerFileName);
@@ -297,7 +301,16 @@ public abstract class CachingDataStore e
                 } else {
                     LOG.info("marker file = [{}] exists ",
                         markerFile.getAbsolutePath());
+                    if (!asyncWriteCacheInitStatus) {
+                        LOG.info("Initialization of asyncWriteCache failed. "
+                            + "Re-loading all files from local cache");
+                        uploadFilesFromCache();
+                        asyncWriteCache.reset();
+                    }
                 }
+            } else {
+                throw new DataStoreException("Failed to intialized DataStore."
+                    + " MarkerFileName is null or empty. ");
             }
             // upload any leftover async uploads to backend during last shutdown
             Set<String> fileList = asyncWriteCache.getAll();
@@ -452,12 +465,12 @@ public abstract class CachingDataStore e
         String fileName = getFileName(identifier);
         try {
             if (asyncWriteCache.hasEntry(fileName, minModifiedDate > 0)) {
-                LOG.debug("getRecord: [{}]  retrieved from asyncUploadmap",
+                LOG.trace("getRecord: [{}]  retrieved from asyncUploadmap",
                     identifier);
                 usesIdentifier(identifier);
                 return new CachingDataRecord(this, identifier);
             } else if (getLength(identifier) > -1) {
-                LOG.debug("getRecord: [{}]  retrieved using getLength",
+                LOG.trace("getRecord: [{}]  retrieved using getLength",
                     identifier);
                 touchInternal(identifier);
                 usesIdentifier(identifier);
@@ -483,13 +496,13 @@ public abstract class CachingDataStore e
         String fileName = getFileName(identifier);
         try {
             if (asyncWriteCache.hasEntry(fileName, minModifiedDate > 0)) {
-                LOG.debug(
+                LOG.trace(
                     "getRecordIfStored: [{}]  retrieved from asyncuploadmap",
                     identifier);
                 usesIdentifier(identifier);
                 return new CachingDataRecord(this, identifier);
             } else if (recLenCache.containsKey(identifier)) {
-                LOG.debug(
+                LOG.trace(
                     "getRecordIfStored: [{}]  retrieved using recLenCache",
                     identifier);
                 touchInternal(identifier);
@@ -615,13 +628,13 @@ public abstract class CachingDataStore e
         String fileName = getFileName(identifier);
         long lastModified = asyncWriteCache.getLastModified(fileName);
         if (lastModified != 0) {
-            LOG.debug(
+            LOG.trace(
                 "identifier [{}], lastModified=[{}] retrireved from AsyncUploadCache ",
                 identifier, lastModified);
 
         } else if (asyncTouchCache.get(identifier) != null) {
             lastModified = asyncTouchCache.get(identifier);
-            LOG.debug(
+            LOG.trace(
                 "identifier [{}], lastModified=[{}] retrireved from asyncTouchCache ",
                 identifier, lastModified);
         } else {
@@ -644,11 +657,11 @@ public abstract class CachingDataStore e
 
         Long length = recLenCache.get(identifier);
         if (length != null) {
-            LOG.debug(" identifier [{}] length fetched from recLengthCache",
+            LOG.trace(" identifier [{}] length fetched from recLengthCache",
                 identifier);
             return length;
         } else if ((length = cache.getFileLength(fileName)) != null) {
-            LOG.debug(" identifier [{}] length fetched from local cache",
+            LOG.trace(" identifier [{}] length fetched from local cache",
                 identifier);
             recLenCache.put(identifier, length);
             return length;
@@ -874,17 +887,19 @@ public abstract class CachingDataStore e
             downloadExecService.execute(new Runnable() {
                 @Override
                 public void run() {
+                    long startTime = System.currentTimeMillis();
                     InputStream input = null;
                     try {
-                        // getStream to cache file
-                        LOG.debug("Async download [{}] started.", identifier);
+                        LOG.trace("Async download [{}] started.", identifier);
                         input = getStream(identifier);
                     } catch (RepositoryException re) {
                         // ignore exception
                     } finally {
                         asyncDownloadCache.remove(identifier);
                         IOUtils.closeQuietly(input);
-                        LOG.debug("Async download [{}] completed.", identifier);
+                        LOG.debug("Async download [{}] completed in [{}] ms.",
+                            identifier,
+                            (System.currentTimeMillis() - startTime));
                     }
                 }
             });

Modified: jackrabbit/trunk/jackrabbit-data/src/main/java/org/apache/jackrabbit/core/data/FSBackend.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-data/src/main/java/org/apache/jackrabbit/core/data/FSBackend.java?rev=1677956&r1=1677955&r2=1677956&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-data/src/main/java/org/apache/jackrabbit/core/data/FSBackend.java
(original)
+++ jackrabbit/trunk/jackrabbit-data/src/main/java/org/apache/jackrabbit/core/data/FSBackend.java
Wed May  6 10:28:57 2015
@@ -110,10 +110,12 @@ public class FSBackend implements Backen
             throw new DataStoreException("Can not create a directory "
                 + "because a file exists with the same name: " + this.path);
         }
-        boolean created = pathDir.mkdirs();
-        if (!created) {
-            throw new DataStoreException("Could not create directory: "
-                + pathDir.getAbsolutePath());
+        if( !pathDir.exists()) {
+            boolean created = pathDir.mkdirs();
+            if (!created) {
+                throw new DataStoreException("Could not create directory: "
+                                + pathDir.getAbsolutePath());
+            }
         }
         asyncWriteExecuter = (ThreadPoolExecutor) Executors.newFixedThreadPool(
             10, new NamedThreadFactory("fs-write-worker"));

Modified: jackrabbit/trunk/jackrabbit-data/src/test/java/org/apache/jackrabbit/core/data/TestCachingFDS.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-data/src/test/java/org/apache/jackrabbit/core/data/TestCachingFDS.java?rev=1677956&r1=1677955&r2=1677956&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-data/src/test/java/org/apache/jackrabbit/core/data/TestCachingFDS.java
(original)
+++ jackrabbit/trunk/jackrabbit-data/src/test/java/org/apache/jackrabbit/core/data/TestCachingFDS.java
Wed May  6 10:28:57 2015
@@ -17,10 +17,13 @@
 
 package org.apache.jackrabbit.core.data;
 
+import java.io.File;
+import java.io.FileOutputStream;
 import java.util.Properties;
 
 import javax.jcr.RepositoryException;
 
+import org.apache.commons.io.IOUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -28,6 +31,10 @@ public class TestCachingFDS extends Test
 
     protected static final Logger LOG = LoggerFactory.getLogger(TestCachingFDS.class);
 
+    private static final String PENDIND_UPLOAD_FILE = "async-pending-uploads.ser";
+
+    private static final String TO_BE_DELETED_UPLOAD_FILE = "async-tobedeleted-uploads.ser";
+
     protected DataStore createDataStore() throws RepositoryException {
         CachingFDS cacheFDS = new CachingFDS();
         Properties props = loadProperties("/fs.properties");
@@ -47,4 +54,30 @@ public class TestCachingFDS extends Test
         return cacheFDS;
     }
 
+    /**
+     * Test robustness of {@link AsyncUploadCache} corruption.
+     */
+    public void testAsyncUploadCacheCorruption() {
+        try {
+            ds = createDataStore();
+            File pendingUploads = new File(dataStoreDir + "/"
+                + PENDIND_UPLOAD_FILE);
+            FileOutputStream fos = new FileOutputStream(pendingUploads);
+            IOUtils.write("garbage-data", fos);
+            fos.close();
+
+            File tobeDeletedFile = new File(dataStoreDir + "/"
+                + TO_BE_DELETED_UPLOAD_FILE);
+            fos = new FileOutputStream(tobeDeletedFile);
+            IOUtils.write("garbage-data", fos);
+            fos.close();
+            ds.close();
+
+            doAddRecordTest();
+        } catch (Exception e) {
+            LOG.error("error:", e);
+            fail(e.getMessage());
+        }
+    }
+
 }

Modified: jackrabbit/trunk/jackrabbit-data/src/test/resources/fs.properties
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-data/src/test/resources/fs.properties?rev=1677956&r1=1677955&r2=1677956&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-data/src/test/resources/fs.properties (original)
+++ jackrabbit/trunk/jackrabbit-data/src/test/resources/fs.properties Wed May  6 10:28:57
2015
@@ -1 +1,17 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
 



Mime
View raw message