Skip to content

Conversation

@swallez
Copy link
Member

@swallez swallez commented Sep 16, 2019

Ensures empty containers that never had children added are deleted after a grace period.

The grace period ensures that such empty containers live at for one full collection period. This gives clients time to create the container and add children in separate transactions even if the container is created right before the collection task is run.

@maoling
Copy link
Member

maoling commented Sep 17, 2019

  • If I create a container node which has not any children yet, it will never be deleted by the cleaning task, this behavior is expected.
  • the doc in the zookeeperProgrammers.md

ZooKeeper has the notion of container znodes. Container znodes are
special purpose znodes useful for recipes such as leader, lock, etc.
When the last child of a container is deleted, the container becomes
a candidate to be deleted by the server at some point in the future.
Given this property, you should be prepared to get
KeeperException.NoNodeException when creating children inside of
container znodes. i.e. when creating child znodes inside of container znodes
always check for KeeperException.NoNodeException and recreate the container
znode when it occurs.

if (wasNewWithNoChildren) {
candidates.add(containerPath);
} else {
noChildrenAtLastCheck.add(containerPath);
Copy link
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
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);


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

containerManager.checkContainers();
Copy link
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
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?

@tisonkun
Copy link
Member

I second @maoling here that "If I create a container node which has not any children yet, it will never be deleted by the cleaning task, this behavior is expected."

When a user create a container node he must prepare to create several children of it. Otherwise it is a misuse that the user should take care of the clean-up by himself. In an edge case that the creation of child fails, it is the responsibility of users to tolerate the failing case.

Mainly my concern is if we introduce such grace period it becomes even worse users are now enforced to take care of an edge case caused by ZooKeeper: if they create a container first, following a creation of child which suffer network traffic and fails because of the grace period expire.

Besides, I'm afraid it also affects how downstream project like Curator takes care of container znodes. cc @Randgalt

@maoling
Copy link
Member

maoling commented Sep 18, 2019

  • this change has violated the semantic of CONTAINER node designed from ZOOKEEPER-2163,
    making the behavior of CONTAINER node very weird.

This proposal adds a new node type, CONTAINER. A CONTAINER node is the same as a PERSISTENT node with the additional property that when its last child is deleted, it is deleted (and CONTAINER nodes recursively up the tree are deleted if empty).

  • Further:the exist of CONTAINER node is an important flag for the developers to implement their recipes.how can I distinguish the Non-existent of that CONTAINER node is because of all her children have been deleted or she has no children at all.
  • What a scene I can image is: I have a main task which has many sub-tasks, then I can create a container node /main-task, then create ephemeral sequence nodes for every sub-tasks(e.g:/main-task/sub-task1,/main-task/sub-task2), a sub-task deleted its node after finishing its task.the main task will observer the existent of /main-task to judge whether the main task has finished successfully. If we pick up this patch, if all the sub-threads have all failed, after some time, the main task will also observer the in-existent of /main-task, mistakenly consider the state of main-task.

Copy link
Contributor

@nkalmar nkalmar left a comment

Choose a reason for hiding this comment

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

I also agree with @maoling and @tisonkun .
For me, it just makes more sense that an initialized container node does not get deleted. I wouldn't expect this to happen.

I personally also don't like the unconfigurable collection period TTL.

This is a behavioural change rather than a bug. If you want to change the behaviour, I think it should be first discussed with the community on [email protected]

@swallez
Copy link
Member Author

swallez commented Oct 9, 2019

Ok, I understand this is a feature rather than an unwanted side effect of giving time for application to create childrens, and I won't dispute that.

What led to proposing this change is a problem we encountered when using Curator's PersistentTtlNode that creates a container and adds a child to it, but doesn't do it as a transaction. This led to the issue we encountered.

I'm therefore closing this PR and the associated issue and will address this issue in Curator.

@swallez swallez closed this Oct 9, 2019
@tisonkun
Copy link
Member

tisonkun commented Oct 9, 2019

Thanks for your update @swallez . Sounds interesting what Curator's PersistentTtlNode does. Will check it out :-)

@Randgalt
Copy link
Member

Randgalt commented Oct 9, 2019

Sorry - I missed the cc on this. I'll follow on Curator if @swallez opens an issue there.

@swallez
Copy link
Member Author

swallez commented Oct 9, 2019

@tisonkun PersistentTtlNode creates a container as a PersistentNode and then adds a TTL node in it named touch that is refreshed periodically. This means the application can use the parent as a regular node and won't be polluted by watch event triggered by the periodic refresh required by the TTL.

The problem in Curator is that those two nodes (container and touch child) are created separately. So if there's a crash between these two requests and touch is never created, the parent container stays forever.

@swallez swallez deleted the ZOOKEEPER-3546-delete-empty-containers branch October 9, 2019 16:36
@swallez
Copy link
Member Author

swallez commented Oct 9, 2019

@Randgalt creating an issue on Curator right now ;-)

@Randgalt
Copy link
Member

Randgalt commented Oct 9, 2019

Yeah - I think it can be done in a transaction. The transaction APIs support TTL I'm pretty sure.

@henrikno
Copy link

Curator issue for reference: https://issues.apache.org/jira/browse/CURATOR-545

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants