Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ public class ContainerManager {
private final int maxPerMinute;
private final Timer timer;
private final AtomicReference<TimerTask> task = new AtomicReference<TimerTask>(null);
private final Set<String> noChildrenAtLastCheck = new HashSet<String>();

/**
* @param zkDb the ZK database
Expand Down Expand Up @@ -139,14 +140,22 @@ protected Collection<String> getCandidates() {
Set<String> candidates = new HashSet<String>();
for (String containerPath : zkDb.getDataTree().getContainers()) {
DataNode node = zkDb.getDataTree().getNode(containerPath);
/*
cversion > 0: keep newly created containers from being deleted
before any children have been added. If you were to create the
container just before a container cleaning period the container
would be immediately be deleted.
*/
if ((node != null) && (node.stat.getCversion() > 0) && (node.getChildren().isEmpty())) {
candidates.add(containerPath);
boolean wasNewWithNoChildren = noChildrenAtLastCheck.remove(containerPath);

if (node != null && node.getChildren().isEmpty()) {
if (node.stat.getCversion() == 0) {
// Give newly created containers a grace period and avoid deleting
// them before any children could be added. If you were to create the
// container just before a container cleaning period the container
// would be immediately be deleted.
if (wasNewWithNoChildren) {
candidates.add(containerPath);
} else {
noChildrenAtLastCheck.add(containerPath);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

At a first glance we are only adding elements and never clearing the collection

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, we do it outside of the getChildren().isEmpty() test. Children may have been added since the container was added to that collection, so we need to make sure that containers with children don't stay in it forever.

boolean wasNewWithNoChildren = noChildrenAtLastCheck.remove(containerPath);

}
} else {
candidates.add(containerPath);
}
}
}
for (String ttlPath : zkDb.getDataTree().getTtls()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -237,6 +237,22 @@ public Void call() throws Exception {
assertEquals(queue.poll(5, TimeUnit.SECONDS), "/four");
}

@Test(timeout = 30000)
public void testContainerWithNoChildGracePeriod() throws KeeperException, InterruptedException {
zk.create("/foo", new byte[0], ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.CONTAINER);

ContainerManager containerManager = new ContainerManager(serverFactory.getZooKeeperServer().getZKDatabase(), serverFactory.getZooKeeperServer().firstProcessor, 1, 100);
containerManager.checkContainers();
Thread.sleep(1000);

assertNotNull("Container should still be there", zk.exists("/foo", false));

containerManager.checkContainers();

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we avoid this sleep?
This test may turn into a flaky one

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I used the same approach as other tests in that class, where I understand that these sleep after each call to checkContainers are precisely there to avoid flakiness by giving time to the ZK server to asynchronously delete the nodes that have been selected for removal.

Did I miss something?

Thread.sleep(1000);

assertNull("Container should have been deleted", zk.exists("/foo", false));
}

private void createNoStatVerifyResult(String newName) throws KeeperException, InterruptedException {
assertNull("Node existed before created", zk.exists(newName, false));
zk.create(newName, newName.getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.CONTAINER);
Expand Down