From 59d7eed239580030de4fcbceae521dc5765f20fa Mon Sep 17 00:00:00 2001 From: Lawrence Qiu Date: Tue, 13 Oct 2026 03:40:06 +0000 Subject: [PATCH] perf(bigquery): [T1-10] eliminate LinkedList staging and un-sized transforms in InsertAllRequest, insertAll, and InsertAllResponse --- .../google/cloud/bigquery/BigQueryImpl.java | 48 ++++++++--------- .../cloud/bigquery/InsertAllRequest.java | 2 +- .../cloud/bigquery/InsertAllResponse.java | 51 ++++++++++--------- .../cloud/bigquery/InsertAllResponseTest.java | 6 ++- 4 files changed, 53 insertions(+), 54 deletions(-) diff --git a/java-bigquery/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/BigQueryImpl.java b/java-bigquery/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/BigQueryImpl.java index 586becb710b2..3fd52f6c1ad2 100644 --- a/java-bigquery/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/BigQueryImpl.java +++ b/java-bigquery/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/BigQueryImpl.java @@ -62,7 +62,6 @@ import com.google.common.base.Function; import com.google.common.base.Strings; import com.google.common.base.Supplier; -import com.google.common.collect.FluentIterable; import com.google.common.collect.ImmutableList; import com.google.common.collect.Iterables; import com.google.common.collect.Lists; @@ -2053,23 +2052,13 @@ public InsertAllResponse insertAll(InsertAllRequest request) { requestPb.setIgnoreUnknownValues(request.ignoreUnknownValues()); requestPb.setSkipInvalidRows(request.skipInvalidRows()); requestPb.setTemplateSuffix(request.getTemplateSuffix()); - // Using an array of size 1 here to have a mutable boolean variable, which can - // be modified in - // an anonymous inner class. - final boolean[] allInsertIdsSet = {true}; - List rowsPb = - FluentIterable.from(request.getRows()) - .transform( - new Function() { - @Override - public Rows apply(RowToInsert rowToInsert) { - allInsertIdsSet[0] &= rowToInsert.getId() != null; - return new Rows() - .setInsertId(rowToInsert.getId()) - .setJson(rowToInsert.getContent()); - } - }) - .toList(); + List rows = request.getRows(); + List rowsPb = new ArrayList<>(rows.size()); + boolean allInsertIdsSet = true; + for (RowToInsert rowToInsert : rows) { + allInsertIdsSet &= rowToInsert.getId() != null; + rowsPb.add(new Rows().setInsertId(rowToInsert.getId()).setJson(rowToInsert.getContent())); + } requestPb.setRows(rowsPb); TableDataInsertAllResponse responsePb; @@ -2084,7 +2073,7 @@ && getOptions().getOpenTelemetryTracer() != null) { .startSpan(); } try (Scope insertAllScope = insertAll != null ? insertAll.makeCurrent() : null) { - if (allInsertIdsSet[0]) { + if (allInsertIdsSet) { // allowing retries only if all row insertIds are set (used for deduplication) try { responsePb = @@ -2447,11 +2436,9 @@ public com.google.api.services.bigquery.model.QueryResponse call() } if (results.getErrors() != null) { - List bigQueryErrors = - Lists.transform(results.getErrors(), BigQueryError.FROM_PB_FUNCTION); // Throwing BigQueryException since there may be no JobId and we want to stay consistent // with the case where there is an HTTP error - throw new BigQueryException(bigQueryErrors); + throw new BigQueryException(fromErrorPbList(results.getErrors())); } long numRows; @@ -2533,6 +2520,15 @@ private static TableResult.Builder newTableResultBuilder( .setCacheHit(results.getCacheHit()); } + private static ImmutableList fromErrorPbList(List errorsPb) { + ImmutableList.Builder builder = + ImmutableList.builderWithExpectedSize(errorsPb.size()); + for (ErrorProto errorProto : errorsPb) { + builder.add(errorProto != null ? BigQueryError.fromPb(errorProto) : null); + } + return builder.build(); + } + private static long getNumRows(com.google.api.services.bigquery.model.QueryResponse results) { if (results.getNumDmlAffectedRows() == null && results.getTotalRows() == null) { return 0L; @@ -2591,9 +2587,7 @@ && getOptions().getOpenTelemetryTracer() != null) { } if (results.getErrors() != null) { - List bigQueryErrors = - Lists.transform(results.getErrors(), BigQueryError.FROM_PB_FUNCTION); - throw new BigQueryException(bigQueryErrors); + throw new BigQueryException(fromErrorPbList(results.getErrors())); } // If the query is incomplete (took longer than the fast-path timeout), transition @@ -2862,9 +2856,7 @@ && getOptions().getOpenTelemetryTracer() != null) { } if (results.getErrors() != null && !results.getErrors().isEmpty()) { - List bigQueryErrors = - Lists.transform(results.getErrors(), BigQueryError.FROM_PB_FUNCTION); - throw new BigQueryException(bigQueryErrors); + throw new BigQueryException(fromErrorPbList(results.getErrors())); } JobId actualJobId = diff --git a/java-bigquery/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/InsertAllRequest.java b/java-bigquery/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/InsertAllRequest.java index ce93800987f7..514298add461 100644 --- a/java-bigquery/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/InsertAllRequest.java +++ b/java-bigquery/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/InsertAllRequest.java @@ -173,7 +173,7 @@ public Builder setTable(TableId table) { /** Sets the rows to insert as a list of {@link RowToInsert} objects. */ public Builder setRows(Iterable rows) { - this.rows = Lists.newLinkedList(checkNotNull(rows)); + this.rows = Lists.newArrayList(checkNotNull(rows)); return this; } diff --git a/java-bigquery/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/InsertAllResponse.java b/java-bigquery/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/InsertAllResponse.java index 9a75f5cbd6ae..bd58def425c1 100644 --- a/java-bigquery/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/InsertAllResponse.java +++ b/java-bigquery/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/InsertAllResponse.java @@ -19,14 +19,11 @@ import com.google.api.services.bigquery.model.ErrorProto; import com.google.api.services.bigquery.model.TableDataInsertAllResponse; import com.google.api.services.bigquery.model.TableDataInsertAllResponse.InsertErrors; -import com.google.common.base.Function; import com.google.common.base.MoreObjects; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; -import com.google.common.collect.Iterables; -import com.google.common.collect.Lists; -import com.google.common.collect.Maps; import java.io.Serializable; +import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.Objects; @@ -93,19 +90,17 @@ public String toString() { TableDataInsertAllResponse toPb() { TableDataInsertAllResponse responsePb = new TableDataInsertAllResponse(); if (!insertErrors.isEmpty()) { - responsePb.setInsertErrors( - ImmutableList.copyOf( - Iterables.transform( - insertErrors.entrySet(), - new Function>, InsertErrors>() { - @Override - public InsertErrors apply(Map.Entry> entry) { - return new InsertErrors() - .setIndex(entry.getKey()) - .setErrors( - Lists.transform(entry.getValue(), BigQueryError.TO_PB_FUNCTION)); - } - }))); + ImmutableList.Builder errorsBuilder = + ImmutableList.builderWithExpectedSize(insertErrors.size()); + for (Map.Entry> entry : insertErrors.entrySet()) { + List rowErrors = entry.getValue(); + List errorsPb = new ArrayList<>(rowErrors.size()); + for (BigQueryError error : rowErrors) { + errorsPb.add(error != null ? error.toPb() : null); + } + errorsBuilder.add(new InsertErrors().setIndex(entry.getKey()).setErrors(errorsPb)); + } + responsePb.setInsertErrors(errorsBuilder.build()); } return responsePb; } @@ -114,14 +109,24 @@ static InsertAllResponse fromPb(TableDataInsertAllResponse responsePb) { Map> insertErrors = null; if (responsePb.getInsertErrors() != null) { List errorsPb = responsePb.getInsertErrors(); - insertErrors = Maps.newHashMapWithExpectedSize(errorsPb.size()); + ImmutableMap.Builder> mapBuilder = + ImmutableMap.builderWithExpectedSize(errorsPb.size()); for (InsertErrors errorPb : errorsPb) { - insertErrors.put( - errorPb.getIndex(), - Lists.transform( - errorPb.getErrors() != null ? errorPb.getErrors() : ImmutableList.of(), - BigQueryError.FROM_PB_FUNCTION)); + List rowErrorsPb = errorPb.getErrors(); + ImmutableList rowErrors; + if (rowErrorsPb != null && !rowErrorsPb.isEmpty()) { + ImmutableList.Builder rowErrorsBuilder = + ImmutableList.builderWithExpectedSize(rowErrorsPb.size()); + for (ErrorProto errorProto : rowErrorsPb) { + rowErrorsBuilder.add(errorProto != null ? BigQueryError.fromPb(errorProto) : null); + } + rowErrors = rowErrorsBuilder.build(); + } else { + rowErrors = ImmutableList.of(); + } + mapBuilder.put(errorPb.getIndex(), rowErrors); } + insertErrors = mapBuilder.buildKeepingLast(); } return new InsertAllResponse(insertErrors); } diff --git a/java-bigquery/google-cloud-bigquery/src/test/java/com/google/cloud/bigquery/InsertAllResponseTest.java b/java-bigquery/google-cloud-bigquery/src/test/java/com/google/cloud/bigquery/InsertAllResponseTest.java index 9b30e25860b1..78dc69571361 100644 --- a/java-bigquery/google-cloud-bigquery/src/test/java/com/google/cloud/bigquery/InsertAllResponseTest.java +++ b/java-bigquery/google-cloud-bigquery/src/test/java/com/google/cloud/bigquery/InsertAllResponseTest.java @@ -19,6 +19,7 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertSame; import static org.junit.jupiter.api.Assertions.assertTrue; import com.google.common.collect.ImmutableList; @@ -63,8 +64,9 @@ public void testHasErrors() { @Test public void testToPbAndFromPb() { - compareInsertAllResponse( - INSERT_ALL_RESPONSE, InsertAllResponse.fromPb(INSERT_ALL_RESPONSE.toPb())); + InsertAllResponse fromPb = InsertAllResponse.fromPb(INSERT_ALL_RESPONSE.toPb()); + compareInsertAllResponse(INSERT_ALL_RESPONSE, fromPb); + assertSame(fromPb.getErrorsFor(0L).get(0), fromPb.getErrorsFor(0L).get(0)); compareInsertAllResponse( EMPTY_INSERT_ALL_RESPONSE, InsertAllResponse.fromPb(EMPTY_INSERT_ALL_RESPONSE.toPb())); }