private void handleChildrenChanged(String eventPath) throws InterruptedException, KeeperException {
        ZNodeState zNodeState = retrieveOrCreateZNodeState(eventPath);
        zNodeState.acquire();
        try {
            final Set<String> lastTimeChildren = zNodeState.getChildren();
            Set<String> newChildNames = new HashSet<String>();

            final List<String> children;
            try {
                children = zk.getChildren(eventPath, true);
            } catch (KeeperException e) {
                znodeStateCache.remove(eventPath);
                return;
            }

            for (String child : children) {
                newChildNames.add(child);
            }
            zNodeState.setChildren(newChildNames);

            final Sets.SetView<String> removedChilds = Sets.difference(lastTimeChildren, newChildNames);
            final Sets.SetView<String> newChilds = Sets.difference(newChildNames, lastTimeChildren);

            for (String removedChild : removedChilds) {
                final String childFQPath = eventPath.equals("/") ? ("/" + removedChild) : (eventPath + "/" + removedChild);
                propagateToListeners(new ZNodeMessage(childFQPath, ZNodeMessage.Type.D, null));
            }

            for (String newChild : newChilds) {
                final String childFQPath = eventPath.equals("/") ? ("/" + newChild) : (eventPath + "/" + newChild);

                Stat childStat;
                try {
                    childStat = zk.exists(childFQPath, true);
                } catch (KeeperException e) {
                    continue;
                }
                
                propagateToListeners(new ZNodeMessage(childFQPath, ZNodeMessage.Type.C, childStat));
                zk.getChildren(childFQPath, true);
            }
        } finally {
            zNodeState.release();
        }
    }