]> source.dussan.org Git - vaadin-framework.git/commitdiff
Fix race condition that might leave access queue unpurged (#12292)
authorLeif Åstrand <leif@vaadin.com>
Mon, 29 Jul 2013 12:51:33 +0000 (15:51 +0300)
committerLeif Åstrand <leif@vaadin.com>
Mon, 17 Mar 2014 16:34:17 +0000 (18:34 +0200)
Cherry-pick of 3a373efe (the original fix) and 2ff71f62 (fixing a
regression) that were marked to not be automatically merged from 7.1 to
master.

Change-Id: Iee1012486906d8c2c46cef94cfcd6d2b399d7a6b

server/src/com/vaadin/server/VaadinService.java
server/src/com/vaadin/server/VaadinSession.java

index c926efc67cb580291f4a78d23a2a87329bcb0f90..86cd9701c00712ae7121d520b3e7fa15405e50bb 100644 (file)
@@ -1696,6 +1696,23 @@ public abstract class VaadinService implements Serializable {
         FutureAccess future = new FutureAccess(session, runnable);
         session.getPendingAccessQueue().add(future);
 
+        ensureAccessQueuePurged(session);
+
+        return future;
+    }
+
+    /**
+     * Makes sure the pending access queue is purged for the provided session.
+     * If the session is currently locked by the current thread or some other
+     * thread, the queue will be purged when the session is unlocked. If the
+     * lock is not held by any thread, it is acquired and the queue is purged
+     * right away.
+     * 
+     * @since 7.1.2
+     * @param session
+     *            the session for which the access queue should be purged
+     */
+    public void ensureAccessQueuePurged(VaadinSession session) {
         /*
          * If no thread is currently holding the lock, pending changes for UIs
          * with automatic push would not be processed and pushed until the next
@@ -1718,8 +1735,6 @@ public abstract class VaadinService implements Serializable {
         } catch (InterruptedException e) {
             // Just ignore
         }
-
-        return future;
     }
 
     /**
index 265d18b8590b57c4f23193c6dcfd858624ab638a..619a329ab9a75911d8005d2f7641364ab7f8ae5a 100644 (file)
@@ -969,12 +969,14 @@ public class VaadinSession implements HttpSessionBindingListener, Serializable {
      */
     public void unlock() {
         assert hasLock();
+        boolean ultimateRelease = false;
         try {
             /*
              * Run pending tasks and push if the reentrant lock will actually be
              * released by this unlock() invocation.
              */
             if (((ReentrantLock) getLockInstance()).getHoldCount() == 1) {
+                ultimateRelease = true;
                 getService().runPendingAccessTasks(this);
 
                 for (UI ui : getUIs()) {
@@ -992,6 +994,18 @@ public class VaadinSession implements HttpSessionBindingListener, Serializable {
         } finally {
             getLockInstance().unlock();
         }
+
+        /*
+         * If the session is locked when a new access task is added, it is
+         * assumed that the queue will be purged when the lock is released. This
+         * might however not happen if a task is enqueued between the moment
+         * when unlock() purges the queue and the moment when the lock is
+         * actually released. This means that the queue should be purged again
+         * if it is not empty after unlocking.
+         */
+        if (ultimateRelease && !getPendingAccessQueue().isEmpty()) {
+            getService().ensureAccessQueuePurged(this);
+        }
     }
 
     /**