ZKAsyncRegistry(Configuration conf) { this.znodePaths = new ZNodePaths(conf); this.zk = new ReadOnlyZKClient(conf); }
@Override public void close() { zk.close(); } }
if (pendingRequests == 0) { LOG.trace("{} to {} inactive for {}ms; closing (Will reconnect when new requests)", getId(), connectString, keepAliveTimeMs); closeZk(); ZooKeeper zk; try { zk = getZk(); } catch (IOException e) { task.connectFailed(e); closeZk(); DoNotRetryIOException error = new DoNotRetryIOException("Client already closed"); Arrays.stream(tasks.toArray(new Task[0])).forEach(t -> t.closed(error));
private <T> CompletableFuture<T> getAndConvert(String path, Converter<T> converter) { CompletableFuture<T> future = new CompletableFuture<>(); zk.get(path).whenComplete((data, error) -> { if (error != null) { future.completeExceptionally(error); return; } try { future.complete(converter.convert(data)); } catch (Exception e) { future.completeExceptionally(e); } }); return future; }
@Override public CompletableFuture<Integer> getCurrentNrHRS() { return zk.exists(znodePaths.rsZNode).thenApply(s -> s != null ? s.getNumChildren() : 0); }
@Override public void close() { if (closed.compareAndSet(false, true)) { LOG.debug("Close zookeeper connection {} to {}", getId(), connectString); tasks.add(CLOSE); } }
public CompletableFuture<Stat> exists(String path) { if (closed.get()) { return failed(new DoNotRetryIOException("Client already closed")); } CompletableFuture<Stat> future = new CompletableFuture<>(); tasks.add(new ZKTask<Stat>(path, future, "exists") { @Override protected void doExec(ZooKeeper zk) { zk.exists(path, false, (rc, path, ctx, stat) -> onComplete(zk, rc, stat, false), null); } }); return future; }
@Test public void testNotCloseZkWhenPending() throws Exception { ZooKeeper mockedZK = mock(ZooKeeper.class); Exchanger<AsyncCallback.DataCallback> exchanger = new Exchanger<>(); doAnswer(i -> { exchanger.exchange(i.getArgument(2)); return null; }).when(mockedZK).getData(anyString(), anyBoolean(), any(AsyncCallback.DataCallback.class), any()); doAnswer(i -> null).when(mockedZK).close(); when(mockedZK.getState()).thenReturn(ZooKeeper.States.CONNECTED); RO_ZK.zookeeper = mockedZK; CompletableFuture<byte[]> future = RO_ZK.get(PATH); AsyncCallback.DataCallback callback = exchanger.exchange(null); // 2 * keep alive time to ensure that we will not close the zk when there are pending requests Thread.sleep(6000); assertNotNull(RO_ZK.zookeeper); verify(mockedZK, never()).close(); callback.processResult(Code.OK.intValue(), PATH, null, DATA, null); assertArrayEquals(DATA, future.get()); // now we will close the idle connection. waitForIdleConnectionClosed(); verify(mockedZK, times(1)).close(); } }
if (pendingRequests == 0) { LOG.trace("{} to {} inactive for {}ms; closing (Will reconnect when new requests)", getId(), connectString, keepAliveTimeMs); closeZk(); ZooKeeper zk; try { zk = getZk(); } catch (IOException e) { task.connectFailed(e); closeZk(); IOException error = new IOException("Client already closed"); Arrays.stream(tasks.toArray(new Task[0])).forEach(t -> t.closed(error));
@Override public CompletableFuture<Integer> getCurrentNrHRS() { return zk.exists(znodePaths.rsZNode).thenApply(s -> s != null ? s.getNumChildren() : 0); }
public ReadOnlyZKClient(Configuration conf) { // We might use a different ZK for client access String clientZkQuorumServers = ZKConfig.getClientZKQuorumServersString(conf); if (clientZkQuorumServers != null) { this.connectString = clientZkQuorumServers; } else { this.connectString = ZKConfig.getZKQuorumServersString(conf); } this.sessionTimeoutMs = conf.getInt(ZK_SESSION_TIMEOUT, DEFAULT_ZK_SESSION_TIMEOUT); this.maxRetries = conf.getInt(RECOVERY_RETRY, DEFAULT_RECOVERY_RETRY); this.retryIntervalMs = conf.getInt(RECOVERY_RETRY_INTERVAL_MILLIS, DEFAULT_RECOVERY_RETRY_INTERVAL_MILLIS); this.keepAliveTimeMs = conf.getInt(KEEPALIVE_MILLIS, DEFAULT_KEEPALIVE_MILLIS); LOG.debug( "Connect {} to {} with session timeout={}ms, retries {}, " + "retry interval {}ms, keepAlive={}ms", getId(), connectString, sessionTimeoutMs, maxRetries, retryIntervalMs, keepAliveTimeMs); Threads.setDaemonThreadRunning(new Thread(this::run), "ReadOnlyZKClient-" + connectString + "@" + getId()); }
public CompletableFuture<byte[]> get(String path) { if (closed.get()) { return failed(new DoNotRetryIOException("Client already closed")); } CompletableFuture<byte[]> future = new CompletableFuture<>(); tasks.add(new ZKTask<byte[]>(path, future, "get") { @Override protected void doExec(ZooKeeper zk) { zk.getData(path, false, (rc, path, ctx, data, stat) -> onComplete(zk, rc, data, true), null); } }); return future; }
@Test public void testNoNode() throws InterruptedException, ExecutionException { String pathNotExists = PATH + "_whatever"; try { RO_ZK.get(pathNotExists).get(); fail("should fail because of " + pathNotExists + " does not exist"); } catch (ExecutionException e) { assertThat(e.getCause(), instanceOf(KeeperException.class)); KeeperException ke = (KeeperException) e.getCause(); assertEquals(Code.NONODE, ke.code()); assertEquals(pathNotExists, ke.getPath()); } // exists will not throw exception. assertNull(RO_ZK.exists(pathNotExists).get()); }
@Test public void testSessionExpire() throws Exception { assertArrayEquals(DATA, RO_ZK.get(PATH).get()); ZooKeeper zk = RO_ZK.zookeeper; long sessionId = zk.getSessionId(); UTIL.getZkCluster().getZooKeeperServers().get(0).closeSession(sessionId); // should not reach keep alive so still the same instance assertSame(zk, RO_ZK.zookeeper); byte[] got = RO_ZK.get(PATH).get(); assertArrayEquals(DATA, got); assertNotNull(RO_ZK.zookeeper); assertNotSame(zk, RO_ZK.zookeeper); assertNotEquals(sessionId, RO_ZK.zookeeper.getSessionId()); }
if (pendingRequests == 0) { LOG.trace("{} to {} inactive for {}ms; closing (Will reconnect when new requests)", getId(), connectString, keepAliveTimeMs); closeZk(); ZooKeeper zk; try { zk = getZk(); } catch (IOException e) { task.connectFailed(e); closeZk(); IOException error = new IOException("Client already closed"); Arrays.stream(tasks.toArray(new Task[0])).forEach(t -> t.closed(error));
@AfterClass public static void tearDown() throws IOException { RO_ZK.close(); UTIL.shutdownMiniZKCluster(); UTIL.cleanupTestDir(); }
@BeforeClass public static void setUp() throws Exception { PORT = UTIL.startMiniZKCluster().getClientPort(); ZooKeeper zk = ZooKeeperHelper.getConnectedZooKeeper("localhost:" + PORT, 10000); DATA = new byte[10]; ThreadLocalRandom.current().nextBytes(DATA); zk.create(PATH, DATA, ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT); for (int i = 0; i < CHILDREN; i++) { zk.create(PATH + "/c" + i, new byte[0], ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT); } zk.close(); Configuration conf = UTIL.getConfiguration(); conf.set(HConstants.ZOOKEEPER_QUORUM, "localhost:" + PORT); conf.setInt(ReadOnlyZKClient.RECOVERY_RETRY, 3); conf.setInt(ReadOnlyZKClient.RECOVERY_RETRY_INTERVAL_MILLIS, 100); conf.setInt(ReadOnlyZKClient.KEEPALIVE_MILLIS, 3000); RO_ZK = new ReadOnlyZKClient(conf); // only connect when necessary assertNull(RO_ZK.zookeeper); }
@Override public CompletableFuture<Integer> getCurrentNrHRS() { return zk.exists(znodePaths.rsZNode).thenApply(s -> s != null ? s.getNumChildren() : 0); }
@Override public void close() { if (closed.compareAndSet(false, true)) { LOG.debug("Close zookeeper connection {} to {}", getId(), connectString); tasks.add(CLOSE); } }