Java tutorial
/* * Copyright 2012 - 2016 Splice Machine, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use * this file except in compliance with the License. You may obtain a copy of the * License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software distributed * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR * CONDITIONS OF ANY KIND, either express or implied. See the License for the * specific language governing permissions and limitations under the License. */ package com.splicemachine.ddl; import java.io.IOException; import java.util.Collection; import java.util.List; import com.google.common.collect.Lists; import org.apache.log4j.Logger; import org.apache.zookeeper.CreateMode; import org.apache.zookeeper.KeeperException; import org.apache.zookeeper.Op; import org.apache.zookeeper.OpResult; import org.apache.zookeeper.WatchedEvent; import org.apache.zookeeper.Watcher; import org.apache.zookeeper.ZooDefs; import com.splicemachine.access.configuration.DDLConfiguration; import com.splicemachine.derby.ddl.CommunicationListener; import com.splicemachine.derby.ddl.DDLWatchChecker; import com.splicemachine.hbase.ZkUtils; import com.splicemachine.pipeline.Exceptions; import com.splicemachine.utils.Pair; /** * @author Scott Fines * Date: 9/7/15 */ public class ZooKeeperDDLWatchChecker implements DDLWatchChecker { private static final Logger LOG = Logger.getLogger(ZooKeeperDDLWatchChecker.class); private String id; private Watcher changeIdWatcher; private final DDLZookeeperClient zkClient; public ZooKeeperDDLWatchChecker(DDLZookeeperClient zkClient) { this.zkClient = zkClient; } @Override public boolean initialize(final CommunicationListener changeIdListener) throws IOException { this.id = zkClient.registerThisServer(); if (id == null) return false; //not a server, so inform the world if (id.startsWith("/")) id = id.substring(1); //strip the leading / to make sure that we register properly changeIdWatcher = new Watcher() { @Override public void process(WatchedEvent watchedEvent) { if (watchedEvent.getType().equals(Event.EventType.NodeChildrenChanged)) { if (LOG.isTraceEnabled()) LOG.trace("Received watch event, signalling refresh"); changeIdListener.onCommunicationEvent(watchedEvent.getPath()); } } }; return true; } @Override public Collection<String> getCurrentChangeIds() throws IOException { try { return ZkUtils.getRecoverableZooKeeper().getChildren(zkClient.changePath, changeIdWatcher); } catch (KeeperException ke) { if (ke.code().equals(KeeperException.Code.SESSIONEXPIRED)) { LOG.error("ZooKeeper Session expired, terminating early"); return null; } throw new IOException(ke); } catch (InterruptedException e) { throw Exceptions.getIOException(e); } } @Override public DDLMessage.DDLChange getChange(String changeId) throws IOException { byte[] data = ZkUtils.getData(zkClient.changePath + "/" + changeId); return DDLMessage.DDLChange.newBuilder().mergeFrom(DDLMessage.DDLChange.parseFrom(data)) .setChangeId(changeId).build(); } @Override public void notifyProcessed(Collection<Pair<DDLMessage.DDLChange, String>> processedChanges) throws IOException { /* * Notify the relevant controllers that their change has been processed */ List<Op> ops = Lists.newArrayListWithExpectedSize(processedChanges.size()); List<DDLMessage.DDLChange> changeList = Lists.newArrayList(); for (Pair<DDLMessage.DDLChange, String> pair : processedChanges) { DDLMessage.DDLChange change = pair.getFirst(); String errorMessage = pair.getSecond(); // Tag Errors for handling on the client, will allow us to understand what node failed and why... String path = zkClient.changePath + "/" + change.getChangeId() + "/" + (errorMessage == null ? "" : DDLConfiguration.ERROR_TAG) + id; Op op = Op.create(path, (errorMessage == null ? new byte[] {} : (String.format("server [%s] failed with error [%s]", id, errorMessage).getBytes())), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL); ops.add(op); changeList.add(change); } try { List<OpResult> multi = ZkUtils.getRecoverableZooKeeper().getZooKeeper().multi(ops); for (int i = 0; i < multi.size(); i++) { OpResult result = multi.get(i); if (!(result instanceof OpResult.ErrorResult)) processedChanges.remove(changeList.get(i)); else { OpResult.ErrorResult err = (OpResult.ErrorResult) result; KeeperException.Code code = KeeperException.Code.get(err.getErr()); switch (code) { case NODEEXISTS: //we may have already set the value, so ignore node exists issues case NONODE: // someone already removed the notification, it's obsolete // ignore break; default: throw Exceptions.getIOException(KeeperException.create(code)); } } } } catch (InterruptedException e) { throw Exceptions.getIOException(e); } catch (KeeperException e) { switch (e.code()) { case NODEEXISTS: //we may have already set the value, so ignore node exists issues case NONODE: // someone already removed the notification, it's obsolete // ignore break; default: throw Exceptions.getIOException(e); } } } @Override public void killDDLTransaction(String key) { zkClient.deleteChangeNode(key); } }