Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Byte-range request performance problems with large files #3840

Closed
TheWizz opened this issue Jul 1, 2019 · 20 comments
Closed

Byte-range request performance problems with large files #3840

TheWizz opened this issue Jul 1, 2019 · 20 comments
Assignees

Comments

@TheWizz
Copy link

TheWizz commented Jul 1, 2019

I use org.eclipse.jetty.servlet.DefaultServlet to serve video files, which may be large (several GB). Many browsers use byte-range requests to play video. When serving a large file in this way, there are significant performance problems caused by the PathResource used to read the file. Its getInputStream method calls Files.newInputStream which calls newInputStream through the FileSystemProvider, which calls Channels.newInputStream, finally returning a sun.nio.ch.ChannelInputStream. This works fine when reading the stream from its beginning. However, to read byte ranges, ChannelInputStream uses InputStream#skip to "skip ahead" in the stream. This is done by repeatedly reading data into a 2048 byte large buffer in a loop. Needless to say, when skipping a few hundred MB into a 2 GB video file, this is very inefficient compared to doing a "seek" operation on the file.

I'm using Jetty 9.4.11. As far as I can tell, nothing has changed in more recent versions here. Is this a known issue with Jetty? If so, is there any work-around or tweak that can be applied to make byte-range requests use a "seek" operation instead of a sequential "read-2048-bytes-at-a-time-to-skip-ahead" loop? Presumably, the (deprecated) FileResource behaves better here (hard to tell since its skip method is implemented in native code, but presumably it does a seek operation on the underlying file).

-JM

@gregw
Copy link
Contributor

gregw commented Jul 1, 2019

@TheWizz Ideally to serve this kinds of requests, I think we would want the resource to be in a memory mapped file, so that it can have true random access. So you may need to adjust your resource cache parameters to allow this.... although if you have a lot of GB files, perhaps you will run out of address space for even memory mapped files. Tell us a bit more about the actual sizes and number of such resources, together with how many concurrent requests and if they are for the same resource. We'll have a look at what can be done, as it has been a while since we checked out range requests... certainly not since the switch to PathResources.

@TheWizz
Copy link
Author

TheWizz commented Jul 1, 2019

Thanks fort your reply!

Well, since we're building sort of a general purpose server, with special focus on media files, we don't really know how many or how large files our customers will serve. Hence, we need a performant and scalable general solution. Using a plain SEEK operation may not be as performant as a memory mapped file, but should be far better than the current "read-2048-bytes-at-a-time-to-skip-ahead" method, I would think.

My plan at this point is to see if I can make it use the FileResource instead, even though it's deprecated. Hopefully, such a solution may solve my immediate problem, giving some time to come up with a more contemporary solution.

What would be the easiest way to "plug in" the FileResource instead of the PathResources (assuming that might be made to work for serving plain files)?

-JM

@gregw
Copy link
Contributor

gregw commented Jul 2, 2019

JM/@TheWizz ,
I have confirmed your diagnosis that an InputStream opened with Files.newInputStream(path, StandardOpenOption.READ) have a painfully slow skip implementation, while those that are opened with new FileInputStream(path.toFile()) have a fast native implementation. I think fundamentally this is an issue for the JRE to fix and I will raise an issue there. But until that is fixed, it is simple for us to change the implementation of PathResource.getInputStream() to:

    @Override
    public InputStream getInputStream() throws IOException
    {
        /* Mimic behavior from old FileResource class and its
         * usage of java.io.FileInputStream(File) which will trigger
         * an IOException on construction if the path is a directory
         */
        if (Files.isDirectory(path))
            throw new IOException(path + " is a directory");

        try
        {
            File file = getFile();
            if (file != null)
                return new FileInputStream(file);
        }
        catch (Exception e)
        {
            LOG.ignore(e);
        }

        return Files.newInputStream(path, StandardOpenOption.READ);
    }

or perhaps simpler as the alternative probably is not needed.

We will put something like this in the next release.

gregw added a commit that referenced this issue Jul 2, 2019
Reverted to use FileInputStream

Signed-off-by: Greg Wilkins <[email protected]>
@TheWizz
Copy link
Author

TheWizz commented Jul 2, 2019

Thanks! I can confirm that your fix solves our problem.

@gregw
Copy link
Contributor

gregw commented Jul 2, 2019

Note also that we have opened https://bugs.openjdk.java.net/browse/JDK-8227080

gregw added a commit that referenced this issue Jul 3, 2019
Reverted to use FileInputStream

Signed-off-by: Greg Wilkins <[email protected]>
@gregw gregw closed this as completed Jul 3, 2019
@joakime joakime reopened this Jul 25, 2019
@joakime
Copy link
Contributor

joakime commented Jul 25, 2019

Reopening ... Why are byte-range requests using InputStream here?

We have Resource.getReadableByteChannel().

Oddly the PathResource.getReableByteChannel() is using a wonky implementation.

https://github.com/eclipse/jetty.project/blob/1aaadea13db0075a04a65d724bcfd8277d8a0949/jetty-util/src/main/java/org/eclipse/jetty/util/resource/PathResource.java#L393-L397

If this were changed to ...

    public ReadableByteChannel getReadableByteChannel() throws IOException
    {
        return Files.newByteChannel(path, StandardOpenOption.READ, StandardOpenOption.SPARSE);
    }

Then you get a SeekableByteChannel returned.

@joakime
Copy link
Contributor

joakime commented Jul 25, 2019

Here's some average timing for the various techniques across 2 different JVMs on 3 different OS's.
Each run was against the same 4GB file, seeking to 123MB, then reading 4MB.

  Linux / Ubuntu 18.04.2 Linux / Ubuntu 18.04.2 Windows 10 Pro Windows 10 Pro OSX 10.14.5 OSX 10.14.5
Technique Java 11.0.3+7 Java 1.8.0_202-b08 Java 11.0.4+10-LTS Java 1.8.0_202-b08 Java 11.0.4+11 Java 1.8.0_202-b08
FileChannel.open(Path) 2.09 ms 1.29 ms 13.60 ms 2.34 ms 2.67 ms 21.66 ms
new FileInputStream(File) 1.19 ms 0.85 ms 1.68 ms 1.32 ms 1.56 ms 1.17 ms
Files.newByteChannel(Path) 1.55 ms 0.91 ms 5.46 ms 2.31 ms 2.16 ms 2.05 ms
Files.newInputStream(Path) 55.97 ms 54.73 ms 315.98 ms 566.18 ms 129.49 ms 126.84 ms

The Files.newByteChannel(Path) technique is the most consistently quickest approach for working with Path objects.
The new FileInputStream(File) is the fastest technique overall.

@gregw
Copy link
Contributor

gregw commented Jul 25, 2019

@joakime, so the plan is to revert to using Files.newInputStream(path,...) but with the SPARSE option. Is that sufficient, or should we also to add the SPARSE option to getReadableByteChannel() and then alter the range code to use byte channels rather than streams?

Should the SPARSE option itself be optional? Ie only used if we are supporting ranges? Do we need new methods for that? What is the downside of specifying SPARSE for a non range request?

I'm assuming you will work on this, so I'm assigning it to you. Assign it back to me if you want me to work on it. This would be good to fix at least in part in 9.4.20.

@joakime
Copy link
Contributor

joakime commented Jul 25, 2019

To keep the discussion in one place ...

Added testcase from discussion at Issue #3906 ...

https://github.com/eclipse/jetty.project/blob/24b2ca4c328fcc22a1c1534d39ea2970920b1ac4/jetty-util/src/test/java/org/eclipse/jetty/util/resource/PathResourceTest.java#L42-L70

Results in the following exception ...

java.lang.UnsupportedOperationException
	at com.sun.nio.zipfs.ZipPath.toFile(ZipPath.java:597)
	at org.eclipse.jetty.util.resource.PathResource.getFile(PathResource.java:368)
	at org.eclipse.jetty.util.resource.PathResource.getInputStream(PathResource.java:384)
	at org.eclipse.jetty.util.resource.PathResourceTest.testNonDefaultFileSystem_GetInputStream(PathResourceTest.java:65)

@joakime
Copy link
Contributor

joakime commented Jul 25, 2019

SPARSE has very little meaning on static files on Linux / OSX.
Those filesystems don't really care about that hint on READ (now if this was SPARSE + WRITE, then we'd have something that Linux could sink its teeth into).

However, SPARSE is used on NTFS and that FileSystem definitely takes advantage of it, optimizing for reads more efficiently.

Either way, I'll retest without SPARSE too.

@joakime
Copy link
Contributor

joakime commented Jul 25, 2019

I think the reason InputStream is selected is due to the bugs that PR #3889 fixes for large static resources.

Prior to the fixes in PR #3889, if the static file was over Integer.MAX_VALUE in size, then InputStream was always selected when serving the whole file.
I bet there's something similar going on with byte-range requests.

@gregw
Copy link
Contributor

gregw commented Jul 25, 2019

OK, so I'm confused now. If we revert to Files.newInputStream and SPARCE makes no difference, then wont we again have the slow skip implementation?
What is the plan to keep path encapsulation but not be slow?

@gregw
Copy link
Contributor

gregw commented Jul 25, 2019

Should we be calling getFile() and if that is non-null using new FileInputStream and only use Files.newInputStream if it is null?
Then as a separate exercise, look to use channels in the range code?

@joakime
Copy link
Contributor

joakime commented Jul 25, 2019

IMO, We should never be calling Path.toFile() in mainline code, that's just increasing our problems, not helping them.
Using Path.toFile() in test cases is fine, if you know what you are doing. Staying with Path only is even better.

We should, however, make sure that our implementation of byte-range favors the use of the SeekableByteChannel version over the InputStream version. (that's what I'm working on)
For PathResource, of a real OS file system paths, this will solve for the speed / efficiency case, as SeekableByteChannel is the fast option on all OSs / JVMs.

@gregw
Copy link
Contributor

gregw commented Jul 25, 2019

So if we can use SeekableByteChannel for big files, then that will be fast and encapsulated.
But can that be used for huge files, or will we need to revert to InputStreams? In which case we will have a very slow skip method just when we need it the most.

So sure, it would be best to avoid calling Path.toFile(), but if some code is calling PathResource.getInputStream(), then I think calling it to avoid returning a very poor performing stream is a reasonable work around... at least until java-13 is generally available with the proper fix. I don't want to fix this just for ranges, we should have a good getInputStream method for all usages.

Isn't the best thing to do in the short term to re-implement getInputStream along the lines I'm suggesting so we will get encapsulation and fast ranges.... this can be quickly released in 9.4.20. We can then rework the range code to be channel based rather than input stream based at a more suitable pace for that larger change.

P.S. I'm still confused as to what SPARCE does. If it makes no difference why did you raise it as a suggestion?

@joakime
Copy link
Contributor

joakime commented Jul 25, 2019

Java 14 has the InputStream.skip() slowness fixed per https://bugs.openjdk.java.net/browse/JDK-8227080

ResourceService.sendData() and Resource.writeTo() are the only places in Jetty that use InputStream.skip(int) (and all variants of InputStream too).
ASCIIReader is the only place in Jasper JSP that uses InputStream.skip(), and that's just to conform to the InputStream.skip() interface, nothing in Jasper JSP uses InputStream.skip() itself.

Our range code is rather messy, opening up a new InputStream against the same Resource for each supplied range on the same request. (only needed if the next range is before the current one).

And the range code attempts to work around cached resources? why? that's not the job of the range code, but the the HttpContent, or the Resource. If that work around wasn't there, then the Range code just delegates to Resource.writeTo(OutputStream, long, long) and never needs to know if InputStream or ReadableByteChannel was used.
The range code assumes that InputStream is the be-all-end-all only way to process resources, all resources, even small resources that fit in a Buffer.

The original goal that I've started working on is, is if Resource.getReadableByteChannel() returns an object, then use it as a SeekableByteChannel (which ReadableByteChannel implements).
If not, then fall back to Resource.getInputStream().
But if I can remove the cached resource hack in the ResourceService.sendData() then things get much less verbose/complicated.

@gregw
Copy link
Contributor

gregw commented Jul 25, 2019

I'm not so sure the cached resource "hack" comments are accurate. They are conditional on InputStream in = content.getResource().getInputStream(); and I think all our contents will have a resource and all of them will have input streams.

Plus it is not so much a hack, but an optimisation. We don't want repetitive calls to content.getResource().writeTo(multi, start, size);, as each call will open a new stream/channel internally and skip/seek to the location. Very inefficient! Perhaps we could add a Resource.writeTo(OutputStream, Range... ranges) method that can efficiently write multiple section?

Either way, this code is going to need very careful consideration, review and testing. I can't see it being changed in time for a 9.4.20 release. Thus I think we should still do a quick fix of check for a null toFile() in getInputStream(). That is a simple fix that can be done today and will be fast and encapsulated (although it may be slow for some File system types that don't have files nor a good skip implementation).

@joakime
Copy link
Contributor

joakime commented Jul 25, 2019

Plus it is not so much a hack, but an optimisation. We don't want repetitive calls to content.getResource().writeTo(multi, start, size);, as each call will open a new stream/channel internally and skip/seek to the location. Very inefficient!

Yet, that's what the current implementation seems to do already, opening a new InputStream for each range requested.

See line 817

https://github.com/eclipse/jetty.project/blob/1aaadea13db0075a04a65d724bcfd8277d8a0949/jetty-server/src/main/java/org/eclipse/jetty/server/ResourceService.java#L805-L836

Perhaps we could add a Resource.writeTo(OutputStream, Range... ranges) method that can efficiently write multiple section?

I considered this, but the mime multipart output of names / boundaries / etc on the HttpServletResponse would mean that Resource needs to know HTTP specifics (or at least mime specifics), right? (Out of curiosity, is this multipart behavior also present on HTTP/2 requests for byte ranges?)

Would almost need a Stream<RangeWriter> Resource.newRangeWriters(Range ... ranges) which allows you to just iterate through the ranges from within the same singly opened InputStream or ReadableByteChannel while interleaving the multipart names / boundaries as you see fit in the ResourceService. Now that is a big change!

joakime added a commit that referenced this issue Jul 26, 2019
+ Reverting toFile().getInputStream() on PathResource
+ Adding RangeWriter concept for managing open resource
  across multiple range writes
+ RangeWriter implementation delegates to HttpContent behaviors
  Lookup is :
  - Direct Buffer
  - Indirect Buffer
  - ReadableByteChannel (as SeekableByteChannel)
  - InputStream
+ Adding unit tests for all RangeWriter implementation to ensure
  that they behave the same way everywhere.
+ Making ResourceService use new RangeWriter implementation
+ Existing DefaultServletRangeTest still works as-is

Signed-off-by: Joakim Erdfelt <[email protected]>
joakime added a commit that referenced this issue Jul 30, 2019
+ break out if progress isn't made, loop if not enough
  progress is made

Signed-off-by: Joakim Erdfelt <[email protected]>
joakime added a commit that referenced this issue Jul 30, 2019
+ Construction of PathResource now tests if path belongs
  to the Default FileSystem or not.  This important info
  for later actions against the PathResource that would
  need to know the File object for the Path object.
  Non-Default FileSystem == null
  Default FileSystem == Path.toFile()

Signed-off-by: Joakim Erdfelt <[email protected]>
joakime added a commit that referenced this issue Jul 30, 2019
+ Reset progress on any positive skip value
+ Throw IOException(EOF) for any negative skip value

Signed-off-by: Joakim Erdfelt <[email protected]>
joakime added a commit that referenced this issue Jul 30, 2019
+ Using techniques from SeekableByteChannelRangeWriter
  with variant for -1 count parameter

Signed-off-by: Joakim Erdfelt <[email protected]>
joakime added a commit that referenced this issue Jul 30, 2019
+ Removing unnecessary variables (per PR review)

Signed-off-by: Joakim Erdfelt <[email protected]>
joakime added a commit that referenced this issue Jul 31, 2019
joakime added a commit that referenced this issue Jul 31, 2019
…yterange

Issue #3840 Static resource byte-range support performance
@joakime
Copy link
Contributor

joakime commented Jul 31, 2019

Results of tests of byte-range support on Jetty 9.2.28, Jetty 9.4.19, and Jetty 9.4.x HEAD

The ZipFs (non-default FileSystem error 500's have been mentioned in #3906 (comment) and will be addressed in Issue #3906 with another PR)

Single Range

Http Request Linux / Jetty 9.2.28 Linux / Jetty 9.4.19 Linux / Jetty 9.4.x HEAD
Range / First Half / JarUrl / Large 3,535.91 ms 3,614.54 ms 3,591.25 ms
Range / First Half / JarUrl / Medium 6.98 ms 6.42 ms 8.60 ms
Range / First Half / JarUrl / Small 3.91 ms 3.58 ms 3.93 ms
Range / First Half / Traditional / 1 GB 384.06 ms 349.30 ms 332.39 ms
Range / First Half / Traditional / 10 GB 3,337.92 ms FAILED - Got unexpected status code [200], expected [206] 3,272.40 ms
Range / First Half / Traditional / 2 MB 3.67 ms 4.05 ms 4.60 ms
Range / First Half / Traditional / 20 KB 4.63 ms 3.98 ms 4.08 ms
Range / First Half / Traditional / 4 GB 1,066.25 ms FAILED - Got unexpected status code [416], expected [206] 1,404.99 ms
Range / First Half / ZipFs / Large 3,542.21 ms 3,593.48 ms FAILED - Got unexpected status code [500], expected [206]
Range / First Half / ZipFs / Medium 6.50 ms 6.47 ms FAILED - Got unexpected status code [500], expected [206]
Range / First Half / ZipFs / Small 3.68 ms 3.60 ms FAILED - Got unexpected status code [500], expected [206]
Range / Last 10 bytes / JarUrl / Large 7,289.14 ms 7,294.79 ms 7,310.44 ms
Range / Last 10 bytes / JarUrl / Medium 16.49 ms 15.80 ms 17.05 ms
Range / Last 10 bytes / JarUrl / Small 4.14 ms 4.57 ms 4.71 ms
Range / Last 10 bytes / Traditional / 1 GB 320.11 ms 295.94 ms 2.59 ms
Range / Last 10 bytes / Traditional / 10 GB 3,005.15 ms FAILED - Got unexpected status code [200], expected [206] 2.94 ms
Range / Last 10 bytes / Traditional / 2 MB 3.90 ms 3.61 ms 2.80 ms
Range / Last 10 bytes / Traditional / 20 KB 3.25 ms 3.19 ms 2.90 ms
Range / Last 10 bytes / Traditional / 4 GB 1,153.48 ms FAILED - Got unexpected status code [416], expected [206] 2.39 ms
Range / Last 10 bytes / ZipFs / Large 7,444.81 ms 7,524.80 ms FAILED - Got unexpected status code [500], expected [206]
Range / Last 10 bytes / ZipFs / Medium 16.66 ms 18.09 ms FAILED - Got unexpected status code [500], expected [206]
Range / Last 10 bytes / ZipFs / Small 5.13 ms 4.69 ms FAILED - Got unexpected status code [500], expected [206]
Range / Last Half / JarUrl / Large 7,188.18 ms 7,266.46 ms 7,220.92 ms
Range / Last Half / JarUrl / Medium 13.41 ms 12.75 ms 13.74 ms
Range / Last Half / JarUrl / Small 5.89 ms 5.53 ms 5.73 ms
Range / Last Half / Traditional / 1 GB 457.15 ms 369.90 ms 320.06 ms
Range / Last Half / Traditional / 10 GB 4,585.25 ms FAILED - Got unexpected status code [200], expected [206] 3,243.65 ms
Range / Last Half / Traditional / 2 MB 3.75 ms 4.00 ms 11.68 ms
Range / Last Half / Traditional / 20 KB 2.93 ms 3.34 ms 3.41 ms
Range / Last Half / Traditional / 4 GB 1,801.54 ms FAILED - Got unexpected status code [416], expected [206] 1,225.51 ms
Range / Last Half / ZipFs / Large 7,341.48 ms 7,232.23 ms FAILED - Got unexpected status code [500], expected [206]
Range / Last Half / ZipFs / Medium 12.58 ms 13.85 ms FAILED - Got unexpected status code [500], expected [206]
Range / Last Half / ZipFs / Small 4.77 ms 5.38 ms FAILED - Got unexpected status code [500], expected [206]
Range / Middle Third / JarUrl / Large 4,892.60 ms 4,781.38 ms 4,736.34 ms
Range / Middle Third / JarUrl / Medium 9.33 ms 9.78 ms 10.92 ms
Range / Middle Third / JarUrl / Small 6.78 ms 3.70 ms 3.71 ms
Range / Middle Third / Traditional / 1 GB 347.28 ms 258.58 ms 270.95 ms
Range / Middle Third / Traditional / 10 GB 3,028.42 ms FAILED - Got unexpected status code [200], expected [206] 2,072.03 ms
Range / Middle Third / Traditional / 2 MB 3.24 ms 3.18 ms 3.28 ms
Range / Middle Third / Traditional / 20 KB 3.09 ms 4.03 ms 2.35 ms
Range / Middle Third / Traditional / 4 GB 1,291.13 ms FAILED - Got unexpected status code [416], expected [206] 931.34 ms
Range / Middle Third / ZipFs / Large 4,924.20 ms 4,896.06 ms FAILED - Got unexpected status code [500], expected [206]
Range / Middle Third / ZipFs / Medium 7.94 ms 9.39 ms FAILED - Got unexpected status code [500], expected [206]
Range / Middle Third / ZipFs / Small 3.25 ms 4.03 ms FAILED - Got unexpected status code [500], expected [206]

Multiple Ranges

Http Request Linux / Jetty 9.2.28 Linux / Jetty 9.4.19 Linux / Jetty 9.4.x HEAD
Multiple Ranges / Overlapping / JarUrl / Large 14,591.64 ms 6,533.91 ms 6,427.30 ms
Multiple Ranges / Overlapping / JarUrl / Medium 18.69 ms 14.30 ms 10.71 ms
Multiple Ranges / Overlapping / JarUrl / Small 5.26 ms 3.44 ms 4.38 ms
Multiple Ranges / Overlapping / Traditional / 1 GB 907.19 ms 522.58 ms 487.28 ms
Multiple Ranges / Overlapping / Traditional / 10 GB 9,540.61 ms FAILED - Got unexpected status code [200], expected [206] 4,863.93 ms
Multiple Ranges / Overlapping / Traditional / 2 MB 3.62 ms 3.35 ms 4.35 ms
Multiple Ranges / Overlapping / Traditional / 20 KB 2.60 ms 5.43 ms 3.03 ms
Multiple Ranges / Overlapping / Traditional / 4 GB FAILED - Got unexpected response size [291] (too small) FAILED - Got unexpected status code [416], expected [206] 1,940.53 ms
Multiple Ranges / Overlapping / ZipFs / Large 14,766.70 ms 6,682.90 ms FAILED - Got unexpected status code [500], expected [206]
Multiple Ranges / Overlapping / ZipFs / Medium 20.19 ms 11.58 ms FAILED - Got unexpected status code [500], expected [206]
Multiple Ranges / Overlapping / ZipFs / Small 6.85 ms 5.47 ms FAILED - Got unexpected status code [500], expected [206]
Multiple Ranges / Reverse / JarUrl / Large 16,539.13 ms 16,355.00 ms 16,281.33 ms
Multiple Ranges / Reverse / JarUrl / Medium 23.38 ms 25.67 ms 3.56 ms
Multiple Ranges / Reverse / JarUrl / Small 6.63 ms 6.44 ms 2.16 ms
Multiple Ranges / Reverse / Traditional / 1 GB 862.40 ms 715.97 ms 256.34 ms
Multiple Ranges / Reverse / Traditional / 10 GB FAILED - Got unexpected response size (too small) FAILED - Got unexpected status code [200], expected [206] FAILED - Got unexpected response size (too small)
Multiple Ranges / Reverse / Traditional / 2 MB 4.73 ms 4.97 ms 2.63 ms
Multiple Ranges / Reverse / Traditional / 20 KB 3.67 ms 12.32 ms 1.93 ms
Multiple Ranges / Reverse / Traditional / 4 GB 3,253.86 ms FAILED - Got unexpected status code [416], expected [206] 1,375.36 ms
Multiple Ranges / Reverse / ZipFs / Large 16,642.45 ms 16,651.70 ms FAILED - Got unexpected status code [500], expected [206]
Multiple Ranges / Reverse / ZipFs / Medium 20.71 ms 21.79 ms 3.94 ms
Multiple Ranges / Reverse / ZipFs / Small 6.26 ms 6.62 ms 2.83 ms
Multiple Ranges / Sequential / JarUrl / Large 6,664.01 ms 6,759.30 ms 6,588.51 ms
Multiple Ranges / Sequential / JarUrl / Medium 11.90 ms 9.72 ms 4.07 ms
Multiple Ranges / Sequential / JarUrl / Small 4.12 ms 4.12 ms 2.56 ms
Multiple Ranges / Sequential / Traditional / 1 GB 422.41 ms 392.22 ms 253.44 ms
Multiple Ranges / Sequential / Traditional / 10 GB FAILED - Got unexpected response size (too small) FAILED - Got unexpected status code [200], expected [206] FAILED - Got unexpected response size (too small)
Multiple Ranges / Sequential / Traditional / 2 MB 3.35 ms 3.32 ms 3.61 ms
Multiple Ranges / Sequential / Traditional / 20 KB 3.67 ms 4.24 ms 2.70 ms
Multiple Ranges / Sequential / Traditional / 4 GB 1,660.09 ms FAILED - Got unexpected status code [416], expected [206] 1,207.66 ms
Multiple Ranges / Sequential / ZipFs / Large 6,656.11 ms 6,704.65 ms FAILED - Got unexpected status code [500], expected [206]
Multiple Ranges / Sequential / ZipFs / Medium 11.57 ms 12.10 ms 4.73 ms
Multiple Ranges / Sequential / ZipFs / Small 5.84 ms 6.25 ms 6.36 ms

@joakime joakime added Bug For general bugs on Jetty side Enhancement and removed Bug For general bugs on Jetty side labels Jul 31, 2019
@joakime
Copy link
Contributor

joakime commented Aug 7, 2019

Fixed in jetty-9.4.x

@joakime joakime closed this as completed Aug 7, 2019
enricovianello added a commit to italiangrid/storm-webdav that referenced this issue Oct 29, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants