#8285 - improve Resource to mapped ByteBuffer logic

Signed-off-by: Ludovic Orban <lorban@bitronix.be>
This commit is contained in:
Ludovic Orban 2022-07-25 11:58:18 +02:00
parent ccd79c4b47
commit 38d22f3153
7 changed files with 62 additions and 20 deletions

View File

@ -209,15 +209,7 @@ public class CachingContentFactory implements HttpContent.ContentFactory
if (_useFileMappedBuffer)
{
// map the content into memory
// TODO this is assuming the resource can be mapped! Inefficient to throw to test this
try
{
byteBuffer = BufferUtil.toMappedBuffer(httpContent.getResource().getPath(), 0, _contentLengthValue);
}
catch (Throwable t)
{
LOG.trace("ignored", t);
}
byteBuffer = BufferUtil.toMappedBuffer(httpContent.getResource(), 0, _contentLengthValue);
}
if (byteBuffer == null)

View File

@ -339,8 +339,8 @@ public class CachedContentFactory implements HttpContent.ContentFactory
// a non shared resource. Also ignore max buffer size
try
{
if (_useFileMappedBuffer && resource.getPath() != null && resource.length() < Integer.MAX_VALUE)
return BufferUtil.toMappedBuffer(resource.getPath());
if (_useFileMappedBuffer && resource.getPath() != null && resource.length() <= Integer.MAX_VALUE)
return BufferUtil.toMappedBuffer(resource);
}
catch (IOException | IllegalArgumentException e)
{

View File

@ -17,7 +17,6 @@ import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.RandomAccessFile;
import java.nio.Buffer;
import java.nio.BufferOverflowException;
import java.nio.ByteBuffer;
@ -1055,11 +1054,6 @@ public class BufferUtil
return buf;
}
public static ByteBuffer toMappedBuffer(File file) throws IOException
{
return toMappedBuffer(file.toPath(), 0, file.length());
}
public static ByteBuffer toMappedBuffer(Path path) throws IOException
{
return toMappedBuffer(path, 0, Files.size(path));
@ -1073,6 +1067,20 @@ public class BufferUtil
}
}
public static ByteBuffer toMappedBuffer(Resource resource) throws IOException
{
if (!resource.isMemoryMappable())
return null;
return toMappedBuffer(resource.getPath());
}
public static ByteBuffer toMappedBuffer(Resource resource, long pos, long len) throws IOException
{
if (!resource.isMemoryMappable())
return null;
return toMappedBuffer(resource.getPath(), pos, len);
}
public static String toSummaryString(ByteBuffer buffer)
{
if (buffer == null)

View File

@ -284,6 +284,12 @@ public class PathResource extends Resource
return path.toAbsolutePath().toString();
}
@Override
public boolean isMemoryMappable()
{
return "file".equalsIgnoreCase(uri.getScheme());
}
@Override
public URI getURI()
{

View File

@ -506,6 +506,16 @@ public abstract class Resource implements ResourceFactory
return Files.newByteChannel(getPath(), StandardOpenOption.READ);
}
/**
* Checks if the resource supports being loaded as a memory-mapped ByteBuffer.
*
* @return true if the resource supports memory-mapped ByteBuffer, false otherwise.
*/
public boolean isMemoryMappable()
{
return false;
}
/**
* Deletes the given resource
* Equivalent to {@link Files#deleteIfExists(Path)} with the following parameter:

View File

@ -17,9 +17,12 @@ import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.nio.BufferOverflowException;
import java.nio.ByteBuffer;
import java.nio.file.Path;
import java.util.Arrays;
import java.util.concurrent.ThreadLocalRandom;
import org.eclipse.jetty.toolchain.test.MavenTestingUtils;
import org.eclipse.jetty.util.resource.Resource;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import org.slf4j.Logger;
@ -29,6 +32,7 @@ import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.not;
import static org.hamcrest.Matchers.nullValue;
import static org.hamcrest.Matchers.sameInstance;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
@ -360,4 +364,26 @@ public class BufferUtilTest
BufferUtil.writeTo(buffer.asReadOnlyBuffer(), out);
assertThat("Bytes in out equal bytes in buffer", Arrays.equals(bytes, out.toByteArray()), is(true));
}
@Test
public void testToMappedBufferResource() throws Exception
{
Path testZip = MavenTestingUtils.getTestResourcePathFile("TestData/test.zip");
Path testTxt = MavenTestingUtils.getTestResourcePathFile("TestData/alphabet.txt");
Resource fileResource = Resource.newResource("file:" + testTxt.toAbsolutePath());
ByteBuffer fileBuffer = BufferUtil.toMappedBuffer(fileResource);
assertThat(fileBuffer, not(nullValue()));
assertThat((long)fileBuffer.remaining(), is(fileResource.length()));
Resource jrtResource = Resource.newResource("jrt:/java.base/java/lang/Object.class");
assertThat(jrtResource.exists(), is(true));
assertThat(BufferUtil.toMappedBuffer(jrtResource), nullValue());
try (Resource.Mount mount = Resource.mountJar(testZip))
{
Resource jarResource = mount.root();
assertThat(BufferUtil.toMappedBuffer(jarResource), nullValue());
}
}
}

View File

@ -339,10 +339,10 @@ public class CachedContentFactory implements HttpContent.ContentFactory
// a non shared resource. Also ignore max buffer size
try
{
if (_useFileMappedBuffer && resource.getPath() != null && resource.length() < Integer.MAX_VALUE)
return BufferUtil.toMappedBuffer(resource.getPath());
if (_useFileMappedBuffer && resource.getPath() != null && resource.length() <= Integer.MAX_VALUE)
return BufferUtil.toMappedBuffer(resource);
}
catch (IOException | IllegalArgumentException | UnsupportedOperationException e)
catch (IOException | IllegalArgumentException e)
{
if (LOG.isDebugEnabled())
LOG.debug("Unable to get Mapped Buffer for {}", resource, e);