Search in sources :

Example 6 with TxnResponse

use of com.ibm.etcd.api.TxnResponse 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();
}
Also used : EtcdClient(com.ibm.etcd.client.EtcdClient) CompareResult(com.ibm.etcd.api.Compare.CompareResult) LoggerFactory(org.slf4j.LoggerFactory) TimeoutException(java.util.concurrent.TimeoutException) RevisionCompactedException(com.ibm.etcd.client.watch.RevisionCompactedException) StreamObserver(io.grpc.stub.StreamObserver) Compare(com.ibm.etcd.api.Compare) Map(java.util.Map) Status(io.grpc.Status) RangeResponse(com.ibm.etcd.api.RangeResponse) Function(com.google.common.base.Function) CancellationException(java.util.concurrent.CancellationException) ConcurrentHashMap(java.util.concurrent.ConcurrentHashMap) EventType(com.ibm.etcd.client.utils.RangeCache.Listener.EventType) Set(java.util.Set) NavigableSet(java.util.NavigableSet) NavigableMap(java.util.NavigableMap) GuardedBy(javax.annotation.concurrent.GuardedBy) Collectors(java.util.stream.Collectors) RequestOp(com.ibm.etcd.api.RequestOp) ByteString(com.google.protobuf.ByteString) CompareOrBuilder(com.ibm.etcd.api.CompareOrBuilder) List(java.util.List) Stream(java.util.stream.Stream) GrpcClient.waitFor(com.ibm.etcd.client.GrpcClient.waitFor) DeleteRangeResponse(com.ibm.etcd.api.DeleteRangeResponse) RangeRequest(com.ibm.etcd.api.RangeRequest) Event(com.ibm.etcd.api.Event) CopyOnWriteArrayList(java.util.concurrent.CopyOnWriteArrayList) MoreExecutors(com.google.common.util.concurrent.MoreExecutors) WatchUpdate(com.ibm.etcd.client.kv.WatchUpdate) ListenableFuture(com.google.common.util.concurrent.ListenableFuture) Watch(com.ibm.etcd.client.kv.KvClient.Watch) TxnResponse(com.ibm.etcd.api.TxnResponse) Iterators(com.google.common.collect.Iterators) ConcurrentMap(java.util.concurrent.ConcurrentMap) HashSet(java.util.HashSet) DeleteRangeRequest(com.ibm.etcd.api.DeleteRangeRequest) Code(io.grpc.Status.Code) KeyUtils(com.ibm.etcd.client.KeyUtils) PutRequest(com.ibm.etcd.api.PutRequest) Logger(org.slf4j.Logger) Iterator(java.util.Iterator) Executor(java.util.concurrent.Executor) KvClient(com.ibm.etcd.client.kv.KvClient) SerializingExecutor(com.ibm.etcd.client.SerializingExecutor) KeyValue(com.ibm.etcd.api.KeyValue) TxnRequest(com.ibm.etcd.api.TxnRequest) ExecutionException(java.util.concurrent.ExecutionException) TimeUnit(java.util.concurrent.TimeUnit) ConcurrentSkipListMap(java.util.concurrent.ConcurrentSkipListMap) Futures(com.google.common.util.concurrent.Futures) ConcurrentSkipListSet(java.util.concurrent.ConcurrentSkipListSet) Collections(java.util.Collections) CompareTarget(com.ibm.etcd.api.Compare.CompareTarget) KeyValue(com.ibm.etcd.api.KeyValue) ByteString(com.google.protobuf.ByteString) Code(io.grpc.Status.Code) RangeResponse(com.ibm.etcd.api.RangeResponse) DeleteRangeResponse(com.ibm.etcd.api.DeleteRangeResponse) RangeRequest(com.ibm.etcd.api.RangeRequest) DeleteRangeRequest(com.ibm.etcd.api.DeleteRangeRequest) TxnResponse(com.ibm.etcd.api.TxnResponse) ExecutionException(java.util.concurrent.ExecutionException) TimeoutException(java.util.concurrent.TimeoutException)

Aggregations

TxnResponse (com.ibm.etcd.api.TxnResponse)6 ByteString (com.google.protobuf.ByteString)4 KeyValue (com.ibm.etcd.api.KeyValue)4 RangeResponse (com.ibm.etcd.api.RangeResponse)4 Function (com.google.common.base.Function)3 DeleteRangeResponse (com.ibm.etcd.api.DeleteRangeResponse)3 PutRequest (com.ibm.etcd.api.PutRequest)3 RangeRequest (com.ibm.etcd.api.RangeRequest)3 KvClient (com.ibm.etcd.client.kv.KvClient)3 Futures (com.google.common.util.concurrent.Futures)2 ListenableFuture (com.google.common.util.concurrent.ListenableFuture)2 MoreExecutors (com.google.common.util.concurrent.MoreExecutors)2 DeleteRangeRequest (com.ibm.etcd.api.DeleteRangeRequest)2 Event (com.ibm.etcd.api.Event)2 EtcdClient (com.ibm.etcd.client.EtcdClient)2 SerializingExecutor (com.ibm.etcd.client.SerializingExecutor)2 Watch (com.ibm.etcd.client.kv.KvClient.Watch)2 WatchUpdate (com.ibm.etcd.client.kv.WatchUpdate)2 RevisionCompactedException (com.ibm.etcd.client.watch.RevisionCompactedException)2 List (java.util.List)2