Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -31,14 +31,17 @@

import static com.google.common.base.Preconditions.checkNotNull;

import com.google.api.core.ApiClock;
import com.google.api.core.ApiFuture;
import com.google.api.core.ApiFutureCallback;
import com.google.api.core.ApiFutures;
import com.google.api.core.NanoClock;
import com.google.api.core.SettableApiFuture;
import com.google.api.gax.resumable.ChunkUploadRequest;
import com.google.api.gax.resumable.ChunkUploadResponse;
import com.google.api.gax.resumable.QueryStatusRequest;
import com.google.api.gax.resumable.QueryStatusResponse;
import com.google.api.gax.retrying.RetrySettings;
import com.google.api.gax.retrying.RetryingFuture;
import com.google.common.util.concurrent.MoreExecutors;
import java.time.Duration;
Expand Down Expand Up @@ -68,6 +71,8 @@
private final RewindableStreamBuffer buffer;
private final String uploadUrl;
private final ApiCallContext originalCallContext;
private final long deadlineNanos;
private final ApiClock clock;

private volatile ChunkUploadRequest currentRequest;
private volatile ResumableUploadCommand currentCommand;
Expand All @@ -85,6 +90,28 @@
ChunkUploadRequest request,
ApiCallContext callContext,
ResumableUploadCommand command) {
this(
uploadChunkCallable,
queryStatusCallable,
buffer,
uploadUrl,
request,
callContext,
command,
Long.MAX_VALUE,
NanoClock.getDefaultClock());
}

ChunkAttemptCallable(

Check warning on line 105 in sdk-platform-java/gax-java/gax/src/main/java/com/google/api/gax/rpc/ChunkAttemptCallable.java

View check run for this annotation

SonarQubeCloud / [gapic-generator-java-root] SonarCloud Code Analysis

Constructor has 9 parameters, which is greater than 7 authorized.

See more on https://sonarcloud.io/project/issues?id=googleapis_google-cloud-java_showcase&issues=AaCyXlVFNxZs2PJzo0Ag&open=AaCyXlVFNxZs2PJzo0Ag&pullRequest=14425

Check warning on line 105 in sdk-platform-java/gax-java/gax/src/main/java/com/google/api/gax/rpc/ChunkAttemptCallable.java

View check run for this annotation

SonarQubeCloud / [gapic-generator-java-root] SonarCloud Code Analysis

"currentRequest" is marked "@NullMarked at class level" but is not initialized in this constructor.

See more on https://sonarcloud.io/project/issues?id=googleapis_google-cloud-java_showcase&issues=AaCyXlVFNxZs2PJzo0Af&open=AaCyXlVFNxZs2PJzo0Af&pullRequest=14425
UnaryCallable<ChunkUploadRequest, ChunkUploadResponse<ResponseT>> uploadChunkCallable,
UnaryCallable<QueryStatusRequest, QueryStatusResponse<ResponseT>> queryStatusCallable,
RewindableStreamBuffer buffer,
String uploadUrl,
ChunkUploadRequest request,
ApiCallContext callContext,
ResumableUploadCommand command,
long deadlineNanos,
ApiClock clock) {
this.uploadChunkCallable =
checkNotNull(uploadChunkCallable, "uploadChunkCallable must not be null");
this.queryStatusCallable =
Expand All @@ -94,6 +121,8 @@
this.currentRequest = checkNotNull(request, "request must not be null");
this.originalCallContext = checkNotNull(callContext, "callContext must not be null");
this.currentCommand = checkNotNull(command, "command must not be null");
this.deadlineNanos = deadlineNanos;
this.clock = checkNotNull(clock, "clock must not be null");
}

void setRetryingFuture(RetryingFuture<ChunkUploadResponse<ResponseT>> retryingFuture) {
Expand Down Expand Up @@ -129,10 +158,37 @@
SettableApiFuture<ChunkUploadResponse<ResponseT>> attemptFuture,
ApiCallContext attemptContext,
RetryingFuture<ChunkUploadResponse<ResponseT>> currentRetryingFuture) {
// Per GAX-R7: query uses sensible unary defaults trimmed to the remaining global deadline.
long remainingNanos =
deadlineNanos == Long.MAX_VALUE
? Long.MAX_VALUE
: Math.max(1L, deadlineNanos - clock.nanoTime());
Duration queryTotal =
Duration.ofNanos(
Math.min(
ResumableUploadCallableImpl.DEFAULT_QUERY_RETRY_SETTINGS
.getTotalTimeoutDuration()
.toNanos(),
remainingNanos));
Duration queryRpc =
Duration.ofNanos(
Math.min(
ResumableUploadCallableImpl.DEFAULT_QUERY_RETRY_SETTINGS
.getInitialRpcTimeoutDuration()
.toNanos(),
queryTotal.toNanos()));
RetrySettings trimmedQuerySettings =
ResumableUploadCallableImpl.DEFAULT_QUERY_RETRY_SETTINGS.toBuilder()
.setTotalTimeoutDuration(queryTotal)
.setInitialRpcTimeoutDuration(queryRpc)
.setMaxRpcTimeoutDuration(queryRpc)
.build();
ApiCallContext queryContext = originalCallContext.withRetrySettings(trimmedQuerySettings);

QueryStatusRequest queryRequest = QueryStatusRequest.create(uploadUrl);
ApiFuture<QueryStatusResponse<ResponseT>> queryFuture =
queryStatusCallable.futureCall(queryRequest, attemptContext);
queryStatusCallable.futureCall(queryRequest, queryContext);
if (queryFuture == null) {

Check warning on line 191 in sdk-platform-java/gax-java/gax/src/main/java/com/google/api/gax/rpc/ChunkAttemptCallable.java

View check run for this annotation

SonarQubeCloud / [gapic-generator-java-root] SonarCloud Code Analysis

Change this condition so that it does not always evaluate to "false"

See more on https://sonarcloud.io/project/issues?id=googleapis_google-cloud-java_showcase&issues=AaCyXlVFNxZs2PJzo0Ae&open=AaCyXlVFNxZs2PJzo0Ae&pullRequest=14425
failAttempt(
attemptFuture, new IllegalStateException("queryStatusCallable returned a null future"));
return;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,19 +45,31 @@
@NullMarked
public abstract class ResumableUploadCallSettings {
private static final int DEFAULT_CHUNK_SIZE = 8 * 1024 * 1024; // 8 MB
// Matches Ruby google-apis-core RequestOptions.default.max_elapsed_time = 900s (CL-R9).
private static final Duration DEFAULT_GLOBAL_TIMEOUT = Duration.ofMinutes(15);

abstract @Nullable Integer chunkSizeOption();

abstract @Nullable Duration globalTimeoutOption();

/** Returns the configured chunk size in bytes (defaults to 8 MB / 8,388,608 bytes). */
public abstract int getChunkSize();
public int getChunkSize() {
Integer size = chunkSizeOption();
return size != null ? size : DEFAULT_CHUNK_SIZE;
}

/**
* Returns the global upload timeout governing the entire upload duration, or {@code null} if
* disabled.
* Returns the global upload timeout governing the entire upload duration (defaults to 15
* minutes).
*/
public abstract @Nullable Duration getGlobalTimeout();
public Duration getGlobalTimeout() {
Duration timeout = globalTimeoutOption();
return timeout != null ? timeout : DEFAULT_GLOBAL_TIMEOUT;
}

/**
* Merges another {@code ResumableUploadCallSettings} instance with this one. Fields set in {@code
* other} override fields in this instance.
* Merges another {@code ResumableUploadCallSettings} instance with this one. Fields explicitly
* set in {@code other} override fields in this instance.
*
* @param other settings to overlay; may be {@code null}
* @return a new, resolved {@code ResumableUploadCallSettings} instance
Expand All @@ -67,40 +79,60 @@
return this;
}
Builder builder = toBuilder();
if (other.getChunkSize() > 0) {
builder.setChunkSize(other.getChunkSize());
if (other.chunkSizeOption() != null) {
builder.setChunkSize(other.chunkSizeOption());

Check warning on line 83 in sdk-platform-java/gax-java/gax/src/main/java/com/google/api/gax/rpc/ResumableUploadCallSettings.java

View check run for this annotation

SonarQubeCloud / [gapic-generator-java-root] SonarCloud Code Analysis

Annotate the parameter with @javax.annotation.Nullable in method 'setChunkSize' declaration, or make sure that null can not be passed as argument.

See more on https://sonarcloud.io/project/issues?id=googleapis_google-cloud-java_showcase&issues=AaCyXlU6NxZs2PJzo0Ad&open=AaCyXlU6NxZs2PJzo0Ad&pullRequest=14425
}
if (other.getGlobalTimeout() != null) {
builder.setGlobalTimeout(other.getGlobalTimeout());
if (other.globalTimeoutOption() != null) {
builder.setGlobalTimeout(other.globalTimeoutOption());
}
return builder.build();
}

public abstract Builder toBuilder();

public static Builder newBuilder() {
return new AutoValue_ResumableUploadCallSettings.Builder().setChunkSize(DEFAULT_CHUNK_SIZE);
return new AutoValue_ResumableUploadCallSettings.Builder();
}

/** Builder for {@link ResumableUploadCallSettings}. */
@AutoValue.Builder
public abstract static class Builder {
public abstract Builder setChunkSize(int chunkSize);
abstract Builder setChunkSizeOption(@Nullable Integer chunkSize);

public abstract int getChunkSize();
abstract @Nullable Integer chunkSizeOption();

public abstract Builder setGlobalTimeout(@Nullable Duration globalTimeout);
public Builder setChunkSize(int chunkSize) {
return setChunkSizeOption(chunkSize);
}

public int getChunkSize() {
Integer size = chunkSizeOption();
return size != null ? size : DEFAULT_CHUNK_SIZE;
}

public abstract @Nullable Duration getGlobalTimeout();
abstract Builder setGlobalTimeoutOption(@Nullable Duration globalTimeout);

abstract @Nullable Duration globalTimeoutOption();

public Builder setGlobalTimeout(@Nullable Duration globalTimeout) {
return setGlobalTimeoutOption(globalTimeout);
}

public @Nullable Duration getGlobalTimeout() {
return globalTimeoutOption();
}

abstract ResumableUploadCallSettings autoBuild();

public ResumableUploadCallSettings build() {
Preconditions.checkArgument(getChunkSize() > 0, "chunkSize must be > 0");
if (getGlobalTimeout() != null) {
Integer size = chunkSizeOption();
if (size != null) {
Preconditions.checkArgument(size > 0, "chunkSize must be > 0");
}
Duration timeout = globalTimeoutOption();
if (timeout != null) {
Preconditions.checkArgument(
!getGlobalTimeout().isNegative() && !getGlobalTimeout().isZero(),
"globalTimeout must be positive");
!timeout.isNegative() && !timeout.isZero(), "globalTimeout must be positive");
}
return autoBuild();
}
Expand Down
Loading
Loading