nl.topicus.jdbc.shaded.com.google.cloud.spanner.Operation Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of spanner-jdbc Show documentation
Show all versions of spanner-jdbc Show documentation
JDBC Driver for Google Cloud Spanner
/*
* Copyright 2017 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package nl.topicus.jdbc.shaded.com.google.cloud.spanner;
import nl.topicus.jdbc.shaded.com.google.api.core.ApiClock;
import nl.topicus.jdbc.shaded.com.google.api.core.CurrentMillisClock;
import nl.topicus.jdbc.shaded.com.google.api.gax.retrying.BasicResultRetryAlgorithm;
import nl.topicus.jdbc.shaded.com.google.api.gax.retrying.PollException;
import nl.topicus.jdbc.shaded.com.google.api.gax.retrying.RetrySettings;
import nl.topicus.jdbc.shaded.com.google.cloud.BaseServiceException;
import nl.topicus.jdbc.shaded.com.google.cloud.RetryHelper;
import nl.topicus.jdbc.shaded.com.google.cloud.RetryOption;
import nl.topicus.jdbc.shaded.com.google.cloud.spanner.spi.v1.SpannerRpc;
import nl.topicus.jdbc.shaded.com.google.common.annotations.VisibleForTesting;
import nl.topicus.jdbc.shaded.com.google.longrunning.Operation.ResultCase;
import nl.topicus.jdbc.shaded.com.google.protobuf.Any;
import nl.topicus.jdbc.shaded.com.google.rpc.Status;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import nl.topicus.jdbc.shaded.javax.annotation.Nullable;
import nl.topicus.jdbc.shaded.org.threeten.bp.Duration;
/** Represents a long running operation. */
// TODO(user): Implement other operations on Operation.
public class Operation {
private final RetrySettings DEFAULT_OPERATION_WAIT_SETTINGS =
RetrySettings.newBuilder()
.setTotalTimeout(Duration.ofHours(12L))
.setInitialRetryDelay(Duration.ofMillis(500L))
.setRetryDelayMultiplier(1.0)
.setJittered(false)
.setMaxRetryDelay(Duration.ofMinutes(500L))
.build();
static interface Parser {
R parseResult(Any response);
M parseMetadata(Any metadata);
}
private final M metadata;
private final R result;
private final SpannerException exception;
private final boolean isDone;
private final SpannerRpc rpc;
private final String name;
private final Parser parser;
private final ApiClock clock;
@VisibleForTesting
Operation(
SpannerRpc rpc,
String name,
@Nullable M metadata,
@Nullable R result,
@Nullable SpannerException exception,
boolean isDone,
Parser parser,
ApiClock clock) {
this.rpc = rpc;
this.name = name;
this.metadata = metadata;
this.result = result;
this.exception = exception;
this.isDone = isDone;
this.parser = parser;
this.clock = clock;
}
private static Operation failed(
SpannerRpc rpc, String name, Status status, M metadata, Parser parser, ApiClock clock) {
SpannerException e =
SpannerExceptionFactory.newSpannerException(
ErrorCode.fromRpcStatus(status), status.getMessage(), null);
return new Operation(rpc, name, metadata, null, e, true, parser, clock);
}
private static Operation successful(
SpannerRpc rpc, String name, M metadata, R result, Parser parser, ApiClock clock) {
return new Operation<>(rpc, name, metadata, result, null, true, parser, clock);
}
private static Operation pending(
SpannerRpc rpc, String name, M metadata, Parser parser, ApiClock clock) {
return new Operation<>(rpc, name, metadata, null, null, false, parser, clock);
}
static Operation create(
SpannerRpc rpc, nl.topicus.jdbc.shaded.com.google.longrunning.Operation proto, Parser parser) {
return Operation.create(rpc, proto, parser, CurrentMillisClock.getDefaultClock());
}
static Operation create(
SpannerRpc rpc, nl.topicus.jdbc.shaded.com.google.longrunning.Operation proto, Parser parser, ApiClock clock) {
M metadata = proto.hasMetadata() ? parser.parseMetadata(proto.getMetadata()) : null;
String name = proto.getName();
if (proto.getDone()) {
if (proto.getResultCase() == ResultCase.ERROR) {
return Operation.failed(rpc, name, proto.getError(), metadata, parser, clock);
} else {
return Operation.successful(
rpc, name, metadata, parser.parseResult(proto.getResponse()), parser, clock);
}
} else {
return Operation.pending(rpc, name, metadata, parser, clock);
}
}
/** Fetches the current status of this operation. */
public Operation reload() throws SpannerException {
if (isDone) {
return this;
}
nl.topicus.jdbc.shaded.com.google.longrunning.Operation proto = rpc.getOperation(name);
return Operation.create(rpc, proto, parser);
}
/**
* Blocks till the operation is complete or maximum time, if specified, has elapsed.
*
* @return null if operation is not found otherwise the current operation.
*/
public Operation waitFor(RetryOption... waitOptions) throws SpannerException {
if (isDone()) {
return this;
}
RetrySettings waitSettings =
RetryOption.mergeToSettings(DEFAULT_OPERATION_WAIT_SETTINGS, waitOptions);
try {
nl.topicus.jdbc.shaded.com.google.longrunning.Operation proto = RetryHelper.poll(
new Callable() {
@Override
public nl.topicus.jdbc.shaded.com.google.longrunning.Operation call() throws Exception {
return rpc.getOperation(name);
}
},
waitSettings,
new BasicResultRetryAlgorithm() {
@Override
public boolean shouldRetry(
Throwable prevThrowable, nl.topicus.jdbc.shaded.com.google.longrunning.Operation prevResponse) {
if (prevResponse != null) {
return !prevResponse.getDone();
}
if (prevThrowable instanceof SpannerException) {
SpannerException spannerException = (SpannerException) prevThrowable;
return spannerException.getErrorCode() != ErrorCode.NOT_FOUND
&& spannerException.isRetryable();
}
return false;
}
},
clock);
return Operation.create(rpc, proto, parser);
} catch (InterruptedException e) {
throw SpannerExceptionFactory.propagateInterrupt(e);
} catch (ExecutionException e) {
Throwable cause = e.getCause();
if (cause instanceof SpannerException) {
SpannerException spannerException = (SpannerException) cause;
if(spannerException.getErrorCode() == ErrorCode.NOT_FOUND) {
return null;
}
throw spannerException;
}
if (cause instanceof PollException) {
throw SpannerExceptionFactory.newSpannerException(
ErrorCode.DEADLINE_EXCEEDED, "Operation did not complete in the given time");
}
throw SpannerExceptionFactory.newSpannerException(cause);
}
}
/**
* Returns the metadata returned by the last refresh of this operation. Returns null if no
* metadata was returned or if this operation has not been refereshed.
*/
public M getMetadata() {
return metadata;
}
/** Returns true if the operation is done. */
public boolean isDone() {
return isDone;
}
/**
* Returns result of the operation if the operation is complete and had a result. Returns null if
* the operation is not complete or did not have a result.
*
* @throws SpannerException if the operation failed.
*/
public R getResult() throws SpannerException {
if (exception != null) {
throw exception;
}
return result;
}
/** Returns the name of the operation. */
public String getName() {
return name;
}
/** Returns true if the operation completed sucessfully. */
public boolean isSuccessful() {
return isDone && exception == null;
}
}