diff --git a/platform/vcs-log/impl/src/META-INF/vcs-log.xml b/platform/vcs-log/impl/src/META-INF/vcs-log.xml index 4f44100f5b9e..960c14f95090 100644 --- a/platform/vcs-log/impl/src/META-INF/vcs-log.xml +++ b/platform/vcs-log/impl/src/META-INF/vcs-log.xml @@ -25,6 +25,8 @@ + + diff --git a/platform/vcs-log/impl/src/com/intellij/vcs/log/data/EmptyIndex.java b/platform/vcs-log/impl/src/com/intellij/vcs/log/data/EmptyIndex.java new file mode 100644 index 000000000000..a83d4e16310b --- /dev/null +++ b/platform/vcs-log/impl/src/com/intellij/vcs/log/data/EmptyIndex.java @@ -0,0 +1,59 @@ +/* + * Copyright 2000-2016 JetBrains s.r.o. + * + * Licensed 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. + */ +package com.intellij.vcs.log.data; + +import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.vcs.log.VcsLogDetailsFilter; +import com.intellij.vcs.log.data.index.VcsLogIndex; +import org.jetbrains.annotations.NotNull; + +import java.util.List; +import java.util.Set; + +public class EmptyIndex implements VcsLogIndex { + @Override + public void scheduleIndex(boolean full) { + } + + @Override + public boolean isIndexed(int commit) { + return false; + } + + @Override + public boolean isIndexed(@NotNull VirtualFile root) { + return false; + } + + @Override + public void markForIndexing(int commit, @NotNull VirtualFile root) { + } + + @Override + public boolean canFilter(@NotNull List filters) { + return false; + } + + @NotNull + @Override + public Set filter(@NotNull List detailsFilters) { + throw new UnsupportedOperationException(); + } + + @Override + public void markCorrupted() { + } +} diff --git a/platform/vcs-log/impl/src/com/intellij/vcs/log/data/VcsLogData.java b/platform/vcs-log/impl/src/com/intellij/vcs/log/data/VcsLogData.java index 16af2331ad5d..be451c68b38b 100644 --- a/platform/vcs-log/impl/src/com/intellij/vcs/log/data/VcsLogData.java +++ b/platform/vcs-log/impl/src/com/intellij/vcs/log/data/VcsLogData.java @@ -15,6 +15,7 @@ */ package com.intellij.vcs.log.data; +import com.intellij.ide.caches.CachesInvalidator; import com.intellij.openapi.Disposable; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.components.ServiceManager; @@ -35,6 +36,8 @@ import com.intellij.vcs.log.*; import com.intellij.vcs.log.data.index.VcsLogIndex; import com.intellij.vcs.log.data.index.VcsLogPersistentIndex; import com.intellij.vcs.log.impl.FatalErrorConsumer; +import com.intellij.vcs.log.impl.VcsLogCachesInvalidator; +import com.intellij.vcs.log.util.PersistentUtil; import com.intellij.vcs.log.util.StopWatch; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -91,15 +94,30 @@ public class VcsLogData implements Disposable, VcsLogDataProvider { myUserRegistry = (VcsUserRegistryImpl)ServiceManager.getService(project, VcsUserRegistry.class); myFatalErrorsConsumer = fatalErrorsConsumer; - myHashMap = createLogHashMap(); + VcsLogProgress progress = new VcsLogProgress(); + Disposer.register(this, progress); + + VcsLogCachesInvalidator invalidator = CachesInvalidator.EP_NAME.findExtension(VcsLogCachesInvalidator.class); + if (invalidator.isValid()) { + myHashMap = createLogHashMap(); + myIndex = new VcsLogPersistentIndex(myProject, myHashMap, progress, logProviders, myFatalErrorsConsumer, this); + } + else { + // this is not recoverable + // restart won't help here + // and can not shut down ide because of this + // so use memory storage (probably leading to out of memory at some point) + no index + String message = "Could not delete " + PersistentUtil.LOG_CACHE + "\nDelete it manually and restart IDEA."; + LOG.error(message); + myFatalErrorsConsumer.displayFatalErrorMessage(message); + myHashMap = new InMemoryStorage(); + myIndex = new EmptyIndex(); + } + myTopCommitsDetailsCache = new TopCommitsCache(myHashMap); myMiniDetailsGetter = new MiniDetailsGetter(myHashMap, logProviders, myTopCommitsDetailsCache, this); myDetailsGetter = new CommitDetailsGetter(myHashMap, logProviders, this); - VcsLogProgress progress = new VcsLogProgress(); - Disposer.register(this, progress); - myIndex = new VcsLogPersistentIndex(myProject, myHashMap, progress, logProviders, myFatalErrorsConsumer, this); - myRefresher = new VcsLogRefresherImpl(myProject, myHashMap, myLogProviders, myUserRegistry, myIndex, progress, myTopCommitsDetailsCache, this::fireDataPackChangeEvent, FAILING_EXCEPTION_HANDLER, RECENT_COMMITS_COUNT); diff --git a/platform/vcs-log/impl/src/com/intellij/vcs/log/impl/FatalErrorConsumer.java b/platform/vcs-log/impl/src/com/intellij/vcs/log/impl/FatalErrorConsumer.java index 566ec3d80c1c..0573ed544ba6 100644 --- a/platform/vcs-log/impl/src/com/intellij/vcs/log/impl/FatalErrorConsumer.java +++ b/platform/vcs-log/impl/src/com/intellij/vcs/log/impl/FatalErrorConsumer.java @@ -20,4 +20,6 @@ import org.jetbrains.annotations.Nullable; public interface FatalErrorConsumer { void consume(@Nullable Object source, @NotNull Exception exception); + + void displayFatalErrorMessage(@NotNull String message); } diff --git a/platform/vcs-log/impl/src/com/intellij/vcs/log/impl/VcsLogCachesInvalidator.java b/platform/vcs-log/impl/src/com/intellij/vcs/log/impl/VcsLogCachesInvalidator.java new file mode 100644 index 000000000000..e0260bbf485e --- /dev/null +++ b/platform/vcs-log/impl/src/com/intellij/vcs/log/impl/VcsLogCachesInvalidator.java @@ -0,0 +1,46 @@ +/* + * Copyright 2000-2016 JetBrains s.r.o. + * + * Licensed 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. + */ +package com.intellij.vcs.log.impl; + +import com.intellij.ide.caches.CachesInvalidator; +import com.intellij.openapi.util.io.FileUtil; +import com.intellij.util.ArrayUtil; +import com.intellij.vcs.log.util.PersistentUtil; + +public class VcsLogCachesInvalidator extends CachesInvalidator { + + public synchronized boolean isValid() { + if (PersistentUtil.getCorruptionMarkerFile().exists()) { + boolean deleted = FileUtil.delete(PersistentUtil.LOG_CACHE); + if (!deleted) { + // if could not delete caches, ensure that corruption marker is still there + FileUtil.createIfDoesntExist(PersistentUtil.getCorruptionMarkerFile()); + } + return deleted; + } + return true; + } + + @Override + public void invalidateCaches() { + if (PersistentUtil.LOG_CACHE.exists()) { + String[] children = PersistentUtil.LOG_CACHE.list(); + if (!ArrayUtil.isEmpty(children)) { + FileUtil.createIfDoesntExist(PersistentUtil.getCorruptionMarkerFile()); + } + } + } +} diff --git a/platform/vcs-log/impl/src/com/intellij/vcs/log/impl/VcsLogManager.java b/platform/vcs-log/impl/src/com/intellij/vcs/log/impl/VcsLogManager.java index 84f4b4bbf5a9..cb685aea87f3 100644 --- a/platform/vcs-log/impl/src/com/intellij/vcs/log/impl/VcsLogManager.java +++ b/platform/vcs-log/impl/src/com/intellij/vcs/log/impl/VcsLogManager.java @@ -240,5 +240,10 @@ public class VcsLogManager implements Disposable { myLogData.getIndex().markCorrupted(); } } + + @Override + public void displayFatalErrorMessage(@NotNull String message) { + VcsBalloonProblemNotifier.showOverChangesView(myProject, message, MessageType.ERROR); + } } } diff --git a/platform/vcs-log/impl/src/com/intellij/vcs/log/impl/VcsProjectLog.java b/platform/vcs-log/impl/src/com/intellij/vcs/log/impl/VcsProjectLog.java index 3664dd8b9033..390b7cc1b0a0 100644 --- a/platform/vcs-log/impl/src/com/intellij/vcs/log/impl/VcsProjectLog.java +++ b/platform/vcs-log/impl/src/com/intellij/vcs/log/impl/VcsProjectLog.java @@ -15,6 +15,7 @@ */ package com.intellij.vcs.log.impl; +import com.intellij.ide.caches.CachesInvalidator; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.components.ServiceManager; import com.intellij.openapi.project.Project; @@ -111,7 +112,10 @@ public class VcsProjectLog { logManager.scheduleInitialization(); } else if (PostponableLogRefresher.keepUpToDate()) { - HeavyAwareExecutor.executeOutOfHeavyProcessLater(logManager::scheduleInitialization, 5000); + VcsLogCachesInvalidator invalidator = CachesInvalidator.EP_NAME.findExtension(VcsLogCachesInvalidator.class); + if (invalidator.isValid()) { + HeavyAwareExecutor.executeOutOfHeavyProcessLater(logManager::scheduleInitialization, 5000); + } } } diff --git a/platform/vcs-log/impl/src/com/intellij/vcs/log/util/PersistentUtil.java b/platform/vcs-log/impl/src/com/intellij/vcs/log/util/PersistentUtil.java index 407c77cce7c6..b39928c3b663 100644 --- a/platform/vcs-log/impl/src/com/intellij/vcs/log/util/PersistentUtil.java +++ b/platform/vcs-log/impl/src/com/intellij/vcs/log/util/PersistentUtil.java @@ -33,6 +33,7 @@ import java.util.Map; public class PersistentUtil { @NotNull public static final File LOG_CACHE = new File(PathManager.getSystemPath(), "vcs-log"); + @NotNull private static final String CORRUPTION_MARKER = "corruption.marker"; @NotNull public static String calcLogId(@NotNull Project project, @NotNull Map logProviders) { @@ -83,4 +84,9 @@ public class PersistentUtil { new PersistentHashMap<>(storageFile, new IntInlineKeyDescriptor(), externalizer, Page.PAGE_SIZE), storageFile); } + + @NotNull + public static File getCorruptionMarkerFile() { + return new File(LOG_CACHE, CORRUPTION_MARKER); + } } diff --git a/platform/vcs-log/impl/test/com/intellij/vcs/log/data/VcsLogRefresherTest.java b/platform/vcs-log/impl/test/com/intellij/vcs/log/data/VcsLogRefresherTest.java index da9fe03e983b..d438daa36f4d 100644 --- a/platform/vcs-log/impl/test/com/intellij/vcs/log/data/VcsLogRefresherTest.java +++ b/platform/vcs-log/impl/test/com/intellij/vcs/log/data/VcsLogRefresherTest.java @@ -33,6 +33,7 @@ import com.intellij.vcs.log.graph.GraphCommit; import com.intellij.vcs.log.impl.*; import com.intellij.vcs.test.VcsPlatformTest; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import java.util.*; import java.util.concurrent.*; @@ -194,7 +195,17 @@ public class VcsLogRefresherTest extends VcsPlatformTest { } private VcsLogRefresherImpl createLoader(Consumer dataPackConsumer) { - myLogData = new VcsLogData(myProject, myLogProviders, (source, exception) -> LOG.error(exception)); + myLogData = new VcsLogData(myProject, myLogProviders, new FatalErrorHandler() { + @Override + public void consume(@Nullable Object source, @NotNull Exception exception) { + LOG.error(exception); + } + + @Override + public void displayFatalErrorMessage(@NotNull String message) { + LOG.error(message); + } + }); Disposer.register(myProject, myLogData); return new VcsLogRefresherImpl(myProject, myLogData.getHashMap(), myLogProviders, myLogData.getUserRegistry(), myLogData.getIndex(), new VcsLogProgress(), diff --git a/platform/vcs-log/impl/test/com/intellij/vcs/log/data/VisiblePackBuilderTest.kt b/platform/vcs-log/impl/test/com/intellij/vcs/log/data/VisiblePackBuilderTest.kt index 172b294d2b55..44071cfd9fbc 100644 --- a/platform/vcs-log/impl/test/com/intellij/vcs/log/data/VisiblePackBuilderTest.kt +++ b/platform/vcs-log/impl/test/com/intellij/vcs/log/data/VisiblePackBuilderTest.kt @@ -247,31 +247,5 @@ class VisiblePackBuilderTest { } } - class EmptyIndex : VcsLogIndex { - override fun isIndexed(root: VirtualFile): Boolean { - return false - } - - override fun isIndexed(commit: Int): Boolean { - return false - } - - override fun canFilter(filters: MutableList): Boolean { - return false - } - - override fun scheduleIndex(full: Boolean) { - } - - override fun markForIndexing(index: Int, root: VirtualFile) { - } - - override fun filter(detailsFilters: MutableList): MutableSet { - throw UnsupportedOperationException() - } - - override fun markCorrupted() { - } - } }