Search in sources :

Example 1 with WatchUpdate

use of com.ibm.etcd.client.kv.WatchUpdate in project etcd-java by IBM.

the class WatchTest method getNextSkipEmpty.

static WatchUpdate getNextSkipEmpty(WatchIterator wi) {
    assertTrue(wi.hasNext());
    WatchUpdate wu = wi.next();
    if (wu.getEvents().isEmpty()) {
        assertTrue(wi.hasNext());
        wu = wi.next();
    }
    return wu;
}
Also used : WatchUpdate(com.ibm.etcd.client.kv.WatchUpdate)

Example 2 with WatchUpdate

use of com.ibm.etcd.client.kv.WatchUpdate in project etcd-java by IBM.

the class WatchTest method testWatch.

@Test
public void testWatch() throws Exception {
    proxy.start();
    try (KvStoreClient directClient = EtcdClient.forEndpoint("localhost", 2379).withPlainText().build();
        KvStoreClient client = EtcdClient.forEndpoint("localhost", 2390).withPlainText().build()) {
        KvClient kvc = client.getKvClient();
        long start = System.currentTimeMillis();
        final BlockingQueue<Object> watchEvents = new LinkedBlockingQueue<>();
        final Object COMPLETED = new Object();
        final StreamObserver<WatchUpdate> observer = new StreamObserver<WatchUpdate>() {

            @Override
            public void onNext(WatchUpdate value) {
                System.out.println(t(start) + "watch event: " + value);
                watchEvents.add(value);
            }

            @Override
            public void onError(Throwable t) {
                System.out.println(t(start) + "watch error: " + t);
                watchEvents.add(t);
            }

            @Override
            public void onCompleted() {
                System.out.println(t(start) + "watch completed");
                watchEvents.add(COMPLETED);
            }
        };
        Watch watch = kvc.watch(bs("/watchtest")).asPrefix().start(observer);
        // assertFalse(watch.isDone());
        // test blocking watch at the same time
        WatchIterator watchIterator = kvc.watch(bs("/watchtest")).asPrefix().start();
        assertTrue(watch.get(1, TimeUnit.SECONDS));
        kvc.put(bs("/watchtest/a"), bs("a value")).sync();
        directClient.getKvClient().put(bs("/watchtest/b"), bs("b value")).sync();
        WatchUpdate wu = getNextSkipEmpty(watchEvents);
        assertNotNull(wu);
        assertEquals("event: " + wu, 1, wu.getEvents().size());
        assertEquals(EventType.PUT, wu.getEvents().get(0).getType());
        assertEquals(bs("a value"), wu.getEvents().get(0).getKv().getValue());
        assertEquals(bs("/watchtest/a"), wu.getEvents().get(0).getKv().getKey());
        WatchUpdate wu2 = getNextSkipEmpty(watchIterator);
        assertEquals(EventType.PUT, wu2.getEvents().get(0).getType());
        assertEquals(bs("a value"), wu2.getEvents().get(0).getKv().getValue());
        assertEquals(bs("/watchtest/a"), wu2.getEvents().get(0).getKv().getKey());
        watchEvents.poll(500, TimeUnit.MILLISECONDS);
        watch.close();
        assertEquals(COMPLETED, watchEvents.poll(500, TimeUnit.MILLISECONDS));
        kvc.put(bs("/watchtest/c"), bs("c value")).sync();
        assertNull(watchEvents.poll(500, TimeUnit.MILLISECONDS));
        assertTrue(watchIterator.hasNext());
        assertTrue(watchIterator.hasNext());
        assertEquals(bs("b value"), watchIterator.next().getEvents().get(0).getKv().getValue());
        assertEquals(EventType.PUT, watchIterator.next().getEvents().get(0).getType());
        // fresh new watch
        watch = kvc.watch(ByteString.copyFromUtf8("/watchtest")).asPrefix().start(observer);
        assertTrue(watch.get(1, TimeUnit.SECONDS));
        kvc.batch().put(kvc.put(bs("/watchtest/d"), bs("d value")).asRequest()).delete(kvc.delete(bs("/watchtest/a")).asRequest()).sync();
        wu = getNextSkipEmpty(watchEvents);
        assertEquals(2, wu.getEvents().size());
        assertTrue(wu.getEvents().stream().anyMatch(e -> e.getType() == EventType.DELETE));
        assertTrue(wu.getEvents().stream().anyMatch(e -> e.getType() == EventType.PUT));
        // kill path to server
        proxy.kill();
        Thread.sleep(1000L);
        // while disconnected, put a new key
        directClient.getKvClient().put(bs("/watchtest/e"), bs("e value")).sync();
        Thread.sleep(1000L);
        // reinstate path to server
        proxy.start();
        // watch should be unaffected - next event seen should be the missed one
        wu = (WatchUpdate) watchEvents.poll(3000L, TimeUnit.MILLISECONDS);
        assertEquals(bs("/watchtest/e"), wu.getEvents().get(0).getKv().getKey());
        watch.close();
        // (earlier batch update)
        assertEquals(2, watchIterator.next().getEvents().size());
        assertEquals(bs("/watchtest/e"), watchIterator.next().getEvents().get(0).getKv().getKey());
        watchIterator.close();
        assertNull(watchIterator.next().getHeader());
        assertFalse(watchIterator.hasNext());
        try {
            watchIterator.next();
            fail("should throw NSEE here");
        } catch (NoSuchElementException nsee) {
        }
    } finally {
        proxy.kill();
    }
}
Also used : StreamObserver(io.grpc.stub.StreamObserver) AfterClass(org.junit.AfterClass) WatchUpdate(com.ibm.etcd.client.kv.WatchUpdate) BeforeClass(org.junit.BeforeClass) Watch(com.ibm.etcd.client.kv.KvClient.Watch) ConcurrentHashMap(java.util.concurrent.ConcurrentHashMap) KvClient(com.ibm.etcd.client.kv.KvClient) BlockingQueue(java.util.concurrent.BlockingQueue) Test(org.junit.Test) WatchIterator(com.ibm.etcd.client.kv.KvClient.WatchIterator) LinkedBlockingQueue(java.util.concurrent.LinkedBlockingQueue) AtomicReference(java.util.concurrent.atomic.AtomicReference) WatchCreateException(com.ibm.etcd.client.watch.WatchCreateException) ExecutionException(java.util.concurrent.ExecutionException) TimeUnit(java.util.concurrent.TimeUnit) ByteString(com.google.protobuf.ByteString) StreamObserver(io.grpc.stub.StreamObserver) Map(java.util.Map) Phaser(java.util.concurrent.Phaser) EventType(com.ibm.etcd.api.Event.EventType) KvTest.bs(com.ibm.etcd.client.KvTest.bs) Assert(org.junit.Assert) NoSuchElementException(java.util.NoSuchElementException) PutResponse(com.ibm.etcd.api.PutResponse) KvTest.t(com.ibm.etcd.client.KvTest.t) WatchUpdate(com.ibm.etcd.client.kv.WatchUpdate) LinkedBlockingQueue(java.util.concurrent.LinkedBlockingQueue) Watch(com.ibm.etcd.client.kv.KvClient.Watch) KvClient(com.ibm.etcd.client.kv.KvClient) NoSuchElementException(java.util.NoSuchElementException) WatchIterator(com.ibm.etcd.client.kv.KvClient.WatchIterator) Test(org.junit.Test)

Example 3 with WatchUpdate

use of com.ibm.etcd.client.kv.WatchUpdate in project etcd-java by IBM.

the class RangeCache method fullRefreshCache.

// internal method - should not be called while watch is active
protected ListenableFuture<Boolean> fullRefreshCache() {
    ListenableFuture<List<RangeResponse>> rrfut;
    long seenUpTo = seenUpToRev;
    boolean firstTime = (seenUpTo == 0L);
    if (firstTime || entries.size() <= 20) {
        // TODO *maybe* chunking (for large caches)
        ListenableFuture<RangeResponse> rrf = kvClient.get(fromKey).rangeEnd(toKey).backoffRetry(() -> !closed).timeout(300_000L).async();
        rrfut = Futures.transform(rrf, (Function<RangeResponse, List<RangeResponse>>) rr -> Collections.singletonList(rr));
    } else {
        // in case the local cache is large, reduce data transfer by requesting
        // just keys, and full key+value only for those modified since seenUpToRev
        RangeRequest.Builder rangeReqBld = RangeRequest.newBuilder().setKey(fromKey).setRangeEnd(toKey);
        RangeRequest newModsReq = rangeReqBld.setMinModRevision(seenUpTo + 1).build();
        RangeRequest otherKeysReq = rangeReqBld.clearMinModRevision().setMaxModRevision(seenUpTo).setKeysOnly(true).build();
        ListenableFuture<TxnResponse> trf = kvClient.batch().get(newModsReq).get(otherKeysReq).backoffRetry(() -> !closed).timeout(300_000L).async();
        rrfut = Futures.transform(trf, (Function<TxnResponse, List<RangeResponse>>) tr -> tr.getResponsesList().stream().map(r -> r.getResponseRange()).collect(Collectors.toList()));
    }
    return Futures.transformAsync(rrfut, rrs -> {
        if (closed)
            throw new CancellationException();
        Set<ByteString> snapshot = firstTime ? null : new HashSet<>();
        RangeResponse toUpdate = rrs.get(0);
        if (toUpdate.getKvsCount() > 0)
            for (KeyValue kv : toUpdate.getKvsList()) {
                if (!firstTime)
                    snapshot.add(kv.getKey());
                offerUpdate(kv, true);
            }
        long snapshotRev = toUpdate.getHeader().getRevision();
        if (firstTime)
            notifyListeners(EventType.INITIALIZED, null, true);
        else {
            if (rrs.size() > 1)
                for (KeyValue kv : rrs.get(1).getKvsList()) {
                    snapshot.add(kv.getKey());
                }
            // prune deleted entries
            KeyValue.Builder kvBld = null;
            for (ByteString key : entries.keySet()) if (!snapshot.contains(key)) {
                if (kvBld == null)
                    kvBld = KeyValue.newBuilder().setVersion(0L).setModRevision(snapshotRev);
                offerUpdate(kvBld.setKey(key).build(), true);
            }
        }
        revisionUpdate(snapshotRev);
        Watch newWatch = // .prevKv() //TODO TBD
        kvClient.watch(fromKey).rangeEnd(toKey).progressNotify().startRevision(snapshotRev + 1).executor(listenerExecutor).start(new StreamObserver<WatchUpdate>() {

            @Override
            public void onNext(WatchUpdate update) {
                List<Event> events = update.getEvents();
                int eventCount = events != null ? events.size() : 0;
                if (eventCount > 0)
                    for (Event event : events) {
                        KeyValue kv = event.getKv();
                        // event.getPrevKv(); //TBD
                        switch(event.getType()) {
                            case DELETE:
                                if (kv.getVersion() != 0L)
                                    kv = KeyValue.newBuilder(kv).setVersion(0L).clearValue().build();
                            // fall-thru
                            case PUT:
                                offerUpdate(kv, true);
                                break;
                            case UNRECOGNIZED:
                            default:
                                logger.warn("Unrecognized event for key " + kv.getKey().toStringUtf8());
                                break;
                        }
                    }
                revisionUpdate(eventCount == 0 ? update.getHeader().getRevision() - 1L : events.get(eventCount - 1).getKv().getModRevision());
            }

            @Override
            public void onCompleted() {
                // should only happen after external close()
                if (!closed) {
                    if (!client.isClosed()) {
                        logger.error("Watch completed unexpectedly (not closed)");
                    }
                    close();
                }
            }

            @Override
            public void onError(Throwable t) {
                logger.error("Watch failed with exception ", t);
                if (t instanceof RevisionCompactedException)
                    synchronized (RangeCache.this) {
                        // fail if happens during start, otherwise refresh
                        if (!closed && startFuture != null && startFuture.isDone()) {
                            // will renew watch
                            startFuture = fullRefreshCache();
                        }
                    }
            }
        });
        synchronized (this) {
            if (closed)
                throw new CancellationException();
            return watch = newWatch;
        }
    }, listenerExecutor);
}
Also used : KeyValue(com.ibm.etcd.api.KeyValue) ByteString(com.google.protobuf.ByteString) WatchUpdate(com.ibm.etcd.client.kv.WatchUpdate) Function(com.google.common.base.Function) RangeResponse(com.ibm.etcd.api.RangeResponse) DeleteRangeResponse(com.ibm.etcd.api.DeleteRangeResponse) RevisionCompactedException(com.ibm.etcd.client.watch.RevisionCompactedException) CancellationException(java.util.concurrent.CancellationException) RangeRequest(com.ibm.etcd.api.RangeRequest) DeleteRangeRequest(com.ibm.etcd.api.DeleteRangeRequest) Watch(com.ibm.etcd.client.kv.KvClient.Watch) Event(com.ibm.etcd.api.Event) List(java.util.List) CopyOnWriteArrayList(java.util.concurrent.CopyOnWriteArrayList) TxnResponse(com.ibm.etcd.api.TxnResponse)

Example 4 with WatchUpdate

use of com.ibm.etcd.client.kv.WatchUpdate in project etcd-java by IBM.

the class EtcdWatchIterator method hasNext.

@Override
public boolean hasNext() {
    if (complete == null) {
        WatchUpdate wu = updateQueue.peek();
        if (// includes null
        !(wu instanceof CompletedUpdate) || ((CompletedUpdate) wu).error != null) {
            return true;
        }
        updateQueue.remove();
        complete = (CompletedUpdate) wu;
    }
    return false;
}
Also used : WatchUpdate(com.ibm.etcd.client.kv.WatchUpdate)

Example 5 with WatchUpdate

use of com.ibm.etcd.client.kv.WatchUpdate in project etcd-java by IBM.

the class WatchTest method testCreateFail.

@Test
public void testCreateFail() throws Exception {
    KvStoreClient client = EtcdClient.forEndpoint("localhost", 2379).withPlainText().build();
    try {
        KvClient kvc = client.getKvClient();
        // range end before start => should fail
        Watch watch2 = kvc.watch(ByteString.copyFromUtf8("/watchtest2")).rangeEnd(ByteString.copyFromUtf8("/watchtest1")).startRevision(-5000L).start((ListenerObserver<WatchUpdate>) (c, v, t) -> {
        });
        try {
            watch2.get(1000, TimeUnit.SECONDS);
            fail("watch future should fail");
        } catch (ExecutionException e) {
            System.out.println("watch creation failed with exception: " + e);
            assertTrue(e.getCause() instanceof WatchCreateException);
        }
    } finally {
        client.close();
    }
}
Also used : AfterClass(org.junit.AfterClass) WatchUpdate(com.ibm.etcd.client.kv.WatchUpdate) BeforeClass(org.junit.BeforeClass) Watch(com.ibm.etcd.client.kv.KvClient.Watch) ConcurrentHashMap(java.util.concurrent.ConcurrentHashMap) KvClient(com.ibm.etcd.client.kv.KvClient) BlockingQueue(java.util.concurrent.BlockingQueue) Test(org.junit.Test) WatchIterator(com.ibm.etcd.client.kv.KvClient.WatchIterator) LinkedBlockingQueue(java.util.concurrent.LinkedBlockingQueue) AtomicReference(java.util.concurrent.atomic.AtomicReference) WatchCreateException(com.ibm.etcd.client.watch.WatchCreateException) ExecutionException(java.util.concurrent.ExecutionException) TimeUnit(java.util.concurrent.TimeUnit) ByteString(com.google.protobuf.ByteString) StreamObserver(io.grpc.stub.StreamObserver) Map(java.util.Map) Phaser(java.util.concurrent.Phaser) EventType(com.ibm.etcd.api.Event.EventType) KvTest.bs(com.ibm.etcd.client.KvTest.bs) Assert(org.junit.Assert) NoSuchElementException(java.util.NoSuchElementException) PutResponse(com.ibm.etcd.api.PutResponse) KvTest.t(com.ibm.etcd.client.KvTest.t) Watch(com.ibm.etcd.client.kv.KvClient.Watch) WatchUpdate(com.ibm.etcd.client.kv.WatchUpdate) KvClient(com.ibm.etcd.client.kv.KvClient) ExecutionException(java.util.concurrent.ExecutionException) WatchCreateException(com.ibm.etcd.client.watch.WatchCreateException) Test(org.junit.Test)

Aggregations

WatchUpdate (com.ibm.etcd.client.kv.WatchUpdate)5 ByteString (com.google.protobuf.ByteString)3 Watch (com.ibm.etcd.client.kv.KvClient.Watch)3 EventType (com.ibm.etcd.api.Event.EventType)2 PutResponse (com.ibm.etcd.api.PutResponse)2 KvTest.bs (com.ibm.etcd.client.KvTest.bs)2 KvTest.t (com.ibm.etcd.client.KvTest.t)2 KvClient (com.ibm.etcd.client.kv.KvClient)2 WatchIterator (com.ibm.etcd.client.kv.KvClient.WatchIterator)2 WatchCreateException (com.ibm.etcd.client.watch.WatchCreateException)2 StreamObserver (io.grpc.stub.StreamObserver)2 Map (java.util.Map)2 NoSuchElementException (java.util.NoSuchElementException)2 BlockingQueue (java.util.concurrent.BlockingQueue)2 ConcurrentHashMap (java.util.concurrent.ConcurrentHashMap)2 ExecutionException (java.util.concurrent.ExecutionException)2 LinkedBlockingQueue (java.util.concurrent.LinkedBlockingQueue)2 Phaser (java.util.concurrent.Phaser)2 TimeUnit (java.util.concurrent.TimeUnit)2 AtomicReference (java.util.concurrent.atomic.AtomicReference)2