aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFabian Lange <lange.fabian@gmail.com>2014-03-12 12:47:00 +0100
committerVaadin Code Review <review@vaadin.com>2014-03-13 12:33:07 +0000
commit7e7b6239ca8867d13e8d8b279a0541bfd71466f7 (patch)
tree5f0030f16bc2a846382c567dfccfc463d1ef10bf
parent7112abe944259a615e26342de17d0302ddec3562 (diff)
downloadvaadin-framework-7e7b6239ca8867d13e8d8b279a0541bfd71466f7.tar.gz
vaadin-framework-7e7b6239ca8867d13e8d8b279a0541bfd71466f7.zip
reduce frequency of session locking and StreamingProgressEvents (#13155)
This change introduces throttling of streaming progress events. Before a event was fired once a buffer was filled. However as the buffer is only 4kb in size, fast uploads would trigger massive amounts of events. This change is backwards incompatible on a logical level. Before this change, a listener would get contentLength/4kb events, while after this change the amount is limited to one progress event per 500ms. Change-Id: I5da092ec4488971b8554b68b44c346057bfcc0e0
-rw-r--r--server/src/com/vaadin/server/communication/FileUploadHandler.java49
1 files changed, 36 insertions, 13 deletions
diff --git a/server/src/com/vaadin/server/communication/FileUploadHandler.java b/server/src/com/vaadin/server/communication/FileUploadHandler.java
index 3f6bfd9267..88f2e4b120 100644
--- a/server/src/com/vaadin/server/communication/FileUploadHandler.java
+++ b/server/src/com/vaadin/server/communication/FileUploadHandler.java
@@ -227,6 +227,9 @@ public class FileUploadHandler implements RequestHandler {
/* Same as in apache commons file upload library that was previously used. */
private static final int MAX_UPLOAD_BUFFER_SIZE = 4 * 1024;
+ /* Minimum interval which will be used for streaming progress events. */
+ public static final int DEFAULT_STREAMING_PROGRESS_EVENT_INTERVAL_MS = 500;
+
@Override
public boolean handleRequest(VaadinSession session, VaadinRequest request,
VaadinResponse response) throws IOException {
@@ -537,26 +540,35 @@ public class FileUploadHandler implements RequestHandler {
}
final byte buffer[] = new byte[MAX_UPLOAD_BUFFER_SIZE];
+ long lastStreamingEvent = 0;
int bytesReadToBuffer = 0;
- while ((bytesReadToBuffer = in.read(buffer)) > 0) {
- out.write(buffer, 0, bytesReadToBuffer);
- totalBytes += bytesReadToBuffer;
+ do {
+ bytesReadToBuffer = in.read(buffer);
+ if (bytesReadToBuffer > 0) {
+ out.write(buffer, 0, bytesReadToBuffer);
+ totalBytes += bytesReadToBuffer;
+ }
if (listenProgress) {
- // update progress if listener set and contentLength
- // received
- session.lock();
- try {
- StreamingProgressEventImpl progressEvent = new StreamingProgressEventImpl(
- filename, type, contentLength, totalBytes);
- streamVariable.onProgress(progressEvent);
- } finally {
- session.unlock();
+ long now = System.currentTimeMillis();
+ // to avoid excessive session locking and event storms,
+ // events are sent in intervals, or at the end of the file.
+ if (lastStreamingEvent + getProgressEventInterval() <= now
+ || bytesReadToBuffer <= 0) {
+ lastStreamingEvent = now;
+ session.lock();
+ try {
+ StreamingProgressEventImpl progressEvent = new StreamingProgressEventImpl(
+ filename, type, contentLength, totalBytes);
+ streamVariable.onProgress(progressEvent);
+ } finally {
+ session.unlock();
+ }
}
}
if (streamVariable.isInterrupted()) {
throw new UploadInterruptedException();
}
- }
+ } while (bytesReadToBuffer > 0);
// upload successful
out.close();
@@ -599,6 +611,17 @@ public class FileUploadHandler implements RequestHandler {
return startedEvent.isDisposed();
}
+ /**
+ * To prevent event storming, streaming progress events are sent in this
+ * interval rather than every time the buffer is filled. This fixes #13155.
+ * To adjust this value override the method, and register your own handler
+ * in VaadinService.createRequestHandlers(). The default is 500ms, and
+ * setting it to 0 effectively restores the old behavior.
+ */
+ protected int getProgressEventInterval() {
+ return DEFAULT_STREAMING_PROGRESS_EVENT_INTERVAL_MS;
+ }
+
static void tryToCloseStream(OutputStream out) {
try {
// try to close output stream (e.g. file handle)