memory index storage reworked:

1. unneccesary synchronization removed
2. clear memory map on document save rather than on myBufferingEnabled flag change
This commit is contained in:
Eugene Zhuravlev
2009-10-28 19:51:04 +03:00
parent 9b11069523
commit d6e6921ab8
6 changed files with 113 additions and 97 deletions
@@ -351,6 +351,19 @@ public class StubIndexImpl extends StubIndex implements ApplicationComponent, Pe
}
}
public void cleanupMemoryStorage() {
for (UpdatableIndex index : myIndices.values()) {
final IndexStorage indexStorage = ((MapReduceIndex)index).getStorage();
index.getWriteLock().lock();
try {
((MemoryIndexStorage)indexStorage).clearMemoryMap();
}
finally {
index.getWriteLock().unlock();
}
}
}
public void clearAllIndices() {
for (UpdatableIndex index : myIndices.values()) {
@@ -217,6 +217,10 @@ public class StubUpdatingIndex extends CustomImplementationFileBasedIndexExtensi
public void bufferingStateChanged(final boolean newState) {
((StubIndexImpl)StubIndexImpl.getInstance()).setDataBufferingEnabled(newState);
}
public void memoryStorageCleared() {
((StubIndexImpl)StubIndexImpl.getInstance()).cleanupMemoryStorage();
}
});
}
return new MyIndex(indexId, owner, storage, getIndexer());
@@ -42,8 +42,10 @@ import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.util.registry.Registry;
import com.intellij.openapi.vfs.*;
import com.intellij.openapi.vfs.ex.VirtualFileManagerEx;
import com.intellij.openapi.vfs.newvfs.BulkFileListener;
import com.intellij.openapi.vfs.newvfs.ManagingFS;
import com.intellij.openapi.vfs.newvfs.NewVirtualFile;
import com.intellij.openapi.vfs.newvfs.events.VFileEvent;
import com.intellij.openapi.vfs.newvfs.impl.NullVirtualFile;
import com.intellij.openapi.vfs.newvfs.persistent.PersistentFS;
import com.intellij.psi.PsiDocumentManager;
@@ -200,6 +202,20 @@ public class FileBasedIndex implements ApplicationComponent {
}
});
connection.subscribe(VirtualFileManager.VFS_CHANGES, new BulkFileListener() {
public void before(List<? extends VFileEvent> events) {
for (VFileEvent event : events) {
if (event.getRequestor() instanceof FileDocumentManager) {
cleanupMemoryStorage();
break;
}
}
}
public void after(List<? extends VFileEvent> events) {
}
});
ApplicationManager.getApplication().addApplicationListener(new ApplicationAdapter() {
public void writeActionStarted(Object action) {
myUpToDateIndices.clear();
@@ -257,7 +273,7 @@ public class FileBasedIndex implements ApplicationComponent {
}
}
private String calcConfigPath(final String path) {
private static String calcConfigPath(final String path) {
try {
final String _path = FileUtil.toSystemIndependentName(new File(path).getCanonicalPath());
return _path.endsWith("/")? _path : _path + "/" ;
@@ -1078,11 +1094,6 @@ public class FileBasedIndex implements ApplicationComponent {
private StorageGuard.Holder setDataBufferingEnabled(final boolean enabled) {
final StorageGuard.Holder holder = myStorageLock.enter(enabled);
if (!enabled) {
synchronized (myLastIndexedDocStamps) {
myLastIndexedDocStamps.clear();
}
}
for (ID<?, ?> indexId : myIndices.keySet()) {
final MapReduceIndex index = (MapReduceIndex)getIndex(indexId);
assert index != null;
@@ -1092,6 +1103,25 @@ public class FileBasedIndex implements ApplicationComponent {
return holder;
}
private void cleanupMemoryStorage() {
synchronized (myLastIndexedDocStamps) {
myLastIndexedDocStamps.clear();
}
for (ID<?, ?> indexId : myIndices.keySet()) {
final MapReduceIndex index = (MapReduceIndex)getIndex(indexId);
assert index != null;
final MemoryIndexStorage memStorage = (MemoryIndexStorage)index.getStorage();
index.getWriteLock().lock();
try {
memStorage.clearMemoryMap();
}
finally {
index.getWriteLock().unlock();
}
memStorage.fireMemoryStorageCleared();
}
}
private void dropUnregisteredIndices() {
final Set<String> indicesToDrop = readRegistsredIndexNames();
for (ID<?, ?> key : myIndices.keySet()) {
@@ -20,13 +20,14 @@ import com.intellij.util.Processor;
import org.jetbrains.annotations.NotNull;
import java.io.Flushable;
import java.io.IOException;
import java.util.Collection;
/**
* @author Eugene Zhuravlev
* Date: Dec 10, 2007
*/
public interface IndexStorage<Key, Value> extends Flushable{
public interface IndexStorage<Key, Value> extends Flushable {
void addValue(Key key, int inputId, Value value) throws StorageException;
@@ -44,4 +45,6 @@ public interface IndexStorage<Key, Value> extends Flushable{
Collection<Key> getKeys() throws StorageException;
void close() throws StorageException;
void flush() throws IOException;
}
@@ -137,7 +137,7 @@ public final class MapIndexStorage<Key, Value> implements IndexStorage<Key, Valu
}
}
public synchronized void close() throws StorageException {
public void close() throws StorageException {
try {
flush();
myMap.close();
@@ -157,7 +157,7 @@ public final class MapIndexStorage<Key, Value> implements IndexStorage<Key, Valu
}
}
public synchronized void clear() throws StorageException{
public void clear() throws StorageException{
try {
myMap.close();
}
@@ -18,14 +18,12 @@ package com.intellij.util.indexing;
import com.intellij.util.CommonProcessors;
import com.intellij.util.Processor;
import com.intellij.util.concurrency.JBLock;
import com.intellij.util.concurrency.JBReentrantReadWriteLock;
import com.intellij.util.concurrency.LockFactory;
import com.intellij.util.containers.ContainerUtil;
import org.jetbrains.annotations.NotNull;
import java.io.IOException;
import java.util.*;
import java.util.concurrent.atomic.AtomicBoolean;
/**
* This storage is needed for indexing yet unsaved data without saving those changes to 'main' backend storage
@@ -36,14 +34,12 @@ import java.util.*;
public class MemoryIndexStorage<Key, Value> implements IndexStorage<Key, Value> {
private final Map<Key, UpdatableValueContainer<Value>> myMap = new HashMap<Key,UpdatableValueContainer<Value>>();
private final IndexStorage<Key, Value> myBackendStorage;
private boolean myBufferingEnabled = false;
private final List<BufferingStateListener> myListeners = ContainerUtil.createEmptyCOWList();
private final JBReentrantReadWriteLock myLock = LockFactory.createReadWriteLock();
private final JBLock r = myLock.readLock();
private final JBLock w = myLock.writeLock();
private final AtomicBoolean myBufferingEnabled = new AtomicBoolean(false);
public interface BufferingStateListener {
void bufferingStateChanged(boolean newState);
void memoryStorageCleared();
}
public MemoryIndexStorage(IndexStorage<Key, Value> backend) {
@@ -59,21 +55,21 @@ public class MemoryIndexStorage<Key, Value> implements IndexStorage<Key, Value>
}
public void setBufferingEnabled(boolean enabled) {
w.lock();
try {
final boolean wasEnabled = myBufferingEnabled;
myBufferingEnabled = enabled;
if (wasEnabled && !enabled) {
myMap.clear();
}
if (wasEnabled != enabled) {
for (BufferingStateListener listener : myListeners) {
listener.bufferingStateChanged(enabled);
}
final boolean wasEnabled = myBufferingEnabled.getAndSet(enabled);
if (wasEnabled != enabled) {
for (BufferingStateListener listener : myListeners) {
listener.bufferingStateChanged(enabled);
}
}
finally {
w.unlock();
}
public void clearMemoryMap() {
myMap.clear();
}
public void fireMemoryStorageCleared() {
for (BufferingStateListener listener : myListeners) {
listener.memoryStorageCleared();
}
}
@@ -82,14 +78,8 @@ public class MemoryIndexStorage<Key, Value> implements IndexStorage<Key, Value>
}
public void clear() throws StorageException {
w.lock();
try {
myMap.clear();
myBackendStorage.clear();
}
finally {
w.unlock();
}
clearMemoryMap();
myBackendStorage.clear();
}
public void flush() throws IOException {
@@ -103,75 +93,60 @@ public class MemoryIndexStorage<Key, Value> implements IndexStorage<Key, Value>
}
public boolean processKeys(final Processor<Key> processor) throws StorageException {
r.lock();
try {
if (myBufferingEnabled) {
final Set<Key> stopList = new HashSet<Key>();
final Set<Key> stopList = new HashSet<Key>();
Processor<Key> decoratingProcessor = new Processor<Key>() {
public boolean process(final Key key) {
if (stopList.contains(key)) return true;
Processor<Key> decoratingProcessor = new Processor<Key>() {
public boolean process(final Key key) {
if (stopList.contains(key)) return true;
final UpdatableValueContainer<Value> container = myMap.get(key);
if (container != null && container.size() == 0) return true;
return processor.process(key);
}
};
for (Key key : myMap.keySet()) {
if (!decoratingProcessor.process(key)) return false;
stopList.add(key);
}
return myBackendStorage.processKeys(decoratingProcessor);
final UpdatableValueContainer<Value> container = myMap.get(key);
if (container != null && container.size() == 0) return true;
return processor.process(key);
}
}
finally {
r.unlock();
}
};
return myBackendStorage.processKeys(processor);
for (Key key : myMap.keySet()) {
if (!decoratingProcessor.process(key)) return false;
stopList.add(key);
}
return myBackendStorage.processKeys(decoratingProcessor);
}
public void addValue(final Key key, final int inputId, final Value value) throws StorageException {
w.lock();
try {
if (myBufferingEnabled) {
getMemValueContainer(key).addValue(inputId, value);
return;
}
if (myBufferingEnabled.get()) {
getMemValueContainer(key).addValue(inputId, value);
return;
}
finally {
w.unlock();
final UpdatableValueContainer<Value> valueContainer = myMap.get(key);
if (valueContainer != null) {
valueContainer.addValue(inputId, value);
}
myBackendStorage.addValue(key, inputId, value);
}
public void removeValue(final Key key, final int inputId, final Value value) throws StorageException {
w.lock();
try {
if (myBufferingEnabled) {
getMemValueContainer(key).removeValue(inputId, value);
return;
}
if (myBufferingEnabled.get()) {
getMemValueContainer(key).removeValue(inputId, value);
return;
}
finally {
w.unlock();
final UpdatableValueContainer<Value> valueContainer = myMap.get(key);
if (valueContainer != null) {
valueContainer.removeValue(inputId, value);
}
myBackendStorage.removeValue(key, inputId, value);
}
public void removeAllValues(Key key, int inputId) throws StorageException {
w.lock();
try {
if (myBufferingEnabled) {
getMemValueContainer(key).removeAllValues(inputId);
return;
}
if (myBufferingEnabled.get()) {
getMemValueContainer(key).removeAllValues(inputId);
return;
}
finally {
w.unlock();
final UpdatableValueContainer<Value> valueContainer = myMap.get(key);
if (valueContainer != null) {
valueContainer.removeAllValues(inputId);
}
myBackendStorage.removeAllValues(key, inputId);
}
@@ -199,18 +174,9 @@ public class MemoryIndexStorage<Key, Value> implements IndexStorage<Key, Value>
@NotNull
public ValueContainer<Value> read(final Key key) throws StorageException {
r.lock();
try {
if (myBufferingEnabled) {
final ValueContainer<Value> valueContainer = myMap.get(key);
if (valueContainer != null) {
return valueContainer;
}
return myBackendStorage.read(key);
}
}
finally {
r.unlock();
final ValueContainer<Value> valueContainer = myMap.get(key);
if (valueContainer != null) {
return valueContainer;
}
return myBackendStorage.read(key);