@Override public RouteConfig fetch(final ProgramId serviceId) { Future<RouteConfig> future = routeConfigMap.get(serviceId); if (future == null) { SettableFuture<RouteConfig> settableFuture = SettableFuture.create(); future = routeConfigMap.putIfAbsent(serviceId, settableFuture); if (future == null) { future = getAndWatchData(serviceId, settableFuture, settableFuture, new ZKRouteWatcher(serviceId)); } } return getConfig(serviceId, future); }
@Override public void store(final ProgramId serviceId, final RouteConfig routeConfig) { Supplier<RouteConfig> supplier = Suppliers.ofInstance(routeConfig); SettableFuture<RouteConfig> oldConfigFuture = routeConfigMap.get(serviceId); Future<RouteConfig> future = ZKExtOperations.createOrSet(zkClient, getZKPath(serviceId), supplier, ROUTE_CONFIG_CODEC, 10); try { future.get(ZK_TIMEOUT_SECS, TimeUnit.SECONDS); SettableFuture<RouteConfig> newFuture = SettableFuture.create(); newFuture.set(routeConfig); if (oldConfigFuture != null) { routeConfigMap.replace(serviceId, oldConfigFuture, newFuture); } else { routeConfigMap.putIfAbsent(serviceId, newFuture); } } catch (ExecutionException | InterruptedException | TimeoutException ex) { throw Throwables.propagate(ex); } }
@Test public void testCreateOfConfig() throws Exception { // This test first the config is missing and then created ApplicationId appId = new ApplicationId("n1", "a1"); final ProgramId programId = appId.service("testCreateOfConfig"); try (final RouteStore writeRouteStore = new ZKRouteStore(zkClientService)) { try (final RouteStore readRouteStore = new ZKRouteStore(zkClientService)) { // First it should be no route Assert.assertTrue(readRouteStore.fetch(programId).getRoutes().isEmpty()); // Write a new route config writeRouteStore.store(programId, new RouteConfig(TEST_ROUTE_CONFIG)); // Fetch it again and it should has the changes Tasks.waitFor(TEST_ROUTE_CONFIG, new Callable<Map<String, Integer>>() { @Override public Map<String, Integer> call() throws Exception { return readRouteStore.fetch(programId).getRoutes(); } }, 5L, TimeUnit.SECONDS, 100, TimeUnit.MILLISECONDS); } } }
@Test public void testChangeConfig() throws Exception { ApplicationId appId = new ApplicationId("n1", "a1"); final ProgramId s1 = appId.service("testChangeConfig"); // Create two RouteStore, one for writing, one for reading try (RouteStore writingRouteStore = new ZKRouteStore(zkClientService)) { try (final RouteStore readingRouteStore = new ZKRouteStore(zkClientService)) { writingRouteStore.store(s1, new RouteConfig(TEST_ROUTE_CONFIG)); Assert.assertEquals(TEST_ROUTE_CONFIG, readingRouteStore.fetch(s1).getRoutes()); writingRouteStore.store(s1, new RouteConfig(TEST_ROUTE_CONFIG2)); Tasks.waitFor(TEST_ROUTE_CONFIG2, new Callable<Map<String, Integer>>() { @Override public Map<String, Integer> call() throws Exception { return readingRouteStore.fetch(s1).getRoutes(); } }, 5, TimeUnit.SECONDS, 100, TimeUnit.MILLISECONDS); } } } }
@Override public RouteConfig fetch(final ProgramId serviceId) { Future<RouteConfig> future = routeConfigMap.get(serviceId); if (future == null) { SettableFuture<RouteConfig> settableFuture = SettableFuture.create(); future = routeConfigMap.putIfAbsent(serviceId, settableFuture); if (future == null) { future = getAndWatchData(serviceId, settableFuture, settableFuture, new ZKRouteWatcher(serviceId)); } } return getConfig(serviceId, future); }
@Override public void store(final ProgramId serviceId, final RouteConfig routeConfig) { Supplier<RouteConfig> supplier = Suppliers.ofInstance(routeConfig); SettableFuture<RouteConfig> oldConfigFuture = routeConfigMap.get(serviceId); Future<RouteConfig> future = ZKExtOperations.createOrSet(zkClient, getZKPath(serviceId), supplier, ROUTE_CONFIG_CODEC, 10); try { future.get(ZK_TIMEOUT_SECS, TimeUnit.SECONDS); SettableFuture<RouteConfig> newFuture = SettableFuture.create(); newFuture.set(routeConfig); if (oldConfigFuture != null) { routeConfigMap.replace(serviceId, oldConfigFuture, newFuture); } else { routeConfigMap.putIfAbsent(serviceId, newFuture); } } catch (ExecutionException | InterruptedException | TimeoutException ex) { throw Throwables.propagate(ex); } }
@Test public void testStore() throws Exception { ApplicationId appId = new ApplicationId("n1", "a1"); final ProgramId s1 = appId.service("testStore"); try (final RouteStore routeStore = new ZKRouteStore(zkClientService)) { routeStore.store(s1, new RouteConfig(TEST_ROUTE_CONFIG)); Assert.assertEquals(TEST_ROUTE_CONFIG, routeStore.fetch(s1).getRoutes()); routeStore.delete(s1); Tasks.waitFor(true, new Callable<Boolean>() { @Override public Boolean call() throws Exception { return routeStore.fetch(s1).getRoutes().isEmpty(); } }, 5L, TimeUnit.SECONDS, 100, TimeUnit.MILLISECONDS); } }
@Override public void delete(final ProgramId serviceId) throws NotFoundException { OperationFuture<String> future = zkClient.delete(getZKPath(serviceId)); SettableFuture<RouteConfig> oldConfigFuture = routeConfigMap.get(serviceId); try { future.get(ZK_TIMEOUT_SECS, TimeUnit.SECONDS); routeConfigMap.remove(serviceId, oldConfigFuture); } catch (ExecutionException | InterruptedException | TimeoutException ex) { if (ex.getCause() instanceof KeeperException.NoNodeException) { throw new NotFoundException(String.format("Route Config for Service %s was not found.", serviceId)); } throw Throwables.propagate(ex); } }
@Test public void testAbsenceOfConfig() throws Exception { ApplicationId appId = new ApplicationId("n1", "a1"); final ProgramId programId = appId.service("testAbsenceOfConfig"); try (final RouteStore routeStore = new ZKRouteStore(zkClientService)) { Assert.assertNotNull(routeStore.fetch(programId)); Assert.assertTrue(routeStore.fetch(programId).getRoutes().isEmpty()); routeStore.store(programId, new RouteConfig(TEST_ROUTE_CONFIG)); Tasks.waitFor(false, new Callable<Boolean>() { @Override public Boolean call() throws Exception { return routeStore.fetch(programId).getRoutes().isEmpty(); } }, 5, TimeUnit.SECONDS); Assert.assertEquals(TEST_ROUTE_CONFIG, routeStore.fetch(programId).getRoutes()); } }
@Override public void delete(final ProgramId serviceId) throws NotFoundException { OperationFuture<String> future = zkClient.delete(getZKPath(serviceId)); SettableFuture<RouteConfig> oldConfigFuture = routeConfigMap.get(serviceId); try { future.get(ZK_TIMEOUT_SECS, TimeUnit.SECONDS); routeConfigMap.remove(serviceId, oldConfigFuture); } catch (ExecutionException | InterruptedException | TimeoutException ex) { if (ex.getCause() instanceof KeeperException.NoNodeException) { throw new NotFoundException(String.format("Route Config for Service %s was not found.", serviceId)); } throw Throwables.propagate(ex); } }
final SettableFuture<RouteConfig> oldSettableFuture, final Watcher watcher) { OperationFuture<NodeData> future = zkClient.getData(getZKPath(serviceId), watcher); Futures.addCallback(future, new FutureCallback<NodeData>() { @Override
final SettableFuture<RouteConfig> oldSettableFuture, final Watcher watcher) { OperationFuture<NodeData> future = zkClient.getData(getZKPath(serviceId), watcher); Futures.addCallback(future, new FutureCallback<NodeData>() { @Override
private void existsAndWatch(final ProgramId serviceId, final SettableFuture<RouteConfig> oldSettableFuture) { Futures.addCallback(zkClient.exists(getZKPath(serviceId), new Watcher() { @Override public void process(WatchedEvent event) { // If service name doesn't exist in the map, then don't rewatch it. if (!routeConfigMap.containsKey(serviceId)) { return; } if (event.getType() == Event.EventType.NodeCreated) { getAndWatchData(serviceId, SettableFuture.<RouteConfig>create(), oldSettableFuture, new ZKRouteWatcher(serviceId)); } } }), new FutureCallback<Stat>() { @Override public void onSuccess(@Nullable Stat result) { if (result != null) { getAndWatchData(serviceId, SettableFuture.<RouteConfig>create(), oldSettableFuture, new ZKRouteWatcher(serviceId)); } } @Override public void onFailure(Throwable t) { routeConfigMap.remove(serviceId); LOG.debug("Failed to check exists for property data for {}", serviceId, t); } }); }
private void existsAndWatch(final ProgramId serviceId, final SettableFuture<RouteConfig> oldSettableFuture) { Futures.addCallback(zkClient.exists(getZKPath(serviceId), new Watcher() { @Override public void process(WatchedEvent event) { // If service name doesn't exist in the map, then don't rewatch it. if (!routeConfigMap.containsKey(serviceId)) { return; } if (event.getType() == Event.EventType.NodeCreated) { getAndWatchData(serviceId, SettableFuture.<RouteConfig>create(), oldSettableFuture, new ZKRouteWatcher(serviceId)); } } }), new FutureCallback<Stat>() { @Override public void onSuccess(@Nullable Stat result) { if (result != null) { getAndWatchData(serviceId, SettableFuture.<RouteConfig>create(), oldSettableFuture, new ZKRouteWatcher(serviceId)); } } @Override public void onFailure(Throwable t) { routeConfigMap.remove(serviceId); LOG.debug("Failed to check exists for property data for {}", serviceId, t); } }); }