performance: do not process changed document twice
authorAlexey Kudravtsev <cdr@intellij.com>
Wed, 7 Dec 2011 16:10:36 +0000 (20:10 +0400)
committerAlexey Kudravtsev <cdr@intellij.com>
Wed, 7 Dec 2011 16:12:05 +0000 (20:12 +0400)
platform/platform-impl/src/com/intellij/openapi/vfs/encoding/EncodingManagerImpl.java
platform/util/src/com/intellij/util/containers/Queue.java
platform/util/src/com/intellij/util/containers/TransferToEDTQueue.java

index 2c33fccf9e7d9ccdbc62cef3ae3f7f1db753798d..22e23f7c88a957e3b6c833894b27c678718aa73b 100644 (file)
@@ -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
index a4c634254132626a8acf9e51aae2456caf8803af..1dbe2e36756cabeee37e1e16556da24ab36c43bc 100644 (file)
@@ -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;
+  }
 }
index 2d83017b15e3afe7d0417ccce83b17cfed61c9a7..e0326f65cdaca5b8939ad46c79693faab2af82a4 100644 (file)
@@ -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