[vcs-log] add users index

This commit is contained in:
Julia Beliaeva
2016-09-20 00:15:17 +03:00
parent 77c1ff4cd4
commit f396310784
5 changed files with 215 additions and 35 deletions
@@ -125,6 +125,15 @@ public class VcsUserRegistryImpl implements Disposable, VcsUserRegistry {
}
}
public int getUserId(@NotNull VcsUser user) throws IOException {
return myPersistentEnumerator.enumerate(user);
}
@Nullable
public VcsUser getUserById(Integer userId) throws IOException {
return myPersistentEnumerator.valueOf(userId);
}
private class MyDescriptor implements KeyDescriptor<VcsUser> {
@Override
public void save(@NotNull DataOutput out, VcsUser value) throws IOException {
@@ -17,6 +17,8 @@ package com.intellij.vcs.log.data.index;
import com.intellij.openapi.Disposable;
import com.intellij.openapi.util.Disposer;
import com.intellij.openapi.util.Ref;
import com.intellij.util.Consumer;
import com.intellij.util.PathUtilRt;
import com.intellij.util.indexing.*;
import com.intellij.util.io.DataExternalizer;
@@ -54,31 +56,47 @@ public class VcsLogFullDetailsIndex implements Disposable {
Disposer.register(disposableParent, this);
}
@NotNull
public TIntHashSet getCommitsWithAnyKey(@NotNull Set<Integer> keys) throws StorageException {
TIntHashSet result = new TIntHashSet();
for (Integer key : keys) {
iterateCommitIds(key, result::add);
}
return result;
}
@NotNull
public TIntHashSet getCommitsWithAllKeys(@NotNull Set<Integer> keys) throws StorageException {
TIntHashSet result = null;
Ref<TIntHashSet> result = new Ref<>(null);
for (Integer key : keys) {
TIntHashSet newResult = new TIntHashSet();
ValueContainer<Void> data = myMapReduceIndex.getData(key);
ValueContainer.ValueIterator<Void> valueIt = data.getValueIterator();
while (valueIt.hasNext()) {
valueIt.next();
ValueContainer.IntIterator inputIt = valueIt.getInputIdsIterator();
while (inputIt.hasNext()) {
int id = inputIt.next();
if (result == null || result.contains(id)) {
newResult.add(id);
}
iterateCommitIds(key, integer -> {
if (result.get() == null || result.get().contains(integer)) {
newResult.add(integer);
}
}
});
result = newResult;
result.set(newResult);
}
if (result == null) return new TIntHashSet();
return result;
if (result.get() == null) return new TIntHashSet();
return result.get();
}
private void iterateCommitIds(int key, @NotNull Consumer<Integer> consumer) throws StorageException {
ValueContainer<Void> data = myMapReduceIndex.getData(key);
ValueContainer.ValueIterator<Void> valueIt = data.getValueIterator();
while (valueIt.hasNext()) {
valueIt.next();
ValueContainer.IntIterator inputIt = valueIt.getInputIdsIterator();
while (inputIt.hasNext()) {
consumer.consume(inputIt.next());
}
}
}
public void update(int commitId, @NotNull VcsFullCommitDetails details) throws IOException {
@@ -17,6 +17,7 @@ package com.intellij.vcs.log.data.index;
import com.intellij.openapi.Disposable;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.components.ServiceManager;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.progress.PerformInBackgroundOption;
import com.intellij.openapi.progress.ProgressIndicator;
@@ -27,6 +28,7 @@ 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.ThrowableComputable;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vcs.VcsException;
import com.intellij.openapi.vfs.VirtualFile;
@@ -34,10 +36,16 @@ import com.intellij.util.Consumer;
import com.intellij.util.Processor;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.indexing.StorageException;
import com.intellij.util.io.*;
import com.intellij.util.io.EnumeratorStringDescriptor;
import com.intellij.util.io.KeyDescriptor;
import com.intellij.util.io.PersistentHashMap;
import com.intellij.util.io.PersistentMap;
import com.intellij.vcs.log.*;
import com.intellij.vcs.log.data.CommitDetailsGetter;
import com.intellij.vcs.log.data.InMemoryMap;
import com.intellij.vcs.log.data.TroveUtil;
import com.intellij.vcs.log.data.VcsUserRegistryImpl;
import com.intellij.vcs.log.ui.filter.VcsLogUserFilterImpl;
import com.intellij.vcs.log.util.PersistentUtil;
import gnu.trove.TIntHashSet;
import gnu.trove.TIntProcedure;
@@ -59,9 +67,12 @@ public class VcsLogPersistentIndex implements VcsLogIndex, Disposable {
@NotNull private final Consumer<Exception> myFatalErrorsConsumer;
@NotNull private final CommitDetailsGetter myDetailsGetter;
@NotNull private final VcsLogStorage myHashMap;
@NotNull private final VcsUserRegistryImpl myUserRegistry;
@NotNull private final Set<VirtualFile> myRoots;
@NotNull private final PersistentMap<Integer, String> myMessagesIndex;
@Nullable private final VcsLogMessagesTrigramIndex myTrigramIndex;
@Nullable private final VcsLogUserIndex myUserIndex;
@NotNull private TIntHashSet myCommitsToIndex = new TIntHashSet();
@@ -75,28 +86,34 @@ public class VcsLogPersistentIndex implements VcsLogIndex, Disposable {
myProject = project;
myDetailsGetter = detailsGetter;
myFatalErrorsConsumer = fatalErrorsConsumer;
myRoots = providers.keySet();
myUserRegistry = (VcsUserRegistryImpl)ServiceManager.getService(myProject, VcsUserRegistry.class);
String logId = PersistentUtil.calcLogId(myProject, providers);
myMessagesIndex = createIndex(EnumeratorStringDescriptor.INSTANCE, "messages", logId, 0);
VcsLogMessagesTrigramIndex trigramIndex;
try {
trigramIndex = new VcsLogMessagesTrigramIndex(logId, disposableParent);
}
catch (IOException e) {
myFatalErrorsConsumer.consume(e);
trigramIndex = null;
}
myTrigramIndex = trigramIndex;
myMessagesIndex = createMap(EnumeratorStringDescriptor.INSTANCE, "messages", logId, 0);
myTrigramIndex = createIndex(() -> new VcsLogMessagesTrigramIndex(logId, this));
myUserIndex = createIndex(() -> new VcsLogUserIndex(logId, myUserRegistry, this));
Disposer.register(disposableParent, this);
}
@Nullable
private <I extends VcsLogFullDetailsIndex> I createIndex(@NotNull ThrowableComputable<I, IOException> computable) {
try {
return computable.compute();
}
catch (IOException e) {
myFatalErrorsConsumer.consume(e);
}
return null;
}
@NotNull
private <V> PersistentMap<Integer, V> createIndex(@NotNull KeyDescriptor<V> descriptor,
@NotNull String kind,
@NotNull String logId, int version) {
private <V> PersistentMap<Integer, V> createMap(@NotNull KeyDescriptor<V> descriptor,
@NotNull String kind,
@NotNull String logId, int version) {
try {
return PersistentUtil.createPersistentHashMap(descriptor, kind, logId, version);
}
@@ -141,10 +158,13 @@ public class VcsLogPersistentIndex implements VcsLogIndex, Disposable {
myMessagesIndex.put(index, detail.getFullMessage());
if (myTrigramIndex != null) myTrigramIndex.update(index, detail);
if (myUserIndex != null) myUserIndex.update(index, detail);
}
myMessagesIndex.force();
if (myTrigramIndex != null) myTrigramIndex.flush();
} catch (IOException | StorageException e) {
if (myUserIndex != null) myUserIndex.flush();
}
catch (IOException | StorageException e) {
myFatalErrorsConsumer.consume(e);
}
}
@@ -152,6 +172,7 @@ public class VcsLogPersistentIndex implements VcsLogIndex, Disposable {
public boolean isIndexed(int commit) {
try {
return myMessagesIndex.get(commit) != null &&
(myUserIndex == null || myUserIndex.isIndexed(commit)) &&
(myTrigramIndex == null || myTrigramIndex.isIndexed(commit));
}
catch (IOException e) {
@@ -198,6 +219,19 @@ public class VcsLogPersistentIndex implements VcsLogIndex, Disposable {
return result;
}
@NotNull
private TIntHashSet filterUsers(@NotNull Set<VcsUser> users) {
if (myUserIndex != null) {
try {
return myUserIndex.getCommitsForUsers(users);
}
catch (IOException | StorageException e) {
myFatalErrorsConsumer.consume(e);
}
}
return new TIntHashSet();
}
@NotNull
public TIntHashSet filterMessages(@NotNull String text) {
if (myTrigramIndex != null) {
@@ -239,7 +273,8 @@ public class VcsLogPersistentIndex implements VcsLogIndex, Disposable {
public boolean canFilter(@NotNull List<VcsLogDetailsFilter> filters) {
if (filters.isEmpty()) return false;
for (VcsLogDetailsFilter filter : filters) {
if (!(filter instanceof VcsLogTextFilter)) {
if (!((filter instanceof VcsLogTextFilter && myTrigramIndex != null) ||
(filter instanceof VcsLogUserFilterImpl && myUserIndex != null))) {
return false;
}
}
@@ -252,9 +287,42 @@ public class VcsLogPersistentIndex implements VcsLogIndex, Disposable {
Set<Integer> result = ContainerUtil.newHashSet();
VcsLogTextFilter textFilter = ContainerUtil.findInstance(detailsFilters, VcsLogTextFilter.class);
VcsLogUserFilterImpl userFilter = ContainerUtil.findInstance(detailsFilters, VcsLogUserFilterImpl.class);
TIntHashSet filteredByMessage;
if (textFilter != null) {
filterMessages(textFilter.getText()).forEach(value -> {
result.add(value);
filteredByMessage = filterMessages(textFilter.getText());
}
else {
filteredByMessage = null;
}
TIntHashSet filteredByUser;
if (userFilter != null) {
Set<VcsUser> users = ContainerUtil.newHashSet();
for (VirtualFile root : myRoots) {
users.addAll(userFilter.getUsers(root));
}
filteredByUser = filterUsers(users);
}
else {
filteredByUser = null;
}
if (filteredByMessage == null) {
if (filteredByUser != null) {
filteredByUser.forEach(value -> {
result.add(value);
return true;
});
}
}
else {
filteredByMessage.forEach(value -> {
if (filteredByUser != null && filteredByUser.contains(value)) {
result.add(value);
}
return true;
});
}
@@ -0,0 +1,76 @@
/*
* 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.index;
import com.intellij.openapi.Disposable;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.indexing.DataIndexer;
import com.intellij.util.indexing.StorageException;
import com.intellij.vcs.log.VcsFullCommitDetails;
import com.intellij.vcs.log.VcsUser;
import com.intellij.vcs.log.data.VcsUserRegistryImpl;
import gnu.trove.THashMap;
import gnu.trove.TIntHashSet;
import org.jetbrains.annotations.NotNull;
import java.io.IOException;
import java.util.Map;
import java.util.Set;
public class VcsLogUserIndex extends VcsLogFullDetailsIndex {
private static final Logger LOG = Logger.getInstance(VcsLogUserIndex.class);
private static final int VERSION = 0;
@NotNull private final VcsUserRegistryImpl myUserRegistry;
public VcsLogUserIndex(@NotNull String logId,
@NotNull VcsUserRegistryImpl userRegistry,
@NotNull Disposable disposableParent) throws IOException {
super(logId, "users", VERSION, new UserIndexer(userRegistry), disposableParent);
myUserRegistry = userRegistry;
}
public TIntHashSet getCommitsForUsers(@NotNull Set<VcsUser> users) throws IOException, StorageException {
Set<Integer> ids = ContainerUtil.newHashSet();
for (VcsUser user : users) {
ids.add(myUserRegistry.getUserId(user));
}
return getCommitsWithAnyKey(ids);
}
private static class UserIndexer implements DataIndexer<Integer, Void, VcsFullCommitDetails> {
@NotNull private final VcsUserRegistryImpl myRegistry;
public UserIndexer(@NotNull VcsUserRegistryImpl registry) {
myRegistry = registry;
}
@NotNull
@Override
public Map<Integer, Void> map(@NotNull VcsFullCommitDetails inputData) {
Map<Integer, Void> result = new THashMap<>();
try {
result.put(myRegistry.getUserId(inputData.getAuthor()), null);
}
catch (IOException e) {
LOG.error(e);
}
return result;
}
}
}
@@ -59,6 +59,15 @@ public class VcsLogUserFilterImpl implements VcsLogUserFilter {
return result;
}
@NotNull
public Collection<VcsUser> getUsers(@NotNull VirtualFile root) {
Set<VcsUser> result = ContainerUtil.newHashSet();
for (String user : myUsers) {
result.addAll(getUsers(root, user));
}
return result;
}
@NotNull
private Set<VcsUser> getUsers(@NotNull VirtualFile root, @NotNull String name) {
Set<VcsUser> users = ContainerUtil.newHashSet();