diff options
author | Fabian Lange <lange.fabian@gmail.com> | 2014-03-12 12:47:00 +0100 |
---|---|---|
committer | Vaadin Code Review <review@vaadin.com> | 2014-03-13 12:33:07 +0000 |
commit | 7e7b6239ca8867d13e8d8b279a0541bfd71466f7 (patch) | |
tree | 5f0030f16bc2a846382c567dfccfc463d1ef10bf | |
parent | 7112abe944259a615e26342de17d0302ddec3562 (diff) | |
download | vaadin-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.java | 49 |
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) |