JarFile.getVersionedEntry scalability with new release cadence
Eirik Bjørsnøs
eirbjo at gmail.com
Sun Apr 12 08:50:20 UTC 2020
>
> I think you could tune away a significant part of that up front cost by
> using JUZFA.entryNameStream(this) instead of
> this.stream().map(ZipEntry::getName). This will avoid expanding each
> entry into a JarEntry internally. Perhaps this gets the up-front
> overhead down to more acceptable levels..?
>
I found JUZFA.getMetaInfEntryNames which made the up front scanning
cost evaporate.
Should be fast for other jars as well, at least when META-INF/ is sparsely
populated.
Here's an updated patch:
diff --git a/src/java.base/share/classes/java/util/jar/JarFile.java
b/src/java.base/share/classes/java/util/jar/JarFile.java
index 1ec0f5bdae..95472604c0 100644
--- a/src/java.base/share/classes/java/util/jar/JarFile.java
+++ b/src/java.base/share/classes/java/util/jar/JarFile.java
@@ -161,7 +161,7 @@ public class JarFile extends ZipFile {
private final Runtime.Version version; // current version
private final int versionFeature; // version.feature()
private boolean isMultiRelease; // is jar multi-release?
-
+ private int[] versions; // which versions does the jar
contain
// indicates if Class-Path attribute present
private boolean hasClassPathAttribute;
// true if manifest checked for special attributes
@@ -599,12 +599,13 @@ public class JarFile extends ZipFile {
}
private JarEntry getVersionedEntry(String name, JarEntry je) {
- if (BASE_VERSION_FEATURE < versionFeature) {
+ int[] versions = this.versions;
+ if (BASE_VERSION_FEATURE < versionFeature && versions != null &&
versions.length > 0) {
if (!name.startsWith(META_INF)) {
// search for versioned entry
- int v = versionFeature;
- while (v > BASE_VERSION_FEATURE) {
- JarFileEntry vje = getEntry0(META_INF_VERSIONS + v +
"/" + name);
+ int v = versions.length - 1;
+ while (v >= 0) {
+ JarFileEntry vje = getEntry0(META_INF_VERSIONS +
versions[v] + "/" + name);
if (vje != null) {
return vje.withBasename(name);
}
@@ -1016,9 +1017,18 @@ public class JarFile extends ZipFile {
byte[] lbuf = new byte[512];
Attributes attr = new Attributes();
attr.read(new Manifest.FastInputStream(
- new ByteArrayInputStream(b)), lbuf);
- isMultiRelease = Boolean.parseBoolean(
- attr.getValue(Attributes.Name.MULTI_RELEASE));
+ new ByteArrayInputStream(b)), lbuf);
+ if(Boolean.parseBoolean(
+
attr.getValue(Attributes.Name.MULTI_RELEASE))) {
+ isMultiRelease = true;
+ versions =
Stream.of(JUZFA.getMetaInfEntryNames(this))
+ .mapToInt(this::parseVersion)
+ .filter(v -> v != -1 && v >=
BASE_VERSION_FEATURE && v <= versionFeature)
+ .distinct()
+ .sorted()
+ .toArray();
+ }
+
}
}
}
@@ -1026,6 +1036,27 @@ public class JarFile extends ZipFile {
}
}
+ /**
+ * If {@code entryName} is a a versioned entry, parse and return the
version as an integer, otherwise return -1
+ */
+ private int parseVersion(String entryName) {
+ if(!entryName.startsWith(META_INF_VERSIONS)) {
+ return -1;
+ }
+
+ int separator = entryName.indexOf("/", META_INF_VERSIONS.length());
+
+ if(separator == -1) {
+ return -1;
+ }
+
+ try {
+ return Integer.parseInt(entryName, META_INF_VERSIONS.length(),
separator, 10);
+ } catch (NumberFormatException e) {
+ return -1;
+ }
+ }
+
synchronized void ensureInitialization() {
try {
maybeInstantiateVerifier();
Eirik.
More information about the core-libs-dev
mailing list