Skip to content

Commit 086d3f8

Browse files
committed
improve performance of ReadOnlyZipStore.getArchiveComment
1 parent 7e0e90e commit 086d3f8

File tree

1 file changed

+75
-22
lines changed

1 file changed

+75
-22
lines changed

src/main/java/dev/zarr/zarrjava/store/ReadOnlyZipStore.java

Lines changed: 75 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -52,28 +52,49 @@ public ByteBuffer get(String[] keys, long start) {
5252
}
5353

5454
public String getArchiveComment() throws IOException {
55-
ByteBuffer buffer = underlyingStore.read();
56-
if (buffer == null) {
57-
return null;
58-
}
59-
byte[] bufArray;
60-
if (buffer.hasArray()) {
61-
bufArray = buffer.array();
62-
} else {
63-
bufArray = new byte[buffer.remaining()];
64-
buffer.duplicate().get(bufArray);
55+
// Attempt to read from the end of the file to find the EOCD record.
56+
// We try a small chunk first (1KB) which covers most short comments (or no comment),
57+
// then the maximum possible EOCD size (approx 65KB).
58+
int[] readSizes = {1024, 65535 + 22};
59+
60+
for (int size : readSizes) {
61+
ByteBuffer buffer;
62+
long fileSize = underlyingStore.getSize();
63+
64+
if (fileSize < size){
65+
buffer = underlyingStore.read();
66+
}
67+
else {
68+
buffer = underlyingStore.read(fileSize - size);
69+
}
70+
71+
if (buffer == null) {
72+
return null;
73+
}
74+
75+
byte[] bufArray;
76+
if (buffer.hasArray()) {
77+
bufArray = buffer.array();
78+
} else {
79+
bufArray = new byte[buffer.remaining()];
80+
buffer.duplicate().get(bufArray);
81+
}
82+
83+
String comment = getZipCommentFromBuffer(bufArray);
84+
if (comment != null) {
85+
return comment;
86+
}
6587
}
66-
return getZipCommentFromBuffer(bufArray);
88+
return null;
6789
}
68-
6990
@Nullable
7091
@Override
7192
public ByteBuffer get(String[] keys, long start, long end) {
72-
ByteBuffer buffer = underlyingStore.read();
73-
if (buffer == null) {
93+
InputStream inputStream = underlyingStore.getInputStream();
94+
if (inputStream == null) {
7495
return null;
7596
}
76-
try (ZipArchiveInputStream zis = new ZipArchiveInputStream(new ByteBufferBackedInputStream(buffer))) {
97+
try (ZipArchiveInputStream zis = new ZipArchiveInputStream(inputStream)) {
7798
ZipArchiveEntry entry;
7899
while ((entry = zis.getNextEntry()) != null) {
79100
String entryName = entry.getName();
@@ -147,11 +168,11 @@ public ReadOnlyZipStore(@Nonnull String underlyingStorePath) {
147168
public Stream<String[]> list(String[] keys) {
148169
Stream.Builder<String[]> builder = Stream.builder();
149170

150-
ByteBuffer buffer = underlyingStore.read();
151-
if (buffer == null) {
171+
InputStream inputStream = underlyingStore.getInputStream();
172+
if (inputStream == null) {
152173
return builder.build();
153174
}
154-
try (ZipArchiveInputStream zis = new ZipArchiveInputStream(new ByteBufferBackedInputStream(buffer))) {
175+
try (ZipArchiveInputStream zis = new ZipArchiveInputStream(inputStream)) {
155176
ZipArchiveEntry entry;
156177
String prefix = resolveKeys(keys);
157178
while ((entry = zis.getNextEntry()) != null) {
@@ -166,9 +187,7 @@ public Stream<String[]> list(String[] keys) {
166187
String[] entryKeys = resolveEntryKeys(entryName.substring(prefix.length()));
167188
builder.add(entryKeys);
168189
}
169-
} catch (IOException e) {
170-
return null;
171-
}
190+
} catch (IOException ignored) {}
172191
return builder.build();
173192
}
174193

@@ -201,8 +220,42 @@ public InputStream getInputStream(String[] keys, long start, long end) {
201220
return new BoundedInputStream(zis, bytesToRead);
202221
}
203222
return null;
223+
} catch (IOException ignored) {}
224+
return null;
225+
}
226+
227+
@Override
228+
public long getSize(String[] keys) {
229+
InputStream inputStream = underlyingStore.getInputStream();
230+
if (inputStream == null) {
231+
throw new RuntimeException(new IOException("Underlying store input stream is null"));
232+
}
233+
try (ZipArchiveInputStream zis = new ZipArchiveInputStream(inputStream)) {
234+
ZipArchiveEntry entry;
235+
while ((entry = zis.getNextEntry()) != null) {
236+
String entryName = entry.getName();
237+
238+
if (entryName.startsWith("/")) {
239+
entryName = entryName.substring(1);
240+
}
241+
if (entry.isDirectory() || !entryName.equals(resolveKeys(keys))) {
242+
continue;
243+
}
244+
long size = entry.getSize();
245+
if (size < 0) {
246+
// read the entire entry to determine size
247+
size = 0;
248+
byte[] bufferArray = new byte[8192];
249+
int len;
250+
while ((len = zis.read(bufferArray)) != -1) {
251+
size += len;
252+
}
253+
}
254+
return size;
255+
}
256+
throw new RuntimeException(new java.io.FileNotFoundException("Key not found: " + resolveKeys(keys)));
204257
} catch (IOException e) {
258+
throw new RuntimeException(e);
205259
}
206-
return null;
207260
}
208261
}

0 commit comments

Comments
 (0)