performance: do not process changed document twice

This commit is contained in:
Alexey Kudravtsev
2011-12-07 20:12:05 +04:00
parent e453c2342c
commit ea554e69d3
3 changed files with 73 additions and 14 deletions
@@ -47,6 +47,7 @@ import com.intellij.openapi.vfs.CharsetToolkit;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.util.Alarm;
import com.intellij.util.Processor;
import gnu.trove.Equality;
import gnu.trove.THashSet;
import org.jdom.Element;
import org.jetbrains.annotations.NonNls;
@@ -69,6 +70,12 @@ import java.util.Set;
}
)
public class EncodingManagerImpl extends EncodingManager implements PersistentStateComponent<Element>, Disposable {
public static final Equality<Reference<Document>> REFERENCE_EQUALITY = new Equality<Reference<Document>>() {
@Override
public boolean equals(Reference<Document> o1, Reference<Document> o2) {
return o1.get() == o2.get();
}
};
private final PropertyChangeSupport myPropertyChangeSupport = new PropertyChangeSupport(this);
private String myDefaultEncoding = CharsetToolkit.UTF8;
private Charset myCachedCharset = null;
@@ -129,7 +136,7 @@ public class EncodingManagerImpl extends EncodingManager implements PersistentSt
}
public void queueUpdateEncodingFromContent(@NotNull Document document) {
myChangedDocuments.offer(new WeakReference<Document>(document));
myChangedDocuments.offerIfAbsent(new WeakReference<Document>(document), REFERENCE_EQUALITY);
}
@Override
@@ -16,6 +16,8 @@
package com.intellij.util.containers;
import com.intellij.util.ArrayUtil;
import com.intellij.util.Processor;
import org.jetbrains.annotations.NotNull;
import java.util.Arrays;
import java.util.List;
@@ -66,7 +68,7 @@ public class Queue<T> {
}
public T pullFirst() {
T result = (T)myArray[myFirst];
T result = peekFirst();
myArray[myFirst] = null;
myFirst++;
if (myFirst == myArray.length) {
@@ -77,6 +79,9 @@ public class Queue<T> {
}
public T peekFirst() {
if (isEmpty()) {
throw new IndexOutOfBoundsException("queue is empty");
}
return (T)myArray[myFirst];
}
@@ -99,10 +104,27 @@ public class Queue<T> {
}
public void clear() {
for (int i = 0; i < myArray.length; i++) {
myArray[i] = null;
}
isWrapped = false;
Arrays.fill(myArray, null);
myFirst = myLast = 0;
}
public boolean process(@NotNull Processor<T> processor) {
if (isWrapped) {
for (int i = myFirst; i < myArray.length; i++) {
T t = (T)myArray[i];
if (!processor.process(t)) return false;
}
for (int i = 0; i < myLast; i++) {
T t = (T)myArray[i];
if (!processor.process(t)) return false;
}
}
else {
for (int i = myFirst; i < myLast; i++) {
T t = (T)myArray[i];
if (!processor.process(t)) return false;
}
}
return true;
}
}
@@ -17,12 +17,11 @@ package com.intellij.util.containers;
import com.intellij.openapi.util.Condition;
import com.intellij.util.Processor;
import gnu.trove.Equality;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import javax.swing.*;
import java.util.Queue;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.atomic.AtomicBoolean;
/**
@@ -38,7 +37,7 @@ public class TransferToEDTQueue<T> {
private final Condition<?> myShutUpCondition;
private final int myMaxUnitOfWorkThresholdMs; //-1 means indefinite
private final Queue<T> myQueue = new ConcurrentLinkedQueue<T>();
private final Queue<T> myQueue = new Queue<T>(10);
private final AtomicBoolean invokeLaterScheduled = new AtomicBoolean();
private final Runnable myUpdateRunnable = new Runnable() {
@Override
@@ -61,14 +60,23 @@ public class TransferToEDTQueue<T> {
long finish = System.currentTimeMillis();
if (myMaxUnitOfWorkThresholdMs != -1 && finish - start > myMaxUnitOfWorkThresholdMs) break;
}
if (!myQueue.isEmpty()) {
if (!isEmpty()) {
scheduleUpdate();
}
}
};
private boolean isEmpty() {
synchronized (myQueue) {
return myQueue.isEmpty();
}
}
private boolean processNext() {
T thing = myQueue.poll();
T thing;
synchronized (myQueue) {
thing = myQueue.isEmpty() ? null : myQueue.pullFirst();
}
if (thing == null) return false;
if (!myProcessor.process(thing)) {
stop();
@@ -84,9 +92,29 @@ public class TransferToEDTQueue<T> {
myMaxUnitOfWorkThresholdMs = maxUnitOfWorkThresholdMs;
}
public void offer(@NotNull T thing) {
myQueue.offer(thing);
public boolean offer(@NotNull T thing) {
synchronized (myQueue) {
myQueue.addLast(thing);
}
scheduleUpdate();
return true;
}
public boolean offerIfAbsent(@NotNull final T thing, @NotNull final Equality<T> equality) {
boolean absent;
synchronized (myQueue) {
absent = myQueue.process(new Processor<T>() {
@Override
public boolean process(T t) {
return !equality.equals(t, thing);
}
});
if (absent) {
myQueue.addLast(thing);
scheduleUpdate();
}
}
return absent;
}
private void scheduleUpdate() {
@@ -101,7 +129,9 @@ public class TransferToEDTQueue<T> {
public void stop() {
stopped = true;
myQueue.clear();
synchronized (myQueue) {
myQueue.clear();
}
}
// process all queue in current thread