use of io.grpc.Status.Code in project etcd-java by IBM.
the class EtcdClient method refreshCredentials.
private CallCredentials refreshCredentials() {
return new CallCredentials() {
// TODO volatile TBD
private Metadata tokenHeader;
private final long authTime = System.currentTimeMillis();
private final ListenableFuture<Metadata> futureTokenHeader = Futures.transform(authenticate(), (Function<AuthenticateResponse, Metadata>) ar -> tokenHeader = tokenHeader(ar));
@Override
public void applyRequestMetadata(MethodDescriptor<?, ?> method, Attributes attrs, Executor appExecutor, MetadataApplier applier) {
Metadata tokHeader = tokenHeader;
if (tokHeader != null)
applier.apply(tokHeader);
else
futureTokenHeader.addListener(() -> {
try {
applier.apply(futureTokenHeader.get());
} catch (ExecutionException | InterruptedException ee) {
// (IE won't be thrown)
Status failStatus = Status.fromThrowable(ee.getCause());
Code code = failStatus != null ? failStatus.getCode() : null;
if (code != Code.INVALID_ARGUMENT && (System.currentTimeMillis() - authTime) > 15_000L) {
// this will force another auth attempt
failStatus = Status.UNAUTHENTICATED.withDescription("re-attempt re-auth");
}
applier.fail(failStatus);
}
}, directExecutor());
}
// @Override
public void thisUsesUnstableApi() {
}
};
}
use of io.grpc.Status.Code in project etcd-java by IBM.
the class RangeCache method strongIterator.
/**
* Iterator whose contents is guaranteed to be sequentially consistent
* with remote updates to the cached range.
*
* @return an {@link Iterator} over the {@link KeyValues} of this cache
*/
public Iterator<KeyValue> strongIterator() {
// memory barrier prior to reading seenUpToRev
entries.get(fromKey);
long seenUpTo = seenUpToRev;
if (seenUpTo == 0L) {
ListenableFuture<Boolean> startFut;
synchronized (this) {
startFut = startFuture;
}
if (startFut == null) {
// cache has not yet been started
return kvClient.get(fromKey).rangeEnd(toKey).timeout(120_000L).sync().getKvsList().iterator();
} else
try {
startFut.get(2L, TimeUnit.MINUTES);
// now started
seenUpTo = seenUpToRev;
} catch (TimeoutException te) {
throw Status.DEADLINE_EXCEEDED.asRuntimeException();
} catch (ExecutionException e) {
throw Status.UNKNOWN.withCause(e).asRuntimeException();
} catch (InterruptedException | CancellationException e) {
throw Status.CANCELLED.withCause(e).asRuntimeException();
}
}
/*
* This logic is similar to that in fullRefreshCache(), but
* it includes an optimistic initial comparison of counts
* to identify cases where no deletions have been missed and
* thus a retrieval of all the keys isn't required.
*/
RangeRequest.Builder rangeReqBld = RangeRequest.newBuilder().setKey(fromKey).setRangeEnd(toKey);
RangeRequest curCountReq = rangeReqBld.setCountOnly(true).setMaxCreateRevision(seenUpTo).build();
RangeRequest seenCountReq = rangeReqBld.clearMaxCreateRevision().setRevision(seenUpTo).build();
RangeRequest newModsReq = rangeReqBld.clearRevision().clearCountOnly().setMinModRevision(seenUpTo + 1).build();
// first, attempt to get:
// 0- kvs modified since seenUpTo
// 1- current count excluding those created since seenUpTo
// 2- count at revision seenUpTo (this could potentially
// fail with compaction error, see below)
ListenableFuture<TxnResponse> txn = kvClient.batch().get(newModsReq).get(curCountReq).get(seenCountReq).async();
TxnResponse txnResp;
try {
txnResp = waitFor(txn, 8000L);
} catch (RuntimeException e) {
Code code = Status.fromThrowable(e).getCode();
if (code != Code.OUT_OF_RANGE)
throw e;
// if (2) above fails due to compaction, also retrieve all current keys
RangeRequest otherKeysReq = rangeReqBld.clearMinModRevision().setMaxModRevision(seenUpTo).setKeysOnly(true).build();
txnResp = waitFor(kvClient.batch().get(newModsReq).get(otherKeysReq).async(), // longer timeout
60_000L);
}
long revNow = txnResp.getHeader().getRevision();
if (revNow > seenUpToRev) {
RangeResponse newModKvs = txnResp.getResponses(0).getResponseRange();
List<KeyValue> otherKeys;
if (txnResp.getResponsesCount() == 2) {
// this means we must have taken the compacted exception path above
otherKeys = txnResp.getResponses(1).getResponseRange().getKvsList();
} else if (// <- latest count
txnResp.getResponses(1).getResponseRange().getCount() < txnResp.getResponses(2).getResponseRange().getCount()) {
// <- count at seenUpTo
// if counts don't match, there must have been deletions since seenUpTo,
// so additionally retrieve all current keys
RangeRequest otherKeysReq = rangeReqBld.clearMinModRevision().setMaxModRevision(seenUpTo).setKeysOnly(true).build();
// longer timeout
otherKeys = waitFor(kvClient.get(otherKeysReq), 60_000L).getKvsList();
} else
otherKeys = null;
boolean newKvs = newModKvs.getKvsCount() > 0;
if (otherKeys != null) {
// if this is true, there *might* be deletions to process
if (otherKeys.isEmpty() && !newKvs)
return Collections.emptyIterator();
// bring cache up to date with recently deleted kvs
Set<ByteString> keys = Stream.concat(otherKeys.stream(), newModKvs.getKvsList().stream()).map(kv -> kv.getKey()).collect(Collectors.toSet());
entries.values().stream().filter(kv -> kv.getModRevision() < revNow && !keys.contains(kv.getKey())).forEach(kv -> offerDelete(kv.getKey(), revNow));
}
// bring cache up to date with recently modified kvs
if (newKvs)
newModKvs.getKvsList().forEach(kv -> offerUpdate(kv, false));
if (revNow > seenUpToRev)
listenerExecutor.execute(() -> revisionUpdate(revNow));
}
return iterator();
}
Aggregations