/** * Initializes a new table layout monitor. * * @param zkClient ZooKeeper client. * @throws KeeperException on unrecoverable ZooKeeper error. */ public ZooKeeperMonitor(ZooKeeperClient zkClient) throws KeeperException { this.mZKClient = zkClient; this.mZKClient.createNodeRecursively(ROOT_ZOOKEEPER_PATH); // ZooKeeperClient.retain() should be the last line of the constructor. this.mZKClient.retain(); }
/** {@inheritDoc} */ @Override public void run() { try { ZooKeeperMonitor.this.mZKClient.createNodeRecursively(mUsersDir); } catch (KeeperException ke) { LOG.error("Unrecoverable ZooKeeper error: {}", ke.getMessage()); throw new RuntimeException(ke); } registerWatcher(); } };
/** * Creates a ZooKeeper lock node. * * @param path ZooKeeper lock node path prefix. * @return the created ZooKeeper lock node path. * @throws KeeperException on error. */ private File createZKLockNode(File path) throws KeeperException { boolean parentCreated = false; while (true) { try { return mZKClient.create(path, EMPTY, Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL_SEQUENTIAL); } catch (NoNodeException nne) { LOG.debug("Cannot create ZooKeeper lock node {}: parent node does not exist.", path); Preconditions.checkState(!parentCreated); // creates the parent node at most once. mZKClient.createNodeRecursively(path.getParentFile()); parentCreated = true; } } }
/** * Start this instance user registration. * * @throws IOException on unrecoverable ZooKeeper error. */ public void start() throws IOException { synchronized (mMonitor) { try { final File usersDir = getInstanceUsersDir(mInstanceURI); LOG.debug("Registering user '{}' for Fiji instance '{}' with system version '{}'.", mUserID, mInstanceURI, mSystemVersion); ZooKeeperMonitor.this.mZKClient.createNodeRecursively(usersDir); final String nodeName = makeZKNodeName(mUserID, mSystemVersion); final File nodePath = new File(usersDir, nodeName); mCurrentNode = ZooKeeperMonitor.this.mZKClient.create( nodePath, EMPTY_BYTES, Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL); } catch (KeeperException e) { throw new IOException(e); } } }
/** * Creates a ZooKeeper node and all its parents, if necessary. * * @param path of the node to create. * @throws KeeperException on I/O error. */ public void createNodeRecursively(File path) throws KeeperException { if (exists(path) != null) { return; } if (path.getPath().equals("/")) { // No need to create the root node "/" : return; } final File parent = path.getParentFile(); if (parent != null) { createNodeRecursively(parent); } try { LOG.debug("Creating ZooKeeper node: {}", path); final File createdPath = this.create(path, EMPTY_BYTES, Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT); Preconditions.checkState(createdPath.equals(path)); } catch (NodeExistsException exn) { LOG.debug("ZooKeeper node already exists: {}", path); } }
/** * Register this table user with ZooKeeper. * * @param layoutID layout id known by table user. * @throws IOException on unrecoverable ZooKeeper error. */ private void register(String layoutID) throws IOException { synchronized (mMonitor) { try { final File usersDir = getTableUsersDir(mTableURI); LOG.debug("Registering user '{}' for Fiji table '{}' with layout ID '{}'.", mUserID, mTableURI, layoutID); ZooKeeperMonitor.this.mZKClient.createNodeRecursively(usersDir); final String nodeName = makeZKNodeName(mUserID, layoutID); final File nodePath = new File(usersDir, nodeName); final byte[] data = EMPTY_BYTES; mCurrentNode = ZooKeeperMonitor.this.mZKClient.create( nodePath, data, Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL); } catch (KeeperException e) { throw new IOException(e); } } }
/** * Notifies the users of a table of a new layout. * * <p> * The caller must ensure proper locking of table layout update operations through * {@link #newTableLayoutUpdateLock(FijiURI)}. * </p> * * @param tableURI Notify the users of the table with this URI. * @param layout Encoded layout update for the table with the specified URI. * @param version of the current table layout. * @throws KeeperException on unrecoverable ZooKeeper error. */ public void notifyNewTableLayout(FijiURI tableURI, byte[] layout, int version) throws KeeperException { final File layoutPath = getTableLayoutFile(tableURI); this.mZKClient.createNodeRecursively(layoutPath); // This should not be needed if we add a lock for layout updates. final Stat updateStat = this.mZKClient.setData(layoutPath, layout, version); LOG.debug("Updated layout for table {}. Layout version is {}.", tableURI, updateStat.getVersion()); }