[log] IDEA-132229 Store cached details by int to avoid extra int-to-Hash conversion.

This commit is contained in:
Kirill Likhodedov
2014-12-05 19:01:49 +03:00
parent d07479bb45
commit e70dd1b448
13 changed files with 64 additions and 84 deletions
@@ -40,15 +40,6 @@ public interface VcsLog {
@NotNull
List<VcsFullCommitDetails> getSelectedDetails();
/**
* Returns details of the given commit, if they have been already loaded.
* In most cases they are already in the cache, and will be returned.
* Otherwise null is returned.
* Asynchronous loading of the details which are not yet available is done automatically from the log table component.
*/
@Nullable
VcsFullCommitDetails getDetailsIfAvailable(@NotNull Hash hash);
/**
* Returns names of branches which contain the given commit, or null if this information is unavailable.
*/
@@ -2,7 +2,6 @@ package com.intellij.vcs.log.data;
import com.intellij.openapi.vcs.VcsException;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.vcs.log.Hash;
import com.intellij.vcs.log.VcsFullCommitDetails;
import com.intellij.vcs.log.VcsLogProvider;
import org.jetbrains.annotations.NotNull;
@@ -17,12 +16,12 @@ import java.util.Map;
public class CommitDetailsGetter extends DataGetter<VcsFullCommitDetails> {
CommitDetailsGetter(VcsLogDataHolder dataHolder, @NotNull Map<VirtualFile, VcsLogProvider> logProviders) {
super(dataHolder, logProviders, new VcsCommitCache<VcsFullCommitDetails>());
super(dataHolder, logProviders, new VcsCommitCache<Integer, VcsFullCommitDetails>());
}
@Nullable
@Override
protected VcsFullCommitDetails getFromAdditionalCache(@NotNull Hash hash) {
protected VcsFullCommitDetails getFromAdditionalCache(int commitId) {
return null;
}
@@ -9,7 +9,6 @@ import com.intellij.util.ThrowableConsumer;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.containers.MultiMap;
import com.intellij.util.ui.UIUtil;
import com.intellij.vcs.log.Hash;
import com.intellij.vcs.log.VcsLogProvider;
import com.intellij.vcs.log.VcsShortCommitDetails;
import com.intellij.vcs.log.ui.tables.GraphTableModel;
@@ -42,7 +41,7 @@ public abstract class DataGetter<T extends VcsShortCommitDetails> implements Dis
@NotNull protected final VcsLogDataHolder myDataHolder;
@NotNull private final Map<VirtualFile, VcsLogProvider> myLogProviders;
@NotNull private final VcsCommitCache<T> myCache;
@NotNull private final VcsCommitCache<Integer, T> myCache;
@NotNull private final SequentialLimitedLifoExecutor<TaskDescriptor> myLoader;
/**
@@ -53,7 +52,7 @@ public abstract class DataGetter<T extends VcsShortCommitDetails> implements Dis
@NotNull private final Collection<Runnable> myLoadingFinishedListeners = new ArrayList<Runnable>();
DataGetter(@NotNull VcsLogDataHolder dataHolder, @NotNull Map<VirtualFile, VcsLogProvider> logProviders,
@NotNull VcsCommitCache<T> cache) {
@NotNull VcsCommitCache<Integer, T> cache) {
myDataHolder = dataHolder;
myLogProviders = logProviders;
myCache = cache;
@@ -83,10 +82,7 @@ public abstract class DataGetter<T extends VcsShortCommitDetails> implements Dis
@Nullable
public T getCommitData(int row, @NotNull GraphTableModel tableModel) {
assert EventQueue.isDispatchThread();
Hash hash = tableModel.getHashAtRow(row);
if (hash == null) {
return null;
}
Integer hash = tableModel.getCommitIdAtRow(row);
T details = getFromCache(hash);
if (details != null) {
return details;
@@ -96,44 +92,44 @@ public abstract class DataGetter<T extends VcsShortCommitDetails> implements Dis
}
@Nullable
public T getCommitDataIfAvailable(@NotNull Hash hash) {
public T getCommitDataIfAvailable(int hash) {
return getFromCache(hash);
}
@Nullable
private T getFromCache(@NotNull Hash hash) {
T details = myCache.get(hash);
private T getFromCache(@NotNull Integer commitId) {
T details = myCache.get(commitId);
if (details != null) {
if (details instanceof LoadingDetails) {
if (((LoadingDetails)details).getLoadingTaskIndex() <= myCurrentTaskIndex - MAX_LOADING_TASKS) {
// don't let old "loading" requests stay in the cache forever
myCache.remove(hash);
myCache.remove(commitId);
return null;
}
}
return details;
}
return getFromAdditionalCache(hash);
return getFromAdditionalCache(commitId);
}
/**
* Lookup somewhere else but the standard cache.
*/
@Nullable
protected abstract T getFromAdditionalCache(@NotNull Hash hash);
protected abstract T getFromAdditionalCache(int commitId);
private void runLoadAroundCommitData(int row, @NotNull GraphTableModel tableModel) {
long taskNumber = myCurrentTaskIndex++;
MultiMap<VirtualFile, Hash> commits = getCommitsAround(row, tableModel, UP_PRELOAD_COUNT, DOWN_PRELOAD_COUNT);
for (Map.Entry<VirtualFile, Collection<Hash>> hashesByRoots : commits.entrySet()) {
MultiMap<VirtualFile, Integer> commits = getCommitsAround(row, tableModel, UP_PRELOAD_COUNT, DOWN_PRELOAD_COUNT);
for (Map.Entry<VirtualFile, Collection<Integer>> hashesByRoots : commits.entrySet()) {
VirtualFile root = hashesByRoots.getKey();
Collection<Hash> hashes = hashesByRoots.getValue();
Collection<Integer> hashes = hashesByRoots.getValue();
// fill the cache with temporary "Loading" values to avoid producing queries for each commit that has not been cached yet,
// even if it will be loaded within a previous query
for (Hash hash : hashes) {
if (!myCache.isKeyCached(hash)) {
myCache.put(hash, (T)new LoadingDetails(hash, taskNumber, root));
for (int commitId : hashes) {
if (!myCache.isKeyCached(commitId)) {
myCache.put(commitId, (T)new LoadingDetails(myDataHolder.getHash(commitId), taskNumber, root));
}
}
}
@@ -143,25 +139,25 @@ public abstract class DataGetter<T extends VcsShortCommitDetails> implements Dis
}
@NotNull
private static MultiMap<VirtualFile, Hash> getCommitsAround(int selectedRow, @NotNull GraphTableModel model,
int above, int below) {
MultiMap<VirtualFile, Hash> commits = MultiMap.create();
private static MultiMap<VirtualFile, Integer> getCommitsAround(int selectedRow,
@NotNull GraphTableModel model,
int above,
int below) {
MultiMap<VirtualFile, Integer> commits = MultiMap.create();
for (int row = Math.max(0, selectedRow - above); row < selectedRow + below && row < model.getRowCount(); row++) {
Hash hash = model.getHashAtRow(row);
if (hash != null) {
VirtualFile root = model.getRoot(row);
commits.putValue(root, hash);
}
Integer hash = model.getCommitIdAtRow(row);
VirtualFile root = model.getRoot(row);
commits.putValue(root, hash);
}
return commits;
}
private void preLoadCommitData(@NotNull MultiMap<VirtualFile, Hash> commits) throws VcsException {
for (Map.Entry<VirtualFile, Collection<Hash>> entry : commits.entrySet()) {
List<String> hashStrings = ContainerUtil.map(entry.getValue(), new Function<Hash, String>() {
private void preLoadCommitData(@NotNull MultiMap<VirtualFile, Integer> commits) throws VcsException {
for (Map.Entry<VirtualFile, Collection<Integer>> entry : commits.entrySet()) {
List<String> hashStrings = ContainerUtil.map(entry.getValue(), new Function<Integer, String>() {
@Override
public String fun(Hash hash) {
return hash.asString();
public String fun(Integer commitId) {
return myDataHolder.getHash(commitId).asString();
}
});
List<? extends T> details = readDetails(myLogProviders.get(entry.getKey()), entry.getKey(), hashStrings);
@@ -174,7 +170,7 @@ public abstract class DataGetter<T extends VcsShortCommitDetails> implements Dis
@Override
public void run() {
for (T data : details) {
myCache.put(data.getId(), data);
myCache.put(myDataHolder.getCommitIndex(data.getId()), data);
}
}
});
@@ -193,9 +189,9 @@ public abstract class DataGetter<T extends VcsShortCommitDetails> implements Dis
}
private static class TaskDescriptor {
private final MultiMap<VirtualFile, Hash> myCommits;
private final MultiMap<VirtualFile, Integer> myCommits;
private TaskDescriptor(MultiMap<VirtualFile, Hash> commits) {
private TaskDescriptor(MultiMap<VirtualFile, Integer> commits) {
myCommits = commits;
}
}
@@ -2,7 +2,6 @@ package com.intellij.vcs.log.data;
import com.intellij.openapi.vcs.VcsException;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.vcs.log.Hash;
import com.intellij.vcs.log.VcsLogProvider;
import com.intellij.vcs.log.VcsShortCommitDetails;
import org.jetbrains.annotations.NotNull;
@@ -14,13 +13,13 @@ import java.util.Map;
public class MiniDetailsGetter extends DataGetter<VcsShortCommitDetails> {
MiniDetailsGetter(@NotNull VcsLogDataHolder dataHolder, @NotNull Map<VirtualFile, VcsLogProvider> logProviders) {
super(dataHolder, logProviders, new VcsCommitCache<VcsShortCommitDetails>());
super(dataHolder, logProviders, new VcsCommitCache<Integer, VcsShortCommitDetails>());
}
@Nullable
@Override
protected VcsShortCommitDetails getFromAdditionalCache(@NotNull Hash hash) {
return myDataHolder.getTopCommitDetails(hash);
protected VcsShortCommitDetails getFromAdditionalCache(int commitId) {
return myDataHolder.getTopCommitDetails(commitId);
}
@NotNull
@@ -16,7 +16,6 @@
package com.intellij.vcs.log.data;
import com.intellij.util.containers.SLRUMap;
import com.intellij.vcs.log.Hash;
import com.intellij.vcs.log.VcsShortCommitDetails;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -32,27 +31,27 @@ import java.awt.*;
*
* @author Kirill Likhodedov
*/
class VcsCommitCache<T extends VcsShortCommitDetails> {
class VcsCommitCache<CommitId, T extends VcsShortCommitDetails> {
private final SLRUMap<Hash, T> myCache = new SLRUMap<Hash, T>(5000, 5000);
private final SLRUMap<CommitId, T> myCache = new SLRUMap<CommitId, T>(5000, 5000);
public void put(@NotNull Hash hash, @NotNull T commit) {
public void put(@NotNull CommitId hash, @NotNull T commit) {
assert EventQueue.isDispatchThread();
myCache.put(hash, commit);
}
public boolean isKeyCached(@NotNull Hash hash) {
public boolean isKeyCached(@NotNull CommitId hash) {
assert EventQueue.isDispatchThread();
return myCache.get(hash) != null;
}
@Nullable
public T get(@NotNull Hash hash) {
public T get(@NotNull CommitId hash) {
assert EventQueue.isDispatchThread();
return myCache.get(hash);
}
public void remove(@NotNull Hash hash) {
public void remove(@NotNull CommitId hash) {
myCache.remove(hash);
}
@@ -64,7 +64,7 @@ public class VcsLogDataHolder implements Disposable, VcsLogDataProvider {
* which is important because these details will be constantly visible to the user,
* thus it would be annoying to re-load them from VCS if the cache overflows.
*/
@NotNull private final Map<Hash, VcsCommitMetadata> myTopCommitsDetailsCache = ContainerUtil.newConcurrentMap();
@NotNull private final Map<Integer, VcsCommitMetadata> myTopCommitsDetailsCache = ContainerUtil.newConcurrentMap();
private final VcsUserRegistryImpl myUserRegistry;
@@ -249,8 +249,8 @@ public class VcsLogDataHolder implements Disposable, VcsLogDataProvider {
}
@Nullable
public VcsCommitMetadata getTopCommitDetails(@NotNull Hash hash) {
return myTopCommitsDetailsCache.get(hash);
public VcsCommitMetadata getTopCommitDetails(@NotNull Integer commitId) {
return myTopCommitsDetailsCache.get(commitId);
}
public CommitDetailsGetter getCommitDetailsGetter() {
@@ -50,7 +50,7 @@ public class VcsLogFiltererImpl implements VcsLogFilterer {
VcsLogFiltererImpl(@NotNull final Project project,
@NotNull Map<VirtualFile, VcsLogProvider> providers,
@NotNull VcsLogHashMap hashMap,
@NotNull Map<Hash, VcsCommitMetadata> topCommitsDetailsCache,
@NotNull Map<Integer, VcsCommitMetadata> topCommitsDetailsCache,
@NotNull CommitDetailsGetter detailsGetter,
@NotNull final PermanentGraph.SortType initialSortType,
@NotNull final Consumer<VisiblePack> visiblePackConsumer) {
@@ -46,7 +46,7 @@ public class VcsLogRefresherImpl implements VcsLogRefresher {
@NotNull private final VcsLogHashMap myHashMap;
@NotNull private final Map<VirtualFile, VcsLogProvider> myProviders;
@NotNull private final VcsUserRegistryImpl myUserRegistry;
@NotNull private final Map<Hash, VcsCommitMetadata> myTopCommitsDetailsCache;
@NotNull private final Map<Integer, VcsCommitMetadata> myTopCommitsDetailsCache;
@NotNull private final Consumer<Exception> myExceptionHandler;
private final int myRecentCommitCount;
@@ -58,7 +58,7 @@ public class VcsLogRefresherImpl implements VcsLogRefresher {
@NotNull VcsLogHashMap hashMap,
@NotNull Map<VirtualFile, VcsLogProvider> providers,
@NotNull final VcsUserRegistryImpl userRegistry,
@NotNull Map<Hash, VcsCommitMetadata> topCommitsDetailsCache,
@NotNull Map<Integer, VcsCommitMetadata> topCommitsDetailsCache,
@NotNull final Consumer<DataPack> dataPackUpdateHandler,
@NotNull Consumer<Exception> exceptionHandler,
int recentCommitsCount) {
@@ -179,7 +179,7 @@ public class VcsLogRefresherImpl implements VcsLogRefresher {
for (VcsCommitMetadata detail : metadatas) {
myUserRegistry.addUser(detail.getAuthor());
myUserRegistry.addUser(detail.getCommitter());
myTopCommitsDetailsCache.put(detail.getId(), detail);
myTopCommitsDetailsCache.put(myHashMap.getCommitIndex(detail.getId()), detail);
}
}
@@ -40,13 +40,13 @@ class VisiblePackBuilder {
private static final Logger LOG = Logger.getInstance(VisiblePackBuilder.class);
@NotNull private final VcsLogHashMap myHashMap;
@NotNull private final Map<Hash, VcsCommitMetadata> myTopCommitsDetailsCache;
@NotNull private final Map<Integer, VcsCommitMetadata> myTopCommitsDetailsCache;
@NotNull private final CommitDetailsGetter myCommitDetailsGetter;
@NotNull private final Map<VirtualFile, VcsLogProvider> myLogProviders;
VisiblePackBuilder(@NotNull Map<VirtualFile, VcsLogProvider> providers,
@NotNull VcsLogHashMap hashMap,
@NotNull Map<Hash, VcsCommitMetadata> topCommitsDetailsCache,
@NotNull Map<Integer, VcsCommitMetadata> topCommitsDetailsCache,
@NotNull CommitDetailsGetter detailsGetter) {
myHashMap = hashMap;
myTopCommitsDetailsCache = topCommitsDetailsCache;
@@ -213,15 +213,14 @@ class VisiblePackBuilder {
@Nullable
private VcsCommitMetadata getDetailsFromCache(final int commitIndex) {
final Hash hash = myHashMap.getHash(commitIndex);
VcsCommitMetadata details = myTopCommitsDetailsCache.get(hash);
VcsCommitMetadata details = myTopCommitsDetailsCache.get(commitIndex);
if (details != null) {
return details;
}
return UIUtil.invokeAndWaitIfNeeded(new Computable<VcsCommitMetadata>() {
@Override
public VcsCommitMetadata compute() {
return myCommitDetailsGetter.getCommitDataIfAvailable(hash);
return myCommitDetailsGetter.getCommitDataIfAvailable(commitIndex);
}
});
}
@@ -72,12 +72,6 @@ public class VcsLogImpl implements VcsLog {
return details;
}
@Override
@Nullable
public VcsFullCommitDetails getDetailsIfAvailable(@NotNull final Hash hash) {
return myDataHolder.getCommitDetailsGetter().getCommitDataIfAvailable(hash);
}
@Nullable
@Override
public Collection<String> getContainingBranches(@NotNull Hash commitHash) {
@@ -165,9 +165,8 @@ class DetailsPanel extends JPanel implements ListSelectionListener {
((CardLayout)getLayout()).show(this, STANDARD_LAYER);
int row = rows[0];
GraphTableModel tableModel = (GraphTableModel)myGraphTable.getModel();
Hash hash = tableModel.getHashAtRow(row);
VcsFullCommitDetails commitData = myLogDataHolder.getCommitDetailsGetter().getCommitData(row, tableModel);
if (commitData == null || hash == null) {
if (commitData == null) {
showMessage("No commits selected");
return;
}
@@ -180,14 +179,14 @@ class DetailsPanel extends JPanel implements ListSelectionListener {
else {
myLoadingPanel.stopLoading();
myCommitDetailsPanel.setData(commitData);
myRefsPanel.setRefs(sortRefs(hash, commitData.getRoot()));
myRefsPanel.setRefs(sortRefs(commitData.getId(), commitData.getRoot()));
updateDetailsBorder(commitData);
newCommitDetails = commitData;
}
List<String> branches = null;
if (!(commitData instanceof LoadingDetails)) {
branches = myLogDataHolder.getContainingBranchesGetter().requestContainingBranches(commitData.getRoot(), hash);
branches = myLogDataHolder.getContainingBranchesGetter().requestContainingBranches(commitData.getRoot(), commitData.getId());
}
myCommitDetailsPanel.setBranches(branches);
@@ -114,9 +114,14 @@ public class GraphTableModel extends AbstractTableModel {
return new GraphCommitCell(message, refs);
}
@NotNull
public Integer getCommitIdAtRow(int row) {
return myDataPack.getVisibleGraph().getRowInfo(row).getCommit();
}
@Nullable
public Hash getHashAtRow(int row) {
return myDataHolder.getHash(myDataPack.getVisibleGraph().getRowInfo(row).getCommit());
return myDataHolder.getHash(getCommitIdAtRow(row));
}
public int getRowOfCommit(@NotNull final Hash hash) {
@@ -21,7 +21,6 @@ import com.intellij.util.Consumer;
import com.intellij.util.Function;
import com.intellij.util.concurrency.FutureResult;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.containers.HashMap;
import com.intellij.vcs.log.*;
import com.intellij.vcs.log.graph.GraphCommit;
import com.intellij.vcs.log.impl.*;
@@ -48,7 +47,7 @@ public class VcsLogRefresherTest extends VcsLogPlatformTest {
};
private TestVcsLogProvider myLogProvider;
private VcsLogDataHolder myDataHolder;
private Map<Hash, VcsCommitMetadata> myTopDetailsCache;
private Map<Integer, VcsCommitMetadata> myTopDetailsCache;
private Map<VirtualFile, VcsLogProvider> myLogProviders;
private List<String> myCommits;
@@ -58,7 +57,7 @@ public class VcsLogRefresherTest extends VcsLogPlatformTest {
myLogProvider = new TestVcsLogProvider(myProjectRoot);
myLogProviders = Collections.<VirtualFile, VcsLogProvider>singletonMap(myProjectRoot, myLogProvider);
myTopDetailsCache = new HashMap<Hash, VcsCommitMetadata>();
myTopDetailsCache = ContainerUtil.newHashMap();
myCommits = Arrays.asList("3|-a2|-a1", "2|-a1|-a", "1|-a|-");
myLogProvider.appendHistory(log(myCommits));