6929479: Add a system property sun.zip.disableMemoryMapping to disable mmap use in ZipFile
System property sun.zip.disableMemoryMapping to disable mmap use Reviewed-by: alanb
This commit is contained in:
parent
63a75eead0
commit
57a26502f0
@ -36,6 +36,8 @@ import java.util.Enumeration;
|
||||
import java.util.Set;
|
||||
import java.util.HashSet;
|
||||
import java.util.NoSuchElementException;
|
||||
import java.security.AccessController;
|
||||
import sun.security.action.GetPropertyAction;
|
||||
import static java.util.zip.ZipConstants64.*;
|
||||
|
||||
/**
|
||||
@ -78,6 +80,17 @@ class ZipFile implements ZipConstants, Closeable {
|
||||
|
||||
private static native void initIDs();
|
||||
|
||||
private static final boolean usemmap;
|
||||
|
||||
static {
|
||||
// A system prpperty to disable mmap use to avoid vm crash when
|
||||
// in-use zip file is accidently overwritten by others.
|
||||
String prop = AccessController.doPrivileged(
|
||||
new GetPropertyAction("sun.zip.disableMemoryMapping"));
|
||||
usemmap = (prop == null ||
|
||||
!(prop.length() == 0 || prop.equalsIgnoreCase("true")));
|
||||
}
|
||||
|
||||
/**
|
||||
* Opens a zip file for reading.
|
||||
*
|
||||
@ -196,7 +209,7 @@ class ZipFile implements ZipConstants, Closeable {
|
||||
throw new NullPointerException("charset is null");
|
||||
this.zc = ZipCoder.get(charset);
|
||||
long t0 = System.nanoTime();
|
||||
jzfile = open(name, mode, file.lastModified());
|
||||
jzfile = open(name, mode, file.lastModified(), usemmap);
|
||||
sun.misc.PerfCounter.getZipFileOpenTime().addElapsedTimeFrom(t0);
|
||||
sun.misc.PerfCounter.getZipFileCount().increment();
|
||||
this.name = name;
|
||||
@ -673,8 +686,8 @@ class ZipFile implements ZipConstants, Closeable {
|
||||
}
|
||||
|
||||
|
||||
private static native long open(String name, int mode, long lastModified)
|
||||
throws IOException;
|
||||
private static native long open(String name, int mode, long lastModified,
|
||||
boolean usemmap) throws IOException;
|
||||
private static native int getTotal(long jzfile);
|
||||
private static native int read(long jzfile, long jzentry,
|
||||
long pos, byte[] b, int off, int len);
|
||||
|
@ -81,7 +81,8 @@ ThrowZipException(JNIEnv *env, const char *msg)
|
||||
|
||||
JNIEXPORT jlong JNICALL
|
||||
Java_java_util_zip_ZipFile_open(JNIEnv *env, jclass cls, jstring name,
|
||||
jint mode, jlong lastModified)
|
||||
jint mode, jlong lastModified,
|
||||
jboolean usemmap)
|
||||
{
|
||||
const char *path = JNU_GetStringPlatformChars(env, name, 0);
|
||||
char *msg = 0;
|
||||
@ -109,7 +110,7 @@ Java_java_util_zip_ZipFile_open(JNIEnv *env, jclass cls, jstring name,
|
||||
goto finally;
|
||||
}
|
||||
#endif
|
||||
zip = ZIP_Put_In_Cache(path, zfd, &msg, lastModified);
|
||||
zip = ZIP_Put_In_Cache0(path, zfd, &msg, lastModified, usemmap);
|
||||
}
|
||||
|
||||
if (zip != 0) {
|
||||
|
@ -251,11 +251,16 @@ freeZip(jzfile *zip)
|
||||
if (zip->lock != NULL) MDESTROY(zip->lock);
|
||||
free(zip->name);
|
||||
freeCEN(zip);
|
||||
|
||||
#ifdef USE_MMAP
|
||||
if (zip->maddr != NULL) munmap((char *)zip->maddr, zip->mlen);
|
||||
#else
|
||||
free(zip->cencache.data);
|
||||
if (zip->usemmap) {
|
||||
if (zip->maddr != NULL)
|
||||
munmap((char *)zip->maddr, zip->mlen);
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
free(zip->cencache.data);
|
||||
}
|
||||
if (zip->comment != NULL)
|
||||
free(zip->comment);
|
||||
if (zip->zfd != -1) ZFILE_Close(zip->zfd);
|
||||
@ -585,49 +590,53 @@ readCEN(jzfile *zip, jint knownTotal)
|
||||
ZIP_FORMAT_ERROR("invalid END header (bad central directory offset)");
|
||||
|
||||
#ifdef USE_MMAP
|
||||
/* On Solaris & Linux prior to JDK 6, we used to mmap the whole jar file to
|
||||
* read the jar file contents. However, this greatly increased the perceived
|
||||
* footprint numbers because the mmap'ed pages were adding into the totals shown
|
||||
* by 'ps' and 'top'. We switched to mmaping only the central directory of jar
|
||||
* file while calling 'read' to read the rest of jar file. Here are a list of
|
||||
* reasons apart from above of why we are doing so:
|
||||
* 1. Greatly reduces mmap overhead after startup complete;
|
||||
* 2. Avoids dual path code maintainance;
|
||||
* 3. Greatly reduces risk of address space (not virtual memory) exhaustion.
|
||||
*/
|
||||
if (pagesize == 0) {
|
||||
pagesize = (jlong)sysconf(_SC_PAGESIZE);
|
||||
if (pagesize == 0) goto Catch;
|
||||
}
|
||||
if (cenpos > pagesize) {
|
||||
offset = cenpos & ~(pagesize - 1);
|
||||
} else {
|
||||
offset = 0;
|
||||
}
|
||||
/* When we are not calling recursively, knownTotal is -1. */
|
||||
if (knownTotal == -1) {
|
||||
void* mappedAddr;
|
||||
/* Mmap the CEN and END part only. We have to figure
|
||||
out the page size in order to make offset to be multiples of
|
||||
page size.
|
||||
*/
|
||||
zip->mlen = cenpos - offset + cenlen + endhdrlen;
|
||||
zip->offset = offset;
|
||||
mappedAddr = mmap64(0, zip->mlen, PROT_READ, MAP_SHARED, zip->zfd, (off64_t) offset);
|
||||
zip->maddr = (mappedAddr == (void*) MAP_FAILED) ? NULL :
|
||||
(unsigned char*)mappedAddr;
|
||||
|
||||
if (zip->maddr == NULL) {
|
||||
jio_fprintf(stderr, "mmap failed for CEN and END part of zip file\n");
|
||||
goto Catch;
|
||||
if (zip->usemmap) {
|
||||
/* On Solaris & Linux prior to JDK 6, we used to mmap the whole jar file to
|
||||
* read the jar file contents. However, this greatly increased the perceived
|
||||
* footprint numbers because the mmap'ed pages were adding into the totals shown
|
||||
* by 'ps' and 'top'. We switched to mmaping only the central directory of jar
|
||||
* file while calling 'read' to read the rest of jar file. Here are a list of
|
||||
* reasons apart from above of why we are doing so:
|
||||
* 1. Greatly reduces mmap overhead after startup complete;
|
||||
* 2. Avoids dual path code maintainance;
|
||||
* 3. Greatly reduces risk of address space (not virtual memory) exhaustion.
|
||||
*/
|
||||
if (pagesize == 0) {
|
||||
pagesize = (jlong)sysconf(_SC_PAGESIZE);
|
||||
if (pagesize == 0) goto Catch;
|
||||
}
|
||||
}
|
||||
cenbuf = zip->maddr + cenpos - offset;
|
||||
#else
|
||||
if ((cenbuf = malloc((size_t) cenlen)) == NULL ||
|
||||
(readFullyAt(zip->zfd, cenbuf, cenlen, cenpos) == -1))
|
||||
goto Catch;
|
||||
if (cenpos > pagesize) {
|
||||
offset = cenpos & ~(pagesize - 1);
|
||||
} else {
|
||||
offset = 0;
|
||||
}
|
||||
/* When we are not calling recursively, knownTotal is -1. */
|
||||
if (knownTotal == -1) {
|
||||
void* mappedAddr;
|
||||
/* Mmap the CEN and END part only. We have to figure
|
||||
out the page size in order to make offset to be multiples of
|
||||
page size.
|
||||
*/
|
||||
zip->mlen = cenpos - offset + cenlen + endhdrlen;
|
||||
zip->offset = offset;
|
||||
mappedAddr = mmap64(0, zip->mlen, PROT_READ, MAP_SHARED, zip->zfd, (off64_t) offset);
|
||||
zip->maddr = (mappedAddr == (void*) MAP_FAILED) ? NULL :
|
||||
(unsigned char*)mappedAddr;
|
||||
|
||||
if (zip->maddr == NULL) {
|
||||
jio_fprintf(stderr, "mmap failed for CEN and END part of zip file\n");
|
||||
goto Catch;
|
||||
}
|
||||
}
|
||||
cenbuf = zip->maddr + cenpos - offset;
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
if ((cenbuf = malloc((size_t) cenlen)) == NULL ||
|
||||
(readFullyAt(zip->zfd, cenbuf, cenlen, cenpos) == -1))
|
||||
goto Catch;
|
||||
}
|
||||
|
||||
cenend = cenbuf + cenlen;
|
||||
|
||||
/* Initialize zip file data structures based on the total number
|
||||
@ -700,9 +709,11 @@ readCEN(jzfile *zip, jint knownTotal)
|
||||
cenpos = -1;
|
||||
|
||||
Finally:
|
||||
#ifndef USE_MMAP
|
||||
free(cenbuf);
|
||||
#ifdef USE_MMAP
|
||||
if (!zip->usemmap)
|
||||
#endif
|
||||
free(cenbuf);
|
||||
|
||||
return cenpos;
|
||||
}
|
||||
|
||||
@ -782,8 +793,16 @@ ZIP_Get_From_Cache(const char *name, char **pmsg, jlong lastModified)
|
||||
* If a zip error occurs, then *pmsg will be set to the error message text if
|
||||
* pmsg != 0. Otherwise, *pmsg will be set to NULL.
|
||||
*/
|
||||
|
||||
jzfile *
|
||||
ZIP_Put_In_Cache(const char *name, ZFILE zfd, char **pmsg, jlong lastModified)
|
||||
{
|
||||
return ZIP_Put_In_Cache0(name, zfd, pmsg, lastModified, JNI_TRUE);
|
||||
}
|
||||
|
||||
jzfile *
|
||||
ZIP_Put_In_Cache0(const char *name, ZFILE zfd, char **pmsg, jlong lastModified,
|
||||
jboolean usemmap)
|
||||
{
|
||||
static char errbuf[256];
|
||||
jlong len;
|
||||
@ -793,6 +812,9 @@ ZIP_Put_In_Cache(const char *name, ZFILE zfd, char **pmsg, jlong lastModified)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#ifdef USE_MMAP
|
||||
zip->usemmap = usemmap;
|
||||
#endif
|
||||
zip->refs = 1;
|
||||
zip->lastModified = lastModified;
|
||||
|
||||
@ -877,8 +899,6 @@ ZIP_Close(jzfile *zip)
|
||||
return;
|
||||
}
|
||||
|
||||
#ifndef USE_MMAP
|
||||
|
||||
/* Empirically, most CEN headers are smaller than this. */
|
||||
#define AMPLE_CEN_HEADER_SIZE 160
|
||||
|
||||
@ -928,7 +948,6 @@ sequentialAccessReadCENHeader(jzfile *zip, jlong cenpos)
|
||||
cache->pos = cenpos;
|
||||
return cen;
|
||||
}
|
||||
#endif /* not USE_MMAP */
|
||||
|
||||
typedef enum { ACCESS_RANDOM, ACCESS_SEQUENTIAL } AccessHint;
|
||||
|
||||
@ -953,14 +972,17 @@ newEntry(jzfile *zip, jzcell *zc, AccessHint accessHint)
|
||||
ze->comment = NULL;
|
||||
|
||||
#ifdef USE_MMAP
|
||||
cen = (char*) zip->maddr + zc->cenpos - zip->offset;
|
||||
#else
|
||||
if (accessHint == ACCESS_RANDOM)
|
||||
cen = readCENHeader(zip, zc->cenpos, AMPLE_CEN_HEADER_SIZE);
|
||||
else
|
||||
cen = sequentialAccessReadCENHeader(zip, zc->cenpos);
|
||||
if (cen == NULL) goto Catch;
|
||||
if (zip->usemmap) {
|
||||
cen = (char*) zip->maddr + zc->cenpos - zip->offset;
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
if (accessHint == ACCESS_RANDOM)
|
||||
cen = readCENHeader(zip, zc->cenpos, AMPLE_CEN_HEADER_SIZE);
|
||||
else
|
||||
cen = sequentialAccessReadCENHeader(zip, zc->cenpos);
|
||||
if (cen == NULL) goto Catch;
|
||||
}
|
||||
|
||||
nlen = CENNAM(cen);
|
||||
elen = CENEXT(cen);
|
||||
@ -976,7 +998,6 @@ newEntry(jzfile *zip, jzcell *zc, AccessHint accessHint)
|
||||
if ((ze->name = malloc(nlen + 1)) == NULL) goto Catch;
|
||||
memcpy(ze->name, cen + CENHDR, nlen);
|
||||
ze->name[nlen] = '\0';
|
||||
|
||||
if (elen > 0) {
|
||||
char *extra = cen + CENHDR + nlen;
|
||||
|
||||
@ -1037,9 +1058,10 @@ newEntry(jzfile *zip, jzcell *zc, AccessHint accessHint)
|
||||
ze = NULL;
|
||||
|
||||
Finally:
|
||||
#ifndef USE_MMAP
|
||||
if (cen != NULL && accessHint == ACCESS_RANDOM) free(cen);
|
||||
#ifdef USE_MMAP
|
||||
if (!zip->usemmap)
|
||||
#endif
|
||||
if (cen != NULL && accessHint == ACCESS_RANDOM) free(cen);
|
||||
return ze;
|
||||
}
|
||||
|
||||
|
@ -45,9 +45,6 @@
|
||||
* Header sizes including signatures
|
||||
*/
|
||||
|
||||
#ifdef USE_MMAP
|
||||
#define SIGSIZ 4
|
||||
#endif
|
||||
#define LOCHDR 30
|
||||
#define EXTHDR 16
|
||||
#define CENHDR 46
|
||||
@ -211,9 +208,9 @@ typedef struct jzfile { /* Zip file */
|
||||
jlong mlen; /* length (in bytes) mmaped */
|
||||
jlong offset; /* offset of the mmapped region from the
|
||||
start of the file. */
|
||||
#else
|
||||
cencache cencache; /* CEN header cache */
|
||||
jboolean usemmap; /* if mmap is used. */
|
||||
#endif
|
||||
cencache cencache; /* CEN header cache */
|
||||
ZFILE zfd; /* open file descriptor */
|
||||
void *lock; /* read lock */
|
||||
char *comment; /* zip file comment */
|
||||
@ -259,6 +256,9 @@ ZIP_Get_From_Cache(const char *name, char **pmsg, jlong lastModified);
|
||||
jzfile *
|
||||
ZIP_Put_In_Cache(const char *name, ZFILE zfd, char **pmsg, jlong lastModified);
|
||||
|
||||
jzfile *
|
||||
ZIP_Put_In_Cache0(const char *name, ZFILE zfd, char **pmsg, jlong lastModified, jboolean usemmap);
|
||||
|
||||
void JNICALL
|
||||
ZIP_Close(jzfile *zip);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user