-
Notifications
You must be signed in to change notification settings - Fork 315
Optimize the nameMap of ZipFile #378
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
base: master
Are you sure you want to change the base?
Changes from 1 commit
7a3e348
4019b26
77585b4
c07b7df
eec6ab5
71c3641
d0e5365
b7cb0f0
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -30,6 +30,7 @@ | |
| import java.nio.file.Files; | ||
| import java.nio.file.Path; | ||
| import java.nio.file.StandardOpenOption; | ||
| import java.util.ArrayList; | ||
| import java.util.Arrays; | ||
| import java.util.Collections; | ||
| import java.util.Comparator; | ||
|
|
@@ -371,9 +372,14 @@ public static void closeQuietly(final ZipFile zipFile) { | |
| private final List<ZipArchiveEntry> entries = new LinkedList<>(); | ||
|
|
||
| /** | ||
| * Maps String to list of ZipArchiveEntrys, name -> actual entries. | ||
| * Maps a string to the first entry named it. | ||
| */ | ||
| private final Map<String, LinkedList<ZipArchiveEntry>> nameMap = new HashMap<>(HASH_SIZE); | ||
| private final Map<String, ZipArchiveEntry> nameMap = new HashMap<>(HASH_SIZE); | ||
|
|
||
| /** | ||
| * If multiple entries have the same name, maps the name to entries named it. | ||
|
Glavo marked this conversation as resolved.
Outdated
|
||
| */ | ||
| private Map<String, List<ZipArchiveEntry>> duplicateNameMap = null; | ||
|
Glavo marked this conversation as resolved.
Outdated
|
||
|
|
||
| /** | ||
| * The encoding to use for file names and the file comment. | ||
|
|
@@ -792,11 +798,24 @@ private BoundedArchiveInputStream createBoundedInputStream(final long start, fin | |
|
|
||
| private void fillNameMap() { | ||
| entries.forEach(ze -> { | ||
| // entries is filled in populateFromCentralDirectory and | ||
| // entries are filled in populateFromCentralDirectory and | ||
| // never modified | ||
| final String name = ze.getName(); | ||
| final LinkedList<ZipArchiveEntry> entriesOfThatName = nameMap.computeIfAbsent(name, k -> new LinkedList<>()); | ||
| entriesOfThatName.addLast(ze); | ||
| ZipArchiveEntry firstEntry = nameMap.putIfAbsent(name, ze); | ||
|
Glavo marked this conversation as resolved.
Outdated
|
||
|
|
||
| if (firstEntry != null) { | ||
| if (duplicateNameMap == null) { | ||
| duplicateNameMap = new HashMap<>(); | ||
| } | ||
|
|
||
| List<ZipArchiveEntry> entriesOfThatName = duplicateNameMap.computeIfAbsent(name, k -> { | ||
| ArrayList<ZipArchiveEntry> list = new ArrayList<>(2); | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why 2?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
This list is created when there are two entries with the same name. If no more entries with the same name are encountered later, using 2 as the initial capacity can reduce unnecessary memory footpoint.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The reason for using In general, we can calculate the memory footprint of a lists with
If the list has only two elements, As the list grows, the memory footprint of The combined memory footprint of all objects allocated during For smaller lists, iterating over a |
||
| list.add(firstEntry); | ||
| return list; | ||
| }); | ||
|
|
||
| entriesOfThatName.add(ze); | ||
| } | ||
| }); | ||
| } | ||
|
|
||
|
|
@@ -868,9 +887,12 @@ public Enumeration<ZipArchiveEntry> getEntries() { | |
| * @since 1.6 | ||
| */ | ||
| public Iterable<ZipArchiveEntry> getEntries(final String name) { | ||
| final List<ZipArchiveEntry> entriesOfThatName = nameMap.get(name); | ||
| return entriesOfThatName != null ? entriesOfThatName | ||
| : Collections.emptyList(); | ||
| List<ZipArchiveEntry> entriesOfThatName = duplicateNameMap == null ? null : duplicateNameMap.get(name); | ||
|
Glavo marked this conversation as resolved.
Outdated
|
||
| if (entriesOfThatName == null) { | ||
| ZipArchiveEntry entry = nameMap.get(name); | ||
| entriesOfThatName = entry == null ? Collections.emptyList() : Collections.singletonList(entry); | ||
| } | ||
| return entriesOfThatName; | ||
| } | ||
|
|
||
| /** | ||
|
|
@@ -899,13 +921,17 @@ public Enumeration<ZipArchiveEntry> getEntriesInPhysicalOrder() { | |
| * @since 1.6 | ||
| */ | ||
| public Iterable<ZipArchiveEntry> getEntriesInPhysicalOrder(final String name) { | ||
| ZipArchiveEntry[] entriesOfThatName = ZipArchiveEntry.EMPTY_ARRAY; | ||
| final LinkedList<ZipArchiveEntry> linkedList = nameMap.get(name); | ||
| if (linkedList != null) { | ||
| entriesOfThatName = linkedList.toArray(entriesOfThatName); | ||
| Arrays.sort(entriesOfThatName, offsetComparator); | ||
| if (duplicateNameMap != null) { | ||
| List<ZipArchiveEntry> list = duplicateNameMap.get(name); | ||
| if (list != null) { | ||
| ZipArchiveEntry[] entriesOfThatName = list.toArray(ZipArchiveEntry.EMPTY_ARRAY); | ||
|
Glavo marked this conversation as resolved.
Outdated
|
||
| Arrays.sort(entriesOfThatName, offsetComparator); | ||
| return Arrays.asList(entriesOfThatName); | ||
| } | ||
| } | ||
| return Arrays.asList(entriesOfThatName); | ||
|
|
||
| final ZipArchiveEntry entry = nameMap.get(name); | ||
| return entry == null ? Collections.emptyList() : Collections.singletonList(entry); | ||
| } | ||
|
|
||
| /** | ||
|
|
@@ -921,8 +947,7 @@ public Iterable<ZipArchiveEntry> getEntriesInPhysicalOrder(final String name) { | |
| * {@code null} if not present. | ||
| */ | ||
| public ZipArchiveEntry getEntry(final String name) { | ||
| final LinkedList<ZipArchiveEntry> entriesOfThatName = nameMap.get(name); | ||
| return entriesOfThatName != null ? entriesOfThatName.getFirst() : null; | ||
| return nameMap.get(name); | ||
| } | ||
|
|
||
| /** | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nitpicking: "Maps a string to the first entry by that name" sounds clearer to me.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not good at English so thank you very much for pointing out the poor grammar.