Skip to content

Commit 90e9d61

Browse files
Optimize GoogleCloudStorageHttpHandler (#49677) (#49707)
Removing a lot of needless buffering and array creation to reduce the significant memory usage of tests using this. The incoming stream from the `exchange` is already buffered so there is no point in adding a ton of additional buffers everywhere.
1 parent a59b7e0 commit 90e9d61

File tree

1 file changed

+49
-38
lines changed

1 file changed

+49
-38
lines changed

test/fixtures/gcs-fixture/src/main/java/fixture/gcs/GoogleCloudStorageHttpHandler.java

+49-38
Original file line numberDiff line numberDiff line change
@@ -161,7 +161,7 @@ public void handle(final HttpExchange exchange) throws IOException {
161161
// Batch https://cloud.google.com/storage/docs/json_api/v1/how-tos/batch
162162
final String uri = "/storage/v1/b/" + bucket + "/o/";
163163
final StringBuilder batch = new StringBuilder();
164-
for (String line : Streams.readAllLines(new BufferedInputStream(wrappedRequest))) {
164+
for (String line : Streams.readAllLines(wrappedRequest)) {
165165
if (line.length() == 0 || line.startsWith("--") || line.toLowerCase(Locale.ROOT).startsWith("content")) {
166166
batch.append(line).append('\n');
167167
} else if (line.startsWith("DELETE")) {
@@ -226,8 +226,13 @@ public void handle(final HttpExchange exchange) throws IOException {
226226
final int start = getContentRangeStart(range);
227227
final int end = getContentRangeEnd(range);
228228

229-
final ByteArrayOutputStream out = new ByteArrayOutputStream();
230-
long bytesRead = Streams.copy(wrappedRequest, out);
229+
final ByteArrayOutputStream out = new ByteArrayOutputStream() {
230+
@Override
231+
public byte[] toByteArray() {
232+
return buf;
233+
}
234+
};
235+
long bytesRead = Streams.copy(wrappedRequest, out, new byte[128]);
231236
int length = Math.max(end + 1, limit != null ? limit : 0);
232237
if ((int) bytesRead > length) {
233238
throw new AssertionError("Requesting more bytes than available for blob");
@@ -267,56 +272,62 @@ private String httpServerUrl(final HttpExchange exchange) {
267272
return "http://" + InetAddresses.toUriString(address.getAddress()) + ":" + address.getPort();
268273
}
269274

275+
private static final Pattern NAME_PATTERN = Pattern.compile("\"name\":\"([^\"]*)\"");
276+
270277
public static Optional<Tuple<String, BytesArray>> parseMultipartRequestBody(final InputStream requestBody) throws IOException {
271278
Tuple<String, BytesArray> content = null;
272279
try (BufferedInputStream in = new BufferedInputStream(new GZIPInputStream(requestBody))) {
273280
String name = null;
274281
int read;
282+
ByteArrayOutputStream out = new ByteArrayOutputStream() {
283+
@Override
284+
public byte[] toByteArray() {
285+
return buf;
286+
}
287+
};
275288
while ((read = in.read()) != -1) {
289+
out.reset();
276290
boolean markAndContinue = false;
277-
try (ByteArrayOutputStream out = new ByteArrayOutputStream()) {
278-
do { // search next consecutive {carriage return, new line} chars and stop
279-
if ((char) read == '\r') {
280-
int next = in.read();
281-
if (next != -1) {
282-
if (next == '\n') {
283-
break;
284-
}
285-
out.write(read);
286-
out.write(next);
287-
continue;
291+
do { // search next consecutive {carriage return, new line} chars and stop
292+
if ((char) read == '\r') {
293+
int next = in.read();
294+
if (next != -1) {
295+
if (next == '\n') {
296+
break;
288297
}
289-
}
290-
out.write(read);
291-
} while ((read = in.read()) != -1);
292-
293-
final String line = new String(out.toByteArray(), UTF_8);
294-
if (line.length() == 0 || line.equals("\r\n") || line.startsWith("--")
295-
|| line.toLowerCase(Locale.ROOT).startsWith("content")) {
296-
markAndContinue = true;
297-
} else if (line.startsWith("{\"bucket\":")) {
298-
markAndContinue = true;
299-
Matcher matcher = Pattern.compile("\"name\":\"([^\"]*)\"").matcher(line);
300-
if (matcher.find()) {
301-
name = matcher.group(1);
298+
out.write(read);
299+
out.write(next);
300+
continue;
302301
}
303302
}
304-
if (markAndContinue) {
305-
in.mark(Integer.MAX_VALUE);
306-
continue;
303+
out.write(read);
304+
} while ((read = in.read()) != -1);
305+
final String bucketPrefix = "{\"bucket\":";
306+
final String start = new String(out.toByteArray(), 0, Math.min(out.size(), bucketPrefix.length()), UTF_8);
307+
if (start.length() == 0 || start.equals("\r\n") || start.startsWith("--")
308+
|| start.toLowerCase(Locale.ROOT).startsWith("content")) {
309+
markAndContinue = true;
310+
} else if (start.startsWith(bucketPrefix)) {
311+
markAndContinue = true;
312+
final String line = new String(out.toByteArray(), bucketPrefix.length(), out.size() - bucketPrefix.length(), UTF_8);
313+
Matcher matcher = NAME_PATTERN.matcher(line);
314+
if (matcher.find()) {
315+
name = matcher.group(1);
307316
}
308317
}
318+
if (markAndContinue) {
319+
in.mark(Integer.MAX_VALUE);
320+
continue;
321+
}
309322
if (name != null) {
310323
in.reset();
311-
try (ByteArrayOutputStream binary = new ByteArrayOutputStream()) {
312-
while ((read = in.read()) != -1) {
313-
binary.write(read);
314-
}
315-
binary.flush();
316-
byte[] tmp = binary.toByteArray();
317-
// removes the trailing end "\r\n--__END_OF_PART__--\r\n" which is 23 bytes long
318-
content = Tuple.tuple(name, new BytesArray(Arrays.copyOf(tmp, tmp.length - 23)));
324+
out.reset();
325+
while ((read = in.read()) != -1) {
326+
out.write(read);
319327
}
328+
// removes the trailing end "\r\n--__END_OF_PART__--\r\n" which is 23 bytes long
329+
content = Tuple.tuple(name, new BytesArray(Arrays.copyOf(out.toByteArray(), out.size() - 23)));
330+
break;
320331
}
321332
}
322333
}

0 commit comments

Comments
 (0)