public void waitUntilDone(Set<String> workIDs) throws KeeperException, InterruptedException {

    final String condVar = new String("cond");

    Watcher watcher =
        new Watcher() {
          @Override
          public void process(WatchedEvent event) {
            switch (event.getType()) {
              case NodeChildrenChanged:
                synchronized (condVar) {
                  condVar.notify();
                }
                break;
              case NodeCreated:
              case NodeDataChanged:
              case NodeDeleted:
              case None:
                log.info("Got unexpected zookeeper event: " + event.getType() + " for " + path);
                break;
            }
          }
        };

    List<String> children = zoo.getChildren(path, watcher);

    while (!Collections.disjoint(children, workIDs)) {
      synchronized (condVar) {
        condVar.wait(10000);
      }
      children = zoo.getChildren(path, watcher);
    }
  }
  public void startProcessing(final Processor processor, ThreadPoolExecutor executorService)
      throws KeeperException, InterruptedException {

    threadPool = (ThreadPoolExecutor) executorService;

    zoo.mkdirs(path);
    zoo.mkdirs(path + "/" + LOCKS_NODE);

    List<String> children =
        zoo.getChildren(
            path,
            new Watcher() {
              @Override
              public void process(WatchedEvent event) {
                switch (event.getType()) {
                  case NodeChildrenChanged:
                    if (event.getPath().equals(path))
                      try {
                        lookForWork(processor, zoo.getChildren(path, this));
                      } catch (KeeperException e) {
                        log.error("Failed to look for work", e);
                      } catch (InterruptedException e) {
                        log.info("Interrupted looking for work", e);
                      }
                    else
                      log.info("Unexpected path for NodeChildrenChanged event " + event.getPath());
                    break;
                  case NodeCreated:
                  case NodeDataChanged:
                  case NodeDeleted:
                  case None:
                    log.info("Got unexpected zookeeper event: " + event.getType() + " for " + path);
                    break;
                }
              }
            });

    lookForWork(processor, children);

    Random r = new Random();
    // Add a little jitter to avoid all the tservers slamming zookeeper at once
    SimpleTimer.getInstance()
        .schedule(
            new Runnable() {
              @Override
              public void run() {
                try {
                  lookForWork(processor, zoo.getChildren(path));
                } catch (KeeperException e) {
                  log.error("Failed to look for work", e);
                } catch (InterruptedException e) {
                  log.info("Interrupted looking for work", e);
                }
              }
            },
            r.nextInt(60 * 1000),
            60 * 1000);
  }
 public List<String> getWorkQueued() throws KeeperException, InterruptedException {
   ArrayList<String> children = new ArrayList<String>(zoo.getChildren(path));
   children.remove(LOCKS_NODE);
   return children;
 }