Skip to content

Commit 845587d

Browse files
Johan Parentkrosenvold
authored andcommitted
- Add convert() and getBytes() method to both ZipShort and ZipLong API
- Convert ZipFile and ZipOutputStream to use above mentioned methods to avoid object alloction hotspot (jprofiler) especially for large jars. - Replace ArrayList with LinkedList to reduce alloc-copy overhead when creating large INDEX.LST file - Introduce Calendar per thread (with ThreadLocal) to avoid creating a new Calendar when creating the Date for every ZipEntry - Misc: move array allocation out of loop when possible Signed-off-by: Kristian Rosenvold <[email protected]>, applied with minor modifications
1 parent 1610239 commit 845587d

File tree

5 files changed

+181
-95
lines changed

5 files changed

+181
-95
lines changed

src/main/java/org/codehaus/plexus/archiver/zip/AbstractZipArchiver.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -352,12 +352,12 @@ protected Map<String, Long> getZipEntryNames( File file )
352352
return entries;
353353
}
354354

355-
protected boolean isFileAdded( ArchiveEntry entry, Map entries )
355+
protected static boolean isFileAdded(ArchiveEntry entry, Map entries)
356356
{
357357
return !entries.containsKey( entry.getName() );
358358
}
359359

360-
protected boolean isFileUpdated( ArchiveEntry entry, Map entries )
360+
protected static boolean isFileUpdated(ArchiveEntry entry, Map entries)
361361
{
362362
Long l = (Long) entries.get( entry.getName() );
363363
return l != null && (l == -1 || !ResourceUtils.isUptodate(entry.getResource(), l));

src/main/java/org/codehaus/plexus/archiver/zip/ZipFile.java

Lines changed: 50 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
import java.util.Date;
2727
import java.util.Enumeration;
2828
import java.util.Hashtable;
29+
import java.util.Map;
2930
import java.util.zip.Inflater;
3031
import java.util.zip.InflaterInputStream;
3132
import java.util.zip.ZipException;
@@ -58,12 +59,10 @@
5859
* <li>close is allowed to throw IOException.</li>
5960
* </ul>
6061
*
61-
* @version $Revision$ $Date$
62+
* @version $Revision: 7140 $ $Date: 2008-01-06 12:50:12 +0100 (dim., 06 janv. 2008) $
6263
* from org.apache.ant.tools.zip.ZipFile v1.13
6364
*/
64-
@SuppressWarnings("JavaDoc")
65-
public class ZipFile
66-
implements ArchiveFile
65+
public class ZipFile implements ArchiveFile
6766
{
6867

6968
/**
@@ -80,7 +79,7 @@ public class ZipFile
8079
/**
8180
* Maps ZipEntrys to Longs, recording the offsets of the actual file data.
8281
*/
83-
private final Hashtable<ZipEntry, Long> dataOffsets = new Hashtable<ZipEntry, Long>();
82+
private Hashtable<ZipEntry, Long> dataOffsets = new Hashtable<ZipEntry, Long>();
8483

8584
/**
8685
* The encoding to use for filenames and the file comment.
@@ -233,7 +232,8 @@ public void close()
233232
}
234233
};
235234
default:
236-
throw new ZipException( "Found unsupported compression method " + ze.getMethod() );
235+
throw new ZipException( "Found unsupported compression method "
236+
+ ze.getMethod() );
237237
}
238238
}
239239

@@ -279,46 +279,45 @@ private void populateFromCentralDirectory()
279279
int off = 0;
280280
ZipEntry ze = new ZipEntry();
281281

282-
ZipShort versionMadeBy = new ZipShort( cfh, off );
282+
ze.setPlatform( ( ZipShort.convert( cfh, off ) >> 8 ) & 0x0F );
283283
off += 2;
284-
ze.setPlatform( ( versionMadeBy.getValue() >> 8 ) & 0x0F );
285284

286285
off += 4; // skip version info and general purpose byte
287286

288-
ze.setMethod( ( new ZipShort( cfh, off ) ).getValue() );
287+
ze.setMethod( ZipShort.convert( cfh, off ) );
289288
off += 2;
290289

291-
ze.setTime( fromDosTime( new ZipLong( cfh, off ) ).getTime() );
290+
ze.setTime( fromDosTime( ZipLong.convert( cfh, off ) ).getTime() );
292291
off += 4;
293292

294-
ze.setCrc( ( new ZipLong( cfh, off ) ).getValue() );
293+
ze.setCrc( ZipLong.convert( cfh, off ));
295294
off += 4;
296295

297-
ze.setCompressedSize( ( new ZipLong( cfh, off ) ).getValue() );
296+
ze.setCompressedSize( ZipLong.convert( cfh, off ));
298297
off += 4;
299298

300-
ze.setSize( ( new ZipLong( cfh, off ) ).getValue() );
299+
ze.setSize( ZipLong.convert( cfh, off ) );
301300
off += 4;
302301

303-
int fileNameLen = ( new ZipShort( cfh, off ) ).getValue();
302+
int fileNameLen = ZipShort.convert( cfh, off );
304303
off += 2;
305304

306-
int extraLen = ( new ZipShort( cfh, off ) ).getValue();
305+
int extraLen = ZipShort.convert( cfh, off );
307306
off += 2;
308307

309-
int commentLen = ( new ZipShort( cfh, off ) ).getValue();
308+
int commentLen = ZipShort.convert( cfh, off );
310309
off += 2;
311310

312311
off += 2; // disk number
313312

314-
ze.setInternalAttributes( ( new ZipShort( cfh, off ) ).getValue() );
313+
ze.setInternalAttributes( ZipShort.convert( cfh, off ));
315314
off += 2;
316315

317-
ze.setExternalAttributes( ( new ZipLong( cfh, off ) ).getValue() );
316+
ze.setExternalAttributes( ZipLong.convert( cfh, off ) );
318317
off += 4;
319318

320319
// LFH offset
321-
entries.put( ze, (new ZipLong(cfh, off)).getValue());
320+
entries.put( ze, new Long( ZipLong.convert( cfh, off )) );
322321

323322
byte[] fileName = new byte[fileNameLen];
324323
archive.readFully( fileName );
@@ -405,7 +404,7 @@ private void positionAtCentralDirectory()
405404
archive.seek( off + CFD_LOCATOR_OFFSET );
406405
byte[] cfdOffset = new byte[4];
407406
archive.readFully( cfdOffset );
408-
archive.seek( ( new ZipLong( cfdOffset ) ).getValue() );
407+
archive.seek( ZipLong.convert( cfdOffset ) );
409408
}
410409

411410
/**
@@ -433,27 +432,41 @@ private void positionAtCentralDirectory()
433432
private void resolveLocalFileHeaderData()
434433
throws IOException
435434
{
436-
Enumeration e = getEntries();
437-
while ( e.hasMoreElements() )
438-
{
439-
ZipEntry ze = (ZipEntry) e.nextElement();
440-
long offset = entries.get(ze);
435+
// Create a sufficiently large HashTable in order to avoid
436+
// the cost or repeated expansion of the backing array
437+
// in case of large jars
438+
dataOffsets = new Hashtable<ZipEntry, Long>(entries.size());
439+
440+
// Allocated array once outside the loop
441+
final byte[] b = new byte[2];
442+
443+
// Iterate using the entrySet
444+
for (Map.Entry<ZipEntry, Long> e : entries.entrySet()) {
445+
ZipEntry ze = e.getKey();
446+
long offset = e.getValue();
441447
archive.seek( offset + LFH_OFFSET_FOR_FILENAME_LENGTH );
442-
byte[] b = new byte[2];
443448
archive.readFully( b );
444-
int fileNameLen = ( new ZipShort( b ) ).getValue();
449+
int fileNameLen = ZipShort.convert(b);
445450
archive.readFully( b );
446-
int extraFieldLen = ( new ZipShort( b ) ).getValue();
451+
int extraFieldLen = ZipShort.convert( b );
447452
archive.skipBytes( fileNameLen );
448453
byte[] localExtraData = new byte[extraFieldLen];
449454
archive.readFully( localExtraData );
450455
ze.setExtra( localExtraData );
451-
dataOffsets.put( ze,
452-
offset + LFH_OFFSET_FOR_FILENAME_LENGTH
453-
+ 2 + 2 + fileNameLen + extraFieldLen);
456+
dataOffsets.put( ze, offset + LFH_OFFSET_FOR_FILENAME_LENGTH + 2 + 2 + fileNameLen + extraFieldLen );
454457
}
455458
}
456459

460+
/**
461+
* Creating a Calendar is relatively expensive. So create on per thread and
462+
* keep it alive
463+
*/
464+
static final ThreadLocal threadCalander = new ThreadLocal() {
465+
protected Object initialValue() {
466+
return Calendar.getInstance();
467+
}
468+
};
469+
457470
/**
458471
* Convert a DOS date/time field to a Date object.
459472
*
@@ -463,7 +476,12 @@ private void resolveLocalFileHeaderData()
463476
protected static Date fromDosTime( ZipLong l )
464477
{
465478
long dosTime = l.getValue();
466-
Calendar cal = Calendar.getInstance();
479+
return fromDosTime(dosTime);
480+
}
481+
482+
protected static Date fromDosTime( long dosTime )
483+
{
484+
Calendar cal = (Calendar) threadCalander.get();
467485
cal.set( Calendar.YEAR, (int) ( ( dosTime >> 25 ) & 0x7f ) + 1980 );
468486
cal.set( Calendar.MONTH, (int) ( ( dosTime >> 21 ) & 0x0f ) - 1 );
469487
cal.set( Calendar.DATE, (int) ( dosTime >> 16 ) & 0x1f );
@@ -586,5 +604,4 @@ void addDummy()
586604
addDummyByte = true;
587605
}
588606
}
589-
590607
}

src/main/java/org/codehaus/plexus/archiver/zip/ZipLong.java

Lines changed: 27 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -57,10 +57,7 @@ public ZipLong( byte[] bytes )
5757
*/
5858
public ZipLong( byte[] bytes, int offset )
5959
{
60-
value = ( bytes[ offset + 3 ] << 24 ) & 0xFF000000L;
61-
value += ( bytes[ offset + 2 ] << 16 ) & 0xFF0000;
62-
value += ( bytes[ offset + 1 ] << 8 ) & 0xFF00;
63-
value += ( bytes[ offset ] & 0xFF );
60+
value = convert(bytes, offset);
6461
}
6562

6663
/**
@@ -70,12 +67,7 @@ public ZipLong( byte[] bytes, int offset )
7067
*/
7168
public byte[] getBytes()
7269
{
73-
byte[] result = new byte[4];
74-
result[ 0 ] = (byte) ( ( value & 0xFF ) );
75-
result[ 1 ] = (byte) ( ( value & 0xFF00 ) >> 8 );
76-
result[ 2 ] = (byte) ( ( value & 0xFF0000 ) >> 16 );
77-
result[ 3 ] = (byte) ( ( value & 0xFF000000l ) >> 24 );
78-
return result;
70+
return bytes(value);
7971
}
8072

8173
/**
@@ -111,4 +103,29 @@ public int hashCode()
111103
{
112104
return (int) value;
113105
}
106+
107+
static long convert(byte[] bytes) {
108+
return convert(bytes, 0);
109+
}
110+
111+
static long convert(byte[] bytes, int offset) {
112+
long value = (bytes[offset + 3] << 24) & 0xFF000000L;
113+
value += (bytes[offset + 2] << 16) & 0xFF0000;
114+
value += (bytes[offset + 1] << 8) & 0xFF00;
115+
value += (bytes[offset] & 0xFF);
116+
117+
return value;
118+
}
119+
120+
static byte[] bytes(long value) {
121+
return bytes(value, new byte[4]);
122+
}
123+
124+
static byte[] bytes(long value, byte[] result) {
125+
result[0] = (byte) ((value & 0xFF));
126+
result[1] = (byte) ((value & 0xFF00) >> 8);
127+
result[2] = (byte) ((value & 0xFF0000) >> 16);
128+
result[3] = (byte) ((value & 0xFF000000l) >> 24);
129+
return result;
130+
}
114131
}

0 commit comments

Comments
 (0)