summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLeif Åstrand <leif@vaadin.com>2013-07-29 15:51:33 +0300
committerLeif Åstrand <leif@vaadin.com>2014-03-17 18:34:17 +0200
commit5d0b53bad905a2f77e4e75a3e307a69824c9b87d (patch)
tree2122cdf70d91f7533de4f3f0e31b10fec1792289
parent732c2c3bcd6aaaef29796c0cccdb4231e0561282 (diff)
downloadvaadin-framework-5d0b53bad905a2f77e4e75a3e307a69824c9b87d.tar.gz
vaadin-framework-5d0b53bad905a2f77e4e75a3e307a69824c9b87d.zip
Fix race condition that might leave access queue unpurged (#12292)
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
-rw-r--r--server/src/com/vaadin/server/VaadinService.java19
-rw-r--r--server/src/com/vaadin/server/VaadinSession.java14
2 files changed, 31 insertions, 2 deletions
diff --git a/server/src/com/vaadin/server/VaadinService.java b/server/src/com/vaadin/server/VaadinService.java
index c926efc67c..86cd9701c0 100644
--- a/server/src/com/vaadin/server/VaadinService.java
+++ b/server/src/com/vaadin/server/VaadinService.java
@@ -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;
}
/**
diff --git a/server/src/com/vaadin/server/VaadinSession.java b/server/src/com/vaadin/server/VaadinSession.java
index 265d18b859..619a329ab9 100644
--- a/server/src/com/vaadin/server/VaadinSession.java
+++ b/server/src/com/vaadin/server/VaadinSession.java
@@ -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);
+ }
}
/**