mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
[vcs-log] introduce VcsLogIndex with a simple implementation that has a phm from commit id to full message
This commit is contained in:
committed by
Julia Beliaeva
parent
7774154880
commit
d401d0dec6
@@ -9,14 +9,13 @@ import java.io.IOException;
|
||||
* Date: 8/10/11
|
||||
*/
|
||||
public interface PersistentMap<K, V> {
|
||||
|
||||
|
||||
V get(K key) throws IOException;
|
||||
|
||||
void put(K key, V value) throws IOException;
|
||||
|
||||
boolean processKeys(Processor<K> processor) throws IOException;
|
||||
|
||||
|
||||
boolean isClosed();
|
||||
|
||||
boolean isDirty();
|
||||
|
||||
@@ -69,7 +69,7 @@ abstract class AbstractDataGetter<T extends VcsShortCommitDetails> implements Di
|
||||
Disposer.register(parentDisposable, this);
|
||||
myLoader =
|
||||
new SequentialLimitedLifoExecutor<>(this, MAX_LOADING_TASKS, task -> {
|
||||
preLoadCommitData(task.myCommits);
|
||||
preLoadCommitData(task.myCommits, true);
|
||||
notifyLoaded();
|
||||
});
|
||||
}
|
||||
@@ -142,7 +142,7 @@ abstract class AbstractDataGetter<T extends VcsShortCommitDetails> implements Di
|
||||
public void run(@NotNull final ProgressIndicator indicator) {
|
||||
indicator.checkCanceled();
|
||||
try {
|
||||
TIntObjectHashMap<T> map = preLoadCommitData(toLoad);
|
||||
TIntObjectHashMap<T> map = preLoadCommitData(toLoad, true);
|
||||
map.forEachValue(value -> {
|
||||
result.add(value);
|
||||
return true;
|
||||
@@ -237,7 +237,8 @@ abstract class AbstractDataGetter<T extends VcsShortCommitDetails> implements Di
|
||||
return commits;
|
||||
}
|
||||
|
||||
private TIntObjectHashMap<T> preLoadCommitData(@NotNull TIntHashSet commits) throws VcsException {
|
||||
@NotNull
|
||||
public TIntObjectHashMap<T> preLoadCommitData(@NotNull TIntHashSet commits, boolean saveInCache) throws VcsException {
|
||||
TIntObjectHashMap<T> result = new TIntObjectHashMap<>();
|
||||
final MultiMap<VirtualFile, String> rootsAndHashes = MultiMap.create();
|
||||
commits.forEach(commit -> {
|
||||
@@ -256,7 +257,7 @@ abstract class AbstractDataGetter<T extends VcsShortCommitDetails> implements Di
|
||||
int index = myHashMap.getCommitIndex(data.getId(), data.getRoot());
|
||||
result.put(index, data);
|
||||
}
|
||||
saveInCache(result);
|
||||
if (saveInCache) saveInCache(result);
|
||||
}
|
||||
else {
|
||||
LOG.error("No log provider for root " + entry.getKey().getPath() + ". All known log providers " + myLogProviders);
|
||||
|
||||
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
* 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.util.Processor;
|
||||
import com.intellij.util.io.PersistentMap;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class InMemoryMap<K, V> implements PersistentMap<K, V> {
|
||||
private final Map<K, V> myMap = new HashMap<>();
|
||||
|
||||
@Override
|
||||
public V get(K key) throws IOException {
|
||||
return myMap.get(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void put(K key, V value) throws IOException {
|
||||
myMap.put(key, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean processKeys(Processor<K> processor) throws IOException {
|
||||
for (K key : myMap.keySet()) {
|
||||
if (!processor.process(key)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isClosed() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDirty() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void force() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void markDirty() throws IOException {
|
||||
}
|
||||
}
|
||||
@@ -72,6 +72,7 @@ public class VcsLogData implements Disposable, VcsLogDataProvider {
|
||||
@NotNull private final List<DataPackChangeListener> myDataPackChangeListeners = ContainerUtil.createLockFreeCopyOnWriteList();
|
||||
|
||||
@NotNull private final Consumer<Exception> myFatalErrorsConsumer;
|
||||
@NotNull private final VcsLogIndex myIndex;
|
||||
|
||||
public VcsLogData(@NotNull Project project,
|
||||
@NotNull Map<VirtualFile, VcsLogProvider> logProviders,
|
||||
@@ -86,10 +87,11 @@ public class VcsLogData implements Disposable, VcsLogDataProvider {
|
||||
myTopCommitsDetailsCache = new TopCommitsCache(myHashMap);
|
||||
myMiniDetailsGetter = new MiniDetailsGetter(myHashMap, logProviders, myTopCommitsDetailsCache, this);
|
||||
myDetailsGetter = new CommitDetailsGetter(myHashMap, logProviders, this);
|
||||
myIndex = new VcsLogPersistentIndex(myProject, myHashMap, logProviders, myDetailsGetter, myFatalErrorsConsumer, this);
|
||||
|
||||
myRefresher =
|
||||
new VcsLogRefresherImpl(myProject, myHashMap, myLogProviders, myUserRegistry, myTopCommitsDetailsCache,
|
||||
dataPack -> fireDataPackChangeEvent(dataPack), e -> {
|
||||
new VcsLogRefresherImpl(myProject, myHashMap, myLogProviders, myUserRegistry, myIndex, myTopCommitsDetailsCache,
|
||||
this::fireDataPackChangeEvent, e -> {
|
||||
if (!(e instanceof ProcessCanceledException)) {
|
||||
LOG.error(e);
|
||||
}
|
||||
@@ -134,7 +136,7 @@ public class VcsLogData implements Disposable, VcsLogDataProvider {
|
||||
|
||||
@NotNull
|
||||
public VisiblePackBuilder createVisiblePackBuilder() {
|
||||
return new VisiblePackBuilder(myLogProviders, myHashMap, myTopCommitsDetailsCache, myDetailsGetter);
|
||||
return new VisiblePackBuilder(myLogProviders, myHashMap, myTopCommitsDetailsCache, myDetailsGetter, myIndex);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -290,4 +292,9 @@ public class VcsLogData implements Disposable, VcsLogDataProvider {
|
||||
public TopCommitsCache getTopCommitsCache() {
|
||||
return myTopCommitsDetailsCache;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public VcsLogIndex getIndex() {
|
||||
return myIndex;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* 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.vcs.log.VcsLogDetailsFilter;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
public interface VcsLogIndex {
|
||||
void scheduleIndex();
|
||||
|
||||
void markForIndexing(int commit);
|
||||
|
||||
boolean canFilter(@NotNull List<VcsLogDetailsFilter> filters);
|
||||
|
||||
@NotNull
|
||||
Set<Integer> filter(@NotNull List<VcsLogDetailsFilter> detailsFilters);
|
||||
}
|
||||
@@ -0,0 +1,270 @@
|
||||
/*
|
||||
* 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.Disposable;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.progress.PerformInBackgroundOption;
|
||||
import com.intellij.openapi.progress.ProgressIndicator;
|
||||
import com.intellij.openapi.progress.ProgressManager;
|
||||
import com.intellij.openapi.progress.Task;
|
||||
import com.intellij.openapi.progress.impl.BackgroundableProcessIndicator;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.Condition;
|
||||
import com.intellij.openapi.util.Disposer;
|
||||
import com.intellij.openapi.util.Ref;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.openapi.vcs.VcsException;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.util.Consumer;
|
||||
import com.intellij.util.Processor;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import com.intellij.util.io.EnumeratorStringDescriptor;
|
||||
import com.intellij.util.io.PersistentHashMap;
|
||||
import com.intellij.util.io.PersistentMap;
|
||||
import com.intellij.vcs.log.*;
|
||||
import com.intellij.vcs.log.util.PersistentUtil;
|
||||
import gnu.trove.TIntHashSet;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class VcsLogPersistentIndex implements VcsLogIndex, Disposable {
|
||||
private static final Logger LOG = Logger.getInstance(VcsLogPersistentIndex.class);
|
||||
private static final int BATCH_SIZE = 1000;
|
||||
|
||||
@NotNull private final Project myProject;
|
||||
@NotNull private final Consumer<Exception> myFatalErrorsConsumer;
|
||||
@NotNull private final CommitDetailsGetter myDetailsGetter;
|
||||
@NotNull private final VcsLogStorage myHashMap;
|
||||
|
||||
@NotNull private final PersistentMap<Integer, String> myMessagesIndex;
|
||||
|
||||
@NotNull private TIntHashSet myCommitsToIndex = new TIntHashSet();
|
||||
|
||||
public VcsLogPersistentIndex(@NotNull Project project,
|
||||
@NotNull VcsLogStorage hashMap,
|
||||
@NotNull Map<VirtualFile, VcsLogProvider> providers,
|
||||
@NotNull CommitDetailsGetter detailsGetter,
|
||||
@NotNull Consumer<Exception> fatalErrorsConsumer,
|
||||
@NotNull Disposable disposableParent) {
|
||||
myHashMap = hashMap;
|
||||
myProject = project;
|
||||
myDetailsGetter = detailsGetter;
|
||||
myFatalErrorsConsumer = fatalErrorsConsumer;
|
||||
|
||||
myMessagesIndex = createMessagesIndex(providers);
|
||||
|
||||
Disposer.register(disposableParent, this);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public PersistentMap<Integer, String> createMessagesIndex(@NotNull Map<VirtualFile, VcsLogProvider> providers) {
|
||||
try {
|
||||
return PersistentUtil
|
||||
.createPersistentHashMap(EnumeratorStringDescriptor.INSTANCE, "messages", PersistentUtil.calcLogId(myProject, providers), 0);
|
||||
}
|
||||
catch (IOException e) {
|
||||
myFatalErrorsConsumer.consume(e);
|
||||
return new InMemoryMap<>();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void scheduleIndex() {
|
||||
if (myCommitsToIndex.isEmpty()) return;
|
||||
TIntHashSet commitsToIndex = myCommitsToIndex;
|
||||
myCommitsToIndex = new TIntHashSet();
|
||||
|
||||
Task.Backgroundable task = new MyIndexingTask(commitsToIndex);
|
||||
|
||||
ApplicationManager.getApplication().invokeLater(() -> {
|
||||
BackgroundableProcessIndicator indicator = new BackgroundableProcessIndicator(task);
|
||||
ProgressManager.getInstance().runProcessWithProgressAsynchronously(task, indicator);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
private void index(@NotNull TIntHashSet commits) {
|
||||
try {
|
||||
storeDetails(TroveUtil.streamValues(myDetailsGetter.preLoadCommitData(commits, false)).collect(Collectors.toList()));
|
||||
}
|
||||
catch (VcsException e) {
|
||||
LOG.error(e);
|
||||
commits.forEach(value -> {
|
||||
markForIndexing(value);
|
||||
return true;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private void storeDetails(@NotNull Collection<VcsFullCommitDetails> details) {
|
||||
for (VcsFullCommitDetails detail : details) {
|
||||
try {
|
||||
myMessagesIndex.put(myHashMap.getCommitIndex(detail.getId(), detail.getRoot()), detail.getFullMessage());
|
||||
}
|
||||
catch (IOException e) {
|
||||
myFatalErrorsConsumer.consume(e);
|
||||
}
|
||||
}
|
||||
myMessagesIndex.force();
|
||||
}
|
||||
|
||||
public boolean isIndexed(int commit) {
|
||||
try {
|
||||
return myMessagesIndex.get(commit) != null;
|
||||
}
|
||||
catch (IOException e) {
|
||||
myFatalErrorsConsumer.consume(e);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void markForIndexing(int index) {
|
||||
myCommitsToIndex.add(index);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private <T> TIntHashSet filter(@NotNull PersistentMap<Integer, T> map, @NotNull Condition<T> condition) {
|
||||
TIntHashSet result = new TIntHashSet();
|
||||
try {
|
||||
Processor<Integer> processor = integer -> {
|
||||
try {
|
||||
T value = map.get(integer);
|
||||
if (value != null) {
|
||||
if (condition.value(value)) {
|
||||
result.add(integer);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (IOException e) {
|
||||
myFatalErrorsConsumer.consume(e);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
if (myMessagesIndex instanceof PersistentHashMap) {
|
||||
((PersistentHashMap<Integer, T>)myMessagesIndex).processKeysWithExistingMapping(processor);
|
||||
}
|
||||
else {
|
||||
myMessagesIndex.processKeys(processor);
|
||||
}
|
||||
}
|
||||
catch (IOException e) {
|
||||
myFatalErrorsConsumer.consume(e);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public TIntHashSet filterMessages(@NotNull String text) {
|
||||
return filter(myMessagesIndex, message -> StringUtil.containsIgnoreCase(message, text));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canFilter(@NotNull List<VcsLogDetailsFilter> filters) {
|
||||
if (filters.isEmpty()) return false;
|
||||
for (VcsLogDetailsFilter filter : filters) {
|
||||
if (!(filter instanceof VcsLogTextFilter)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public Set<Integer> filter(@NotNull List<VcsLogDetailsFilter> detailsFilters) {
|
||||
Set<Integer> result = ContainerUtil.newHashSet();
|
||||
|
||||
VcsLogTextFilter textFilter = ContainerUtil.findInstance(detailsFilters, VcsLogTextFilter.class);
|
||||
if (textFilter != null) {
|
||||
filterMessages(textFilter.getText()).forEach(value -> {
|
||||
result.add(value);
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose() {
|
||||
try {
|
||||
myMessagesIndex.close();
|
||||
}
|
||||
catch (IOException e) {
|
||||
LOG.warn(e);
|
||||
}
|
||||
}
|
||||
|
||||
private class MyIndexingTask extends Task.Backgroundable {
|
||||
private final TIntHashSet myCommits;
|
||||
|
||||
public MyIndexingTask(@NotNull TIntHashSet commits) {
|
||||
super(VcsLogPersistentIndex.this.myProject, "Indexing Commit Data", true, PerformInBackgroundOption.ALWAYS_BACKGROUND);
|
||||
myCommits = commits;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run(@NotNull ProgressIndicator indicator) {
|
||||
indicator.setIndeterminate(false);
|
||||
|
||||
Ref<Integer> nCommit = new Ref<>(0);
|
||||
Ref<Integer> indexedCommits = new Ref<>(0);
|
||||
LOG.info("Indexing " + myCommits.size() + " commits");
|
||||
|
||||
long time = System.currentTimeMillis();
|
||||
Ref<TIntHashSet> commitsBatch = new Ref<>(new TIntHashSet());
|
||||
myCommits.forEach(commit -> {
|
||||
if (!isIndexed(commit)) {
|
||||
indexedCommits.set(indexedCommits.get() + 1);
|
||||
commitsBatch.get().add(commit);
|
||||
if (commitsBatch.get().size() >= BATCH_SIZE) {
|
||||
try {
|
||||
index(commitsBatch.get());
|
||||
}
|
||||
finally {
|
||||
commitsBatch.set(new TIntHashSet());
|
||||
}
|
||||
}
|
||||
}
|
||||
nCommit.set(nCommit.get() + 1);
|
||||
|
||||
indicator.checkCanceled();
|
||||
indicator.setFraction(((double)nCommit.get()) / myCommits.size());
|
||||
return true;
|
||||
});
|
||||
|
||||
if (!commitsBatch.get().isEmpty()) {
|
||||
index(commitsBatch.get());
|
||||
|
||||
indicator.checkCanceled(); // TODO schedule for reindexing?
|
||||
indicator.setFraction(((double)nCommit.get() * BATCH_SIZE) / myCommits.size());
|
||||
}
|
||||
|
||||
LOG.info((System.currentTimeMillis() - time) / 1000.0 + "sec for indexing " + indexedCommits.get() + " new commits");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -50,6 +50,7 @@ public class VcsLogRefresherImpl implements VcsLogRefresher {
|
||||
@NotNull private final VcsLogStorage myHashMap;
|
||||
@NotNull private final Map<VirtualFile, VcsLogProvider> myProviders;
|
||||
@NotNull private final VcsUserRegistryImpl myUserRegistry;
|
||||
@NotNull private final VcsLogIndex myIndex;
|
||||
@NotNull private final TopCommitsCache myTopCommitsDetailsCache;
|
||||
@NotNull private final Consumer<Exception> myExceptionHandler;
|
||||
@NotNull private final VcsLogProgress myProgress;
|
||||
@@ -64,6 +65,7 @@ public class VcsLogRefresherImpl implements VcsLogRefresher {
|
||||
@NotNull VcsLogStorage hashMap,
|
||||
@NotNull Map<VirtualFile, VcsLogProvider> providers,
|
||||
@NotNull VcsUserRegistryImpl userRegistry,
|
||||
@NotNull VcsLogIndex index,
|
||||
@NotNull TopCommitsCache topCommitsDetailsCache,
|
||||
@NotNull Consumer<DataPack> dataPackUpdateHandler,
|
||||
@NotNull Consumer<Exception> exceptionHandler,
|
||||
@@ -73,6 +75,7 @@ public class VcsLogRefresherImpl implements VcsLogRefresher {
|
||||
myHashMap = hashMap;
|
||||
myProviders = providers;
|
||||
myUserRegistry = userRegistry;
|
||||
myIndex = index;
|
||||
myTopCommitsDetailsCache = topCommitsDetailsCache;
|
||||
myExceptionHandler = exceptionHandler;
|
||||
myRecentCommitCount = recentCommitsCount;
|
||||
@@ -136,6 +139,7 @@ public class VcsLogRefresherImpl implements VcsLogRefresher {
|
||||
}
|
||||
}.iterate(getProvidersForRoots(requirements.keySet()));
|
||||
myUserRegistry.flush();
|
||||
myIndex.scheduleIndex();
|
||||
sw.report();
|
||||
return logInfo;
|
||||
}
|
||||
@@ -180,7 +184,9 @@ public class VcsLogRefresherImpl implements VcsLogRefresher {
|
||||
private GraphCommitImpl<Integer> compactCommit(@NotNull TimedVcsCommit commit, @NotNull final VirtualFile root) {
|
||||
List<Integer> parents = ContainerUtil.map(commit.getParents(),
|
||||
(NotNullFunction<Hash, Integer>)hash -> myHashMap.getCommitIndex(hash, root));
|
||||
return new GraphCommitImpl<>(myHashMap.getCommitIndex(commit.getId(), root), parents, commit.getTimestamp());
|
||||
int index = myHashMap.getCommitIndex(commit.getId(), root);
|
||||
myIndex.markForIndexing(index);
|
||||
return new GraphCommitImpl<>(index, parents, commit.getTimestamp());
|
||||
}
|
||||
|
||||
private void storeUsersAndDetails(@NotNull List<? extends VcsCommitMetadata> metadatas) {
|
||||
@@ -357,6 +363,7 @@ public class VcsLogRefresherImpl implements VcsLogRefresher {
|
||||
}
|
||||
}.iterate(myProviders);
|
||||
myUserRegistry.flush();
|
||||
myIndex.scheduleIndex();
|
||||
sw.report();
|
||||
return logInfo;
|
||||
}
|
||||
|
||||
@@ -44,15 +44,18 @@ class VisiblePackBuilder {
|
||||
@NotNull private final TopCommitsCache myTopCommitsDetailsCache;
|
||||
@NotNull private final DataGetter<VcsFullCommitDetails> myCommitDetailsGetter;
|
||||
@NotNull private final Map<VirtualFile, VcsLogProvider> myLogProviders;
|
||||
@NotNull private final VcsLogIndex myIndex;
|
||||
|
||||
VisiblePackBuilder(@NotNull Map<VirtualFile, VcsLogProvider> providers,
|
||||
@NotNull VcsLogStorage hashMap,
|
||||
@NotNull TopCommitsCache topCommitsDetailsCache,
|
||||
@NotNull DataGetter<VcsFullCommitDetails> detailsGetter) {
|
||||
@NotNull DataGetter<VcsFullCommitDetails> detailsGetter,
|
||||
@NotNull VcsLogIndex index) {
|
||||
myHashMap = hashMap;
|
||||
myTopCommitsDetailsCache = topCommitsDetailsCache;
|
||||
myCommitDetailsGetter = detailsGetter;
|
||||
myLogProviders = providers;
|
||||
myIndex = index;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@@ -67,29 +70,35 @@ class VisiblePackBuilder {
|
||||
|
||||
Set<Integer> matchingHeads = getMatchingHeads(dataPack.getRefsModel(), dataPack.getLogProviders().keySet(), filters);
|
||||
List<VcsLogDetailsFilter> detailsFilters = filters.getDetailsFilters();
|
||||
Collection<CommitId> matchingCommits = null;
|
||||
Set<Integer> matchingCommits = null;
|
||||
boolean canRequestMore = false;
|
||||
if (!detailsFilters.isEmpty()) {
|
||||
if (commitCount == CommitCountStage.INITIAL) {
|
||||
matchingCommits = filterInMemory(dataPack.getPermanentGraph(), detailsFilters, matchingHeads);
|
||||
if (matchingCommits.size() < commitCount.getCount()) {
|
||||
commitCount = commitCount.next();
|
||||
matchingCommits = null;
|
||||
}
|
||||
if (myIndex.canFilter(detailsFilters)) {
|
||||
matchingCommits = myIndex.filter(detailsFilters);
|
||||
canRequestMore = false;
|
||||
}
|
||||
else {
|
||||
if (commitCount == CommitCountStage.INITIAL) {
|
||||
matchingCommits = getMatchedCommitIndex(filterInMemory(dataPack.getPermanentGraph(), detailsFilters, matchingHeads));
|
||||
if (matchingCommits.size() < commitCount.getCount()) {
|
||||
commitCount = commitCount.next();
|
||||
matchingCommits = null;
|
||||
}
|
||||
}
|
||||
|
||||
if (matchingCommits == null) {
|
||||
try {
|
||||
matchingCommits = getFilteredDetailsFromTheVcs(myLogProviders, filters, commitCount.getCount());
|
||||
}
|
||||
catch (VcsException e) {
|
||||
// TODO show an error balloon or something else for non-ea guys.
|
||||
matchingCommits = Collections.emptyList();
|
||||
LOG.error(e);
|
||||
if (matchingCommits == null) {
|
||||
try {
|
||||
matchingCommits = getMatchedCommitIndex(getFilteredDetailsFromTheVcs(myLogProviders, filters, commitCount.getCount()));
|
||||
}
|
||||
catch (VcsException e) {
|
||||
//TODO show an error balloon or something else for non-ea guys.
|
||||
matchingCommits = Collections.emptySet();
|
||||
LOG.error(e);
|
||||
}
|
||||
}
|
||||
|
||||
canRequestMore = matchingCommits.size() >= commitCount.getCount(); // from VCS: only "==", but from memory can be ">"
|
||||
}
|
||||
|
||||
canRequestMore = matchingCommits.size() >= commitCount.getCount(); // from VCS: only "==", but from memory can be ">"
|
||||
}
|
||||
|
||||
VisibleGraph<Integer> visibleGraph;
|
||||
@@ -97,7 +106,7 @@ class VisiblePackBuilder {
|
||||
visibleGraph = EmptyVisibleGraph.getInstance();
|
||||
}
|
||||
else {
|
||||
visibleGraph = dataPack.getPermanentGraph().createVisibleGraph(sortType, matchingHeads, getMatchedCommitIndex(matchingCommits));
|
||||
visibleGraph = dataPack.getPermanentGraph().createVisibleGraph(sortType, matchingHeads, matchingCommits);
|
||||
}
|
||||
return Pair.create(new VisiblePack(dataPack, visibleGraph, canRequestMore, filters), commitCount);
|
||||
}
|
||||
|
||||
@@ -69,4 +69,16 @@ public class PersistentUtil {
|
||||
return IOUtil.openCleanOrResetBroken(() -> new PersistentBTreeEnumerator<>(storageFile, keyDescriptor, Page.PAGE_SIZE, null, version),
|
||||
storageFile);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static <V> PersistentHashMap<Integer, V> createPersistentHashMap(@NotNull DataExternalizer<V> externalizer,
|
||||
@NotNull String storageKind,
|
||||
@NotNull String logId,
|
||||
int version) throws IOException {
|
||||
File storageFile = getStorageFile(storageKind, logId, version);
|
||||
|
||||
return IOUtil
|
||||
.openCleanOrResetBroken(() -> new PersistentHashMap<>(storageFile, new IntInlineKeyDescriptor(), externalizer, Page.PAGE_SIZE),
|
||||
storageFile);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -201,7 +201,7 @@ public class VcsLogRefresherTest extends VcsPlatformTest {
|
||||
private VcsLogRefresherImpl createLoader(Consumer<DataPack> dataPackConsumer) {
|
||||
myLogData = new VcsLogData(myProject, myLogProviders, LOG::error);
|
||||
Disposer.register(myProject, myLogData);
|
||||
return new VcsLogRefresherImpl(myProject, myLogData.getHashMap(), myLogProviders, myLogData.getUserRegistry(),
|
||||
return new VcsLogRefresherImpl(myProject, myLogData.getHashMap(), myLogProviders, myLogData.getUserRegistry(), myLogData.getIndex(),
|
||||
myLogData.getTopCommitsCache(), dataPackConsumer, FAILING_EXCEPTION_HANDLER, RECENT_COMMITS_COUNT,
|
||||
myLogData) {
|
||||
@Override
|
||||
|
||||
@@ -156,7 +156,7 @@ class VisiblePackBuilderTest {
|
||||
return null
|
||||
}
|
||||
}
|
||||
val builder = VisiblePackBuilder(providers, hashMap, detailsCache, commitDetailsGetter)
|
||||
val builder = VisiblePackBuilder(providers, hashMap, detailsCache, commitDetailsGetter, EmptyIndex())
|
||||
|
||||
return builder.build(dataPack, PermanentGraph.SortType.Normal, filters, CommitCountStage.INITIAL).first
|
||||
}
|
||||
@@ -245,5 +245,21 @@ class VisiblePackBuilderTest {
|
||||
override fun flush() {
|
||||
}
|
||||
}
|
||||
|
||||
class EmptyIndex : VcsLogIndex {
|
||||
override fun canFilter(filters: MutableList<VcsLogDetailsFilter>): Boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
override fun scheduleIndex() {
|
||||
}
|
||||
|
||||
override fun markForIndexing(index: Int) {
|
||||
}
|
||||
|
||||
override fun filter(detailsFilters: MutableList<VcsLogDetailsFilter>): MutableSet<Int> {
|
||||
throw UnsupportedOperationException()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user