more reliable to crashes test state storage (IDEA-144670)
authorMaxim.Mossienko <Maxim.Mossienko@jetbrains.com>
Thu, 3 Sep 2015 10:17:06 +0000 (12:17 +0200)
committerMaxim.Mossienko <Maxim.Mossienko@jetbrains.com>
Thu, 3 Sep 2015 10:20:55 +0000 (12:20 +0200)
platform/lang-impl/src/com/intellij/execution/TestStateStorage.java

index 78e8a3bc895298465d4a77c5f34bfd8c7cef8848..c471b52c2092eedd1900e5f3ef2b40fb1fd3d6e1 100644 (file)
@@ -21,11 +21,10 @@ import com.intellij.openapi.components.ServiceManager;
 import com.intellij.openapi.diagnostic.Logger;
 import com.intellij.openapi.project.Project;
 import com.intellij.openapi.util.Disposer;
+import com.intellij.openapi.util.ThrowableComputable;
 import com.intellij.openapi.util.io.FileUtilRt;
-import com.intellij.util.io.DataExternalizer;
-import com.intellij.util.io.EnumeratorStringDescriptor;
-import com.intellij.util.io.PersistentEnumeratorBase;
-import com.intellij.util.io.PersistentHashMap;
+import com.intellij.openapi.vfs.newvfs.persistent.FlushingDaemon;
+import com.intellij.util.io.*;
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
 
@@ -34,6 +33,7 @@ import java.io.DataOutput;
 import java.io.File;
 import java.io.IOException;
 import java.util.Date;
+import java.util.concurrent.ScheduledFuture;
 
 /**
  * @author Dmitry Avdeev
@@ -57,6 +57,7 @@ public class TestStateStorage implements Disposable {
 
   private static final Logger LOG = Logger.getInstance(TestStateStorage.class);
   private PersistentHashMap<String, Record> myMap;
+  private volatile ScheduledFuture<?> myMapFlusher;
 
   public static TestStateStorage getInstance(@NotNull Project project) {
     return ServiceManager.getService(project, TestStateStorage.class);
@@ -68,37 +69,39 @@ public class TestStateStorage implements Disposable {
     FileUtilRt.createParentDirs(file);
     try {
       myMap = create(file);
-    }
-    catch (PersistentEnumeratorBase.CorruptedException e) {
-      PersistentHashMap.deleteFilesStartingWith(file);
-      try {
-        myMap = create(file);
-      }
-      catch (IOException e1) {
-        LOG.error(e1);
-      }
-    }
-    catch (IOException e) {
+    } catch (IOException e) {
       LOG.error(e);
     }
+    myMapFlusher = FlushingDaemon.everyFiveSeconds(new Runnable() {
+      @Override
+      public void run() {
+        if (myMapFlusher == null) return; // disposed
+        if (myMap != null && myMap.isDirty()) myMap.force();
+      }
+    });
 
     Disposer.register(project, this);
   }
 
   @NotNull
-  protected PersistentHashMap<String, Record> create(File file) throws IOException {
-    return new PersistentHashMap<String, Record>(file, new EnumeratorStringDescriptor(), new DataExternalizer<Record>() {
-      @Override
-      public void save(@NotNull DataOutput out, Record value) throws IOException {
-        out.writeInt(value.magnitude);
-        out.writeLong(value.date.getTime());
-      }
-
+  protected PersistentHashMap<String, Record> create(final File file) throws IOException {
+    return IOUtil.openCleanOrResetBroken(new ThrowableComputable<PersistentHashMap<String, Record>, IOException>() {
       @Override
-      public Record read(@NotNull DataInput in) throws IOException {
-        return new Record(in.readInt(), new Date(in.readLong()));
+      public PersistentHashMap<String, Record> compute() throws IOException {
+        return new PersistentHashMap<String, Record>(file, new EnumeratorStringDescriptor(), new DataExternalizer<Record>() {
+          @Override
+          public void save(@NotNull DataOutput out, Record value) throws IOException {
+            out.writeInt(value.magnitude);
+            out.writeLong(value.date.getTime());
+          }
+
+          @Override
+          public Record read(@NotNull DataInput in) throws IOException {
+            return new Record(in.readInt(), new Date(in.readLong()));
+          }
+        });
       }
-    });
+    }, file);
   }
 
   @Nullable
@@ -124,6 +127,8 @@ public class TestStateStorage implements Disposable {
 
   @Override
   public void dispose() {
+    myMapFlusher.cancel(false);
+    myMapFlusher = null;
     try {
       myMap.close();
     }