mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
[vcs-log] correctly rebuild user registry on error
VcsUserRegistry is a component independent from log. It should rebuild itself on errors and send rebuild notifications. Notifications are used to mark index corrupted, since it depends on user registry.
This commit is contained in:
@@ -16,9 +16,11 @@
|
||||
package com.intellij.vcs.log.data
|
||||
|
||||
import com.intellij.openapi.Disposable
|
||||
import com.intellij.openapi.application.ApplicationManager
|
||||
import com.intellij.openapi.application.PathManager
|
||||
import com.intellij.openapi.diagnostic.Logger
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.util.EventDispatcher
|
||||
import com.intellij.util.containers.ContainerUtil
|
||||
import com.intellij.util.containers.Interner
|
||||
import com.intellij.util.io.*
|
||||
@@ -29,31 +31,42 @@ import java.io.DataInput
|
||||
import java.io.DataOutput
|
||||
import java.io.File
|
||||
import java.io.IOException
|
||||
import java.util.*
|
||||
import java.util.concurrent.atomic.AtomicReference
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
class VcsUserRegistryImpl internal constructor(project: Project) : Disposable, VcsUserRegistry {
|
||||
private val _persistentEnumerator = AtomicReference<PersistentEnumeratorBase<VcsUser>?>()
|
||||
private val persistentEnumerator: PersistentEnumeratorBase<VcsUser>?
|
||||
get() = _persistentEnumerator.get()
|
||||
private val interner: Interner<VcsUser>
|
||||
private val mapFile = File(USER_CACHE_APP_DIR, project.locationHash + "." + STORAGE_VERSION)
|
||||
private val eventDispatcher = EventDispatcher.create<VcsUserRegistryListener>(VcsUserRegistryListener::class.java)
|
||||
|
||||
init {
|
||||
val mapFile = File(USER_CACHE_APP_DIR, project.locationHash + "." + STORAGE_VERSION)
|
||||
persistentEnumerator = initEnumerator(mapFile)
|
||||
initEnumerator()
|
||||
interner = Interner()
|
||||
}
|
||||
|
||||
private fun initEnumerator(mapFile: File): PersistentEnumeratorBase<VcsUser>? {
|
||||
return try {
|
||||
IOUtil.openCleanOrResetBroken({
|
||||
PersistentBTreeEnumerator(mapFile, MyDescriptor(), Page.PAGE_SIZE, null,
|
||||
STORAGE_VERSION)
|
||||
}, mapFile)
|
||||
private fun initEnumerator(): Boolean {
|
||||
try {
|
||||
val enumerator = IOUtil.openCleanOrResetBroken({
|
||||
PersistentBTreeEnumerator(mapFile, MyDescriptor(), Page.PAGE_SIZE, null,
|
||||
STORAGE_VERSION)
|
||||
}, mapFile)
|
||||
val wasSet = _persistentEnumerator.compareAndSet(null, enumerator)
|
||||
if (!wasSet) {
|
||||
LOG.error("Could not assign newly opened enumerator")
|
||||
enumerator?.close()
|
||||
}
|
||||
return wasSet
|
||||
}
|
||||
catch (e: IOException) {
|
||||
LOG.warn(e)
|
||||
null
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
override fun createUser(name: String, email: String): VcsUser {
|
||||
@@ -68,8 +81,8 @@ class VcsUserRegistryImpl internal constructor(project: Project) : Disposable, V
|
||||
}
|
||||
catch (e: IOException) {
|
||||
LOG.warn(e)
|
||||
rebuild(e)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
fun addUsers(users: Collection<VcsUser>) {
|
||||
@@ -84,10 +97,34 @@ class VcsUserRegistryImpl internal constructor(project: Project) : Disposable, V
|
||||
}
|
||||
catch (e: IOException) {
|
||||
LOG.warn(e)
|
||||
rebuild(e)
|
||||
emptySet()
|
||||
}
|
||||
}
|
||||
|
||||
private fun rebuild(t: Throwable) {
|
||||
if (persistentEnumerator?.isCorrupted == true) {
|
||||
_persistentEnumerator.getAndSet(null)?.let { oldEnumerator ->
|
||||
ApplicationManager.getApplication().executeOnPooledThread {
|
||||
try {
|
||||
oldEnumerator.close()
|
||||
}
|
||||
catch (_: IOException) {
|
||||
}
|
||||
finally {
|
||||
if (initEnumerator()) {
|
||||
eventDispatcher.multicaster.onRebuild(t)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun addRebuildListener(listener: VcsUserRegistryListener, disposable: Disposable) {
|
||||
eventDispatcher.addListener(listener, disposable)
|
||||
}
|
||||
|
||||
fun flush() {
|
||||
persistentEnumerator?.force()
|
||||
}
|
||||
@@ -140,3 +177,7 @@ class VcsUserRegistryImpl internal constructor(project: Project) : Disposable, V
|
||||
private const val STORAGE_VERSION = 2
|
||||
}
|
||||
}
|
||||
|
||||
interface VcsUserRegistryListener : EventListener {
|
||||
fun onRebuild(t: Throwable)
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@ import com.intellij.util.containers.ContainerUtil;
|
||||
import com.intellij.util.containers.MultiMap;
|
||||
import com.intellij.vcs.log.VcsLogProvider;
|
||||
import com.intellij.vcs.log.VcsLogRefresher;
|
||||
import com.intellij.vcs.log.VcsUserRegistry;
|
||||
import com.intellij.vcs.log.data.VcsLogData;
|
||||
import com.intellij.vcs.log.data.VcsLogStorage;
|
||||
import com.intellij.vcs.log.ui.AbstractVcsLogUi;
|
||||
@@ -59,13 +60,15 @@ public class VcsLogManager implements Disposable {
|
||||
myRecreateMainLogHandler = recreateHandler;
|
||||
|
||||
Map<VirtualFile, VcsLogProvider> logProviders = findLogProviders(roots, myProject);
|
||||
myLogData = new VcsLogData(myProject, logProviders, new MyFatalErrorsHandler(), this);
|
||||
MyFatalErrorsHandler fatalErrorsHandler = new MyFatalErrorsHandler();
|
||||
myLogData = new VcsLogData(myProject, logProviders, fatalErrorsHandler, this);
|
||||
myPostponableRefresher = new PostponableLogRefresher(myLogData);
|
||||
myTabsLogRefresher = new VcsLogTabsWatcher(myProject, myPostponableRefresher);
|
||||
|
||||
refreshLogOnVcsEvents(logProviders, myPostponableRefresher, myLogData);
|
||||
|
||||
myColorManager = new VcsLogColorManagerImpl(logProviders.keySet());
|
||||
myLogData.getUserRegistry().addRebuildListener(t -> fatalErrorsHandler.consume(myLogData.getUserRegistry(), t), this);
|
||||
|
||||
if (scheduleRefreshImmediately) {
|
||||
scheduleInitialization();
|
||||
@@ -130,7 +133,7 @@ public class VcsLogManager implements Disposable {
|
||||
MultiMap<VcsLogProvider, VirtualFile> providers2roots = MultiMap.create();
|
||||
logProviders.forEach((key, value) -> providers2roots.putValue(value, key));
|
||||
|
||||
for (Map.Entry<VcsLogProvider, Collection<VirtualFile>> entry : providers2roots.entrySet()) {
|
||||
for (Map.Entry<VcsLogProvider, Collection<VirtualFile>> entry: providers2roots.entrySet()) {
|
||||
Disposable disposable = entry.getKey().subscribeToRootRefreshEvents(entry.getValue(), refresher);
|
||||
Disposer.register(disposableParent, disposable);
|
||||
}
|
||||
@@ -140,7 +143,7 @@ public class VcsLogManager implements Disposable {
|
||||
public static Map<VirtualFile, VcsLogProvider> findLogProviders(@NotNull Collection<VcsRoot> roots, @NotNull Project project) {
|
||||
Map<VirtualFile, VcsLogProvider> logProviders = ContainerUtil.newHashMap();
|
||||
VcsLogProvider[] allLogProviders = Extensions.getExtensions(VcsLogProvider.LOG_PROVIDER_EP, project);
|
||||
for (VcsRoot root : roots) {
|
||||
for (VcsRoot root: roots) {
|
||||
AbstractVcs vcs = root.getVcs();
|
||||
VirtualFile path = root.getPath();
|
||||
if (vcs == null || path == null) {
|
||||
@@ -148,7 +151,7 @@ public class VcsLogManager implements Disposable {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (VcsLogProvider provider : allLogProviders) {
|
||||
for (VcsLogProvider provider: allLogProviders) {
|
||||
if (provider.getSupportedVcs().equals(vcs.getKeyInstanceMethod())) {
|
||||
logProviders.put(path, provider);
|
||||
break;
|
||||
@@ -207,7 +210,7 @@ public class VcsLogManager implements Disposable {
|
||||
LOG.error(e);
|
||||
}
|
||||
|
||||
if (source instanceof VcsLogStorage) {
|
||||
if (source instanceof VcsLogStorage || source instanceof VcsUserRegistry) {
|
||||
myLogData.getIndex().markCorrupted();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user