Преглед изворни кода

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
tags/7.1.13
Fabian Lange пре 10 година
родитељ
комит
7e7b6239ca
1 измењених фајлова са 36 додато и 13 уклоњено
  1. 36
    13
      server/src/com/vaadin/server/communication/FileUploadHandler.java

+ 36
- 13
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)

Loading…
Откажи
Сачувај