use of org.apache.bookkeeper.versioning.LongVersion in project bookkeeper by apache.
the class TestZkRegistrationClient method testWatchBookiesSuccess.
@SuppressWarnings("unchecked")
private void testWatchBookiesSuccess(boolean isWritable) throws Exception {
//
// 1. test watch bookies with a listener
//
LinkedBlockingQueue<Versioned<Set<BookieSocketAddress>>> updates = spy(new LinkedBlockingQueue<>());
RegistrationListener listener = bookies -> {
try {
updates.put(bookies);
} catch (InterruptedException e) {
log.warn("Interrupted on enqueue bookie updates", e);
}
};
Set<BookieSocketAddress> addresses = prepareNBookies(10);
List<String> children = Lists.newArrayList();
for (BookieSocketAddress address : addresses) {
children.add(address.toString());
}
Stat stat = mock(Stat.class);
when(stat.getCversion()).thenReturn(1234);
mockGetChildren(isWritable ? regPath : regReadonlyPath, true, Code.OK.intValue(), children, stat);
if (isWritable) {
result(zkRegistrationClient.watchWritableBookies(listener));
} else {
result(zkRegistrationClient.watchReadOnlyBookies(listener));
}
Versioned<Set<BookieSocketAddress>> update = updates.take();
verify(updates, times(1)).put(any(Versioned.class));
assertEquals(new LongVersion(1234), update.getVersion());
assertSetEquals(addresses, update.getValue());
verify(mockZk, times(1)).getChildren(anyString(), any(Watcher.class), any(Children2Callback.class), any());
//
// 2. test watch bookies with a second listener. the second listener returns cached bookies
// without calling `getChildren` again
//
// register another listener
LinkedBlockingQueue<Versioned<Set<BookieSocketAddress>>> secondUpdates = spy(new LinkedBlockingQueue<>());
RegistrationListener secondListener = bookies -> {
try {
secondUpdates.put(bookies);
} catch (InterruptedException e) {
log.warn("Interrupted on enqueue bookie updates", e);
}
};
if (isWritable) {
result(zkRegistrationClient.watchWritableBookies(secondListener));
} else {
result(zkRegistrationClient.watchReadOnlyBookies(secondListener));
}
Versioned<Set<BookieSocketAddress>> secondListenerUpdate = secondUpdates.take();
// first listener will not be notified with any update
verify(updates, times(1)).put(any(Versioned.class));
// second listener will receive same update as the first listener received before
verify(secondUpdates, times(1)).put(any(Versioned.class));
assertSame(update.getVersion(), secondListenerUpdate.getVersion());
assertSame(update.getValue(), secondListenerUpdate.getValue());
// the second listener will return the cached value without issuing another getChildren call
verify(mockZk, times(1)).getChildren(anyString(), any(Watcher.class), any(Children2Callback.class), any());
//
// 3. simulate session expire, it will trigger watcher to refetch bookies again.
// but since there is no updates on bookies, the registered listeners will not be notified.
//
notifyWatchedEvent(EventType.None, KeeperState.Expired, isWritable ? regPath : regReadonlyPath);
// if session expires, the watcher task will get into backoff state
controller.advance(Duration.ofMillis(ZK_CONNECT_BACKOFF_MS));
// the same updates returns, the getChildren calls increase to 2
// but since there is no updates, so no notification is sent.
verify(mockZk, times(2)).getChildren(anyString(), any(Watcher.class), any(Children2Callback.class), any());
assertNull(updates.poll());
// both listener and secondListener will not receive any old update
verify(updates, times(1)).put(any(Versioned.class));
verify(secondUpdates, times(1)).put(any(Versioned.class));
//
// 4. notify with new bookies. both listeners will be notified with new bookies.
//
Set<BookieSocketAddress> newAddresses = prepareNBookies(20);
List<String> newChildren = Lists.newArrayList();
for (BookieSocketAddress address : newAddresses) {
newChildren.add(address.toString());
}
Stat newStat = mock(Stat.class);
when(newStat.getCversion()).thenReturn(1235);
mockGetChildren(isWritable ? regPath : regReadonlyPath, true, Code.OK.intValue(), newChildren, newStat);
// trigger watcher
notifyWatchedEvent(EventType.NodeChildrenChanged, KeeperState.SyncConnected, isWritable ? regPath : regReadonlyPath);
update = updates.take();
assertEquals(new LongVersion(1235), update.getVersion());
assertSetEquals(newAddresses, update.getValue());
secondListenerUpdate = secondUpdates.take();
assertSame(update.getVersion(), secondListenerUpdate.getVersion());
assertSame(update.getValue(), secondListenerUpdate.getValue());
verify(mockZk, times(3)).getChildren(anyString(), any(Watcher.class), any(Children2Callback.class), any());
verify(updates, times(2)).put(any(Versioned.class));
verify(secondUpdates, times(2)).put(any(Versioned.class));
//
// 5. unwatch the second listener and notify with new bookies again. only first listener will
// be notified with new bookies.
//
newAddresses = prepareNBookies(25);
newChildren.clear();
newChildren = Lists.newArrayList();
for (BookieSocketAddress address : newAddresses) {
newChildren.add(address.toString());
}
newStat = mock(Stat.class);
when(newStat.getCversion()).thenReturn(1236);
mockGetChildren(isWritable ? regPath : regReadonlyPath, true, Code.OK.intValue(), newChildren, newStat);
if (isWritable) {
assertEquals(2, zkRegistrationClient.getWatchWritableBookiesTask().getNumListeners());
zkRegistrationClient.unwatchWritableBookies(secondListener);
assertEquals(1, zkRegistrationClient.getWatchWritableBookiesTask().getNumListeners());
} else {
assertEquals(2, zkRegistrationClient.getWatchReadOnlyBookiesTask().getNumListeners());
zkRegistrationClient.unwatchReadOnlyBookies(secondListener);
assertEquals(1, zkRegistrationClient.getWatchReadOnlyBookiesTask().getNumListeners());
}
// the watch task will not be closed since there is still a listener
verify(mockZk, times(0)).removeWatches(eq(isWritable ? regPath : regReadonlyPath), same(isWritable ? zkRegistrationClient.getWatchWritableBookiesTask() : zkRegistrationClient.getWatchReadOnlyBookiesTask()), eq(WatcherType.Children), eq(true), any(VoidCallback.class), any());
// trigger watcher
notifyWatchedEvent(EventType.NodeChildrenChanged, KeeperState.SyncConnected, isWritable ? regPath : regReadonlyPath);
update = updates.take();
assertEquals(new LongVersion(1236), update.getVersion());
assertSetEquals(newAddresses, update.getValue());
secondListenerUpdate = secondUpdates.poll();
assertNull(secondListenerUpdate);
verify(mockZk, times(4)).getChildren(anyString(), any(Watcher.class), any(Children2Callback.class), any());
verify(updates, times(3)).put(any(Versioned.class));
verify(secondUpdates, times(2)).put(any(Versioned.class));
//
// 6. unwatch the first listener. the watch task will be closed and zk watcher will be removed.
//
//
WatchTask expectedWatcher;
if (isWritable) {
expectedWatcher = zkRegistrationClient.getWatchWritableBookiesTask();
assertFalse(expectedWatcher.isClosed());
zkRegistrationClient.unwatchWritableBookies(listener);
assertNull(zkRegistrationClient.getWatchWritableBookiesTask());
} else {
expectedWatcher = zkRegistrationClient.getWatchReadOnlyBookiesTask();
assertFalse(expectedWatcher.isClosed());
zkRegistrationClient.unwatchReadOnlyBookies(listener);
assertNull(zkRegistrationClient.getWatchReadOnlyBookiesTask());
}
// the watch task will not be closed since there is still a listener
assertTrue(expectedWatcher.isClosed());
verify(mockZk, times(1)).removeWatches(eq(isWritable ? regPath : regReadonlyPath), same(expectedWatcher), eq(WatcherType.Children), eq(true), any(VoidCallback.class), any());
}
use of org.apache.bookkeeper.versioning.LongVersion in project bookkeeper by apache.
the class TestZkRegistrationClient method testGetWritableBookies.
@Test
public void testGetWritableBookies() throws Exception {
Set<BookieSocketAddress> addresses = prepareNBookies(10);
List<String> children = Lists.newArrayList();
for (BookieSocketAddress address : addresses) {
children.add(address.toString());
}
Stat stat = mock(Stat.class);
when(stat.getCversion()).thenReturn(1234);
mockGetChildren(regPath, false, Code.OK.intValue(), children, stat);
Versioned<Set<BookieSocketAddress>> result = result(zkRegistrationClient.getWritableBookies());
assertEquals(new LongVersion(1234), result.getVersion());
assertSetEquals(addresses, result.getValue());
}
use of org.apache.bookkeeper.versioning.LongVersion in project bookkeeper by apache.
the class AbstractZkLedgerManagerTest method testLedgerMetadataListener.
@Test
public void testLedgerMetadataListener() throws Exception {
long ledgerId = System.currentTimeMillis();
String ledgerStr = String.valueOf(ledgerId);
LinkedBlockingQueue<LedgerMetadata> changes = new LinkedBlockingQueue<>();
LedgerMetadataListener listener = (ledgerId1, metadata) -> changes.add(metadata);
metadata.setVersion(new LongVersion(1234L));
Stat stat = mock(Stat.class);
when(stat.getVersion()).thenReturn(1234);
when(stat.getCtime()).thenReturn(metadata.getCtime());
mockZkGetData(ledgerStr, true, KeeperException.Code.OK.intValue(), metadata.serialize(), stat);
ledgerManager.registerLedgerMetadataListener(ledgerId, listener);
// the listener will be notified with first get
LedgerMetadata change1 = changes.take();
assertEquals(metadata, change1);
verify(mockZk, times(1)).getData(anyString(), any(Watcher.class), any(DataCallback.class), any());
// the watcher is registered for receiving watched event
assertTrue(watchers.containsKey(ledgerStr));
Set<Watcher> watcherSet1 = watchers.get(ledgerStr);
assertEquals(1, watcherSet1.size());
Watcher registeredWatcher1 = watcherSet1.stream().findFirst().get();
// mock get data to return an updated metadata
metadata.setVersion(new LongVersion(1235L));
when(stat.getVersion()).thenReturn(1235);
mockZkGetData(ledgerStr, true, KeeperException.Code.OK.intValue(), metadata.serialize(), stat);
// notify the watcher event
notifyWatchedEvent(EventType.NodeDataChanged, KeeperState.SyncConnected, ledgerStr);
// the listener should receive an updated metadata
LedgerMetadata change2 = changes.take();
assertEquals(metadata, change2);
verify(mockZk, times(2)).getData(anyString(), any(Watcher.class), any(DataCallback.class), any());
// after the listener receive an updated metadata, a new watcher should be registered
// for subsequent changes again.
assertTrue(watchers.containsKey(ledgerStr));
Set<Watcher> watcherSet2 = watchers.get(ledgerStr);
assertEquals(1, watcherSet2.size());
Watcher registeredWatcher2 = watcherSet2.stream().findFirst().get();
// zookeeper watchers are same, since there is only one giant watcher per ledger manager.
assertSame(registeredWatcher1, registeredWatcher2);
// verify scheduler
verify(scheduler, times(2)).submit(any(Runnable.class));
verify(scheduler, times(0)).schedule(any(Runnable.class), anyLong(), any(TimeUnit.class));
}
use of org.apache.bookkeeper.versioning.LongVersion in project bookkeeper by apache.
the class AbstractZkLedgerManagerTest method testRemoveLedgerMetadataException.
@Test
public void testRemoveLedgerMetadataException() throws Exception {
long ledgerId = System.currentTimeMillis();
String ledgerStr = String.valueOf(ledgerId);
LongVersion version = new LongVersion(1234L);
mockZkDelete(ledgerStr, (int) version.getLongVersion(), KeeperException.Code.CONNECTIONLOSS.intValue());
GenericCallbackFuture<Void> callbackFuture = new GenericCallbackFuture<>();
ledgerManager.removeLedgerMetadata(ledgerId, version, callbackFuture);
try {
result(callbackFuture);
fail("Should fail to remove metadata if no such ledger exists");
} catch (BKException bke) {
assertEquals(Code.ZKException, bke.getCode());
}
verify(mockZk, times(1)).delete(eq(ledgerStr), eq(1234), any(VoidCallback.class), eq(null));
}
use of org.apache.bookkeeper.versioning.LongVersion in project bookkeeper by apache.
the class AbstractZkLedgerManagerTest method testUnregisterLedgerMetadataListener.
@Test
public void testUnregisterLedgerMetadataListener() throws Exception {
long ledgerId = System.currentTimeMillis();
String ledgerStr = String.valueOf(ledgerId);
LinkedBlockingQueue<LedgerMetadata> changes = new LinkedBlockingQueue<>();
LedgerMetadataListener listener = (ledgerId1, metadata) -> changes.add(metadata);
metadata.setVersion(new LongVersion(1234L));
Stat stat = mock(Stat.class);
when(stat.getVersion()).thenReturn(1234);
when(stat.getCtime()).thenReturn(metadata.getCtime());
mockZkGetData(ledgerStr, true, KeeperException.Code.OK.intValue(), metadata.serialize(), stat);
ledgerManager.registerLedgerMetadataListener(ledgerId, listener);
assertTrue(ledgerManager.listeners.containsKey(ledgerId));
// the listener will be notified with first get
LedgerMetadata change1 = changes.take();
assertEquals(metadata, change1);
verify(mockZk, times(1)).getData(anyString(), any(Watcher.class), any(DataCallback.class), any());
// the watcher is registered for receiving watched event
assertTrue(watchers.containsKey(ledgerStr));
Set<Watcher> watcherSet1 = watchers.get(ledgerStr);
assertEquals(1, watcherSet1.size());
Watcher registeredWatcher1 = watcherSet1.stream().findFirst().get();
// mock get data to return an updated metadata
metadata.setVersion(new LongVersion(1235L));
when(stat.getVersion()).thenReturn(1235);
mockZkGetData(ledgerStr, true, KeeperException.Code.OK.intValue(), metadata.serialize(), stat);
// unregister the listener
ledgerManager.unregisterLedgerMetadataListener(ledgerId, listener);
assertFalse(ledgerManager.listeners.containsKey(ledgerId));
// notify the watcher event
notifyWatchedEvent(EventType.NodeDataChanged, KeeperState.SyncConnected, ledgerStr);
// since listener is already unregistered so no more `getData` is issued.
assertNull(changes.poll());
verify(mockZk, times(1)).getData(anyString(), any(Watcher.class), any(DataCallback.class), any());
}
Aggregations