* @throws org.apache.zookeeper.KeeperException on ZooKeeper error.
*/
public void update() throws IOException, KeeperException {
final KijiMetaTable metaTable = mKiji.getMetaTable();
final Lock lock = ZooKeeperUtils.newTableLayoutLock(mZKClient, mTableURI);
lock.lock();
try {
final NavigableMap<Long, KijiTableLayout> layoutMap =
metaTable.getTimedTableLayoutVersions(mTableURI.getTable(), Integer.MAX_VALUE);
final KijiTableLayout currentLayout = layoutMap.lastEntry().getValue();
final TableLayoutDesc update = mLayoutUpdate.apply(currentLayout);
if (!Objects.equal(currentLayout.getDesc().getLayoutId(), update.getReferenceLayout())) {
throw new InvalidLayoutException(String.format(
"Reference layout ID %s does not match current layout ID %s.",
update.getReferenceLayout(), currentLayout.getDesc().getLayoutId()));
}
final TableLayoutUpdateValidator validator = new TableLayoutUpdateValidator(mKiji);
final KijiTableLayout updatedLayout =
KijiTableLayout.createUpdatedLayout(update , currentLayout);
validateCassandraTableLayout(updatedLayout.getDesc());
validator.validate(currentLayout, updatedLayout);
final TableLayoutTracker layoutTracker =
new TableLayoutTracker(mZKClient, mTableURI, mLayoutUpdateHandler).start();
try {
final UsersTracker usersTracker = ZooKeeperUtils.newTableUsersTracker(mZKClient, mTableURI);
usersTracker.registerUpdateHandler(mUsersUpdateHandler);
try {
usersTracker.start();
final String currentLayoutId = mLayoutUpdateHandler.getCurrentLayoutId();
LOG.info("Table {} has current layout ID {}.", mTableURI, currentLayoutId);
if (!Objects.equal(currentLayoutId, currentLayout.getDesc().getLayoutId())) {
throw new InternalKijiError(String.format(
"Inconsistency between meta-table and ZooKeeper: "
+ "meta-table layout has ID %s while ZooKeeper has layout ID %s.",
currentLayout.getDesc().getLayoutId(), currentLayoutId));
}
final String consistentLayoutId = waitForConsistentView();
if ((consistentLayoutId != null) && !Objects.equal(consistentLayoutId, currentLayoutId)) {
throw new InternalKijiError(String.format(
"Consistent layout ID %s does not match current layout %s for table %s.",
consistentLayoutId, currentLayout, mTableURI));
}
writeMetaTable(update);
final TableLayoutDesc newLayoutDesc = mNewLayout.getDesc();
writeZooKeeper(newLayoutDesc);
mLayoutUpdateHandler.waitForLayoutNotification(newLayoutDesc.getLayoutId());
// The following is not necessary:
while (true) {
final String newLayoutId = waitForConsistentView();
if (newLayoutId == null) {
LOG.info("Layout update complete for table {}: table has no users.", mTableURI);
break;
} else if (Objects.equal(newLayoutId, newLayoutDesc.getLayoutId())) {
LOG.info("Layout update complete for table {}: all users switched to layout ID {}.",
mTableURI, newLayoutId);
break;
} else {
LOG.info("Layout update in progress for table {}: users still using layout ID {}.",
mTableURI, newLayoutId);
Time.sleep(1.0);
}
}
} finally {
usersTracker.close();
}
} finally {
layoutTracker.close();
}
} finally {
lock.unlock();
lock.close();
}
}