View Javadoc

1   /*
2    *
3    * Licensed to the Apache Software Foundation (ASF) under one
4    * or more contributor license agreements.  See the NOTICE file
5    * distributed with this work for additional information
6    * regarding copyright ownership.  The ASF licenses this file
7    * to you under the Apache License, Version 2.0 (the
8    * "License"); you may not use this file except in compliance
9    * with the License.  You may obtain a copy of the License at
10   *
11   *     http://www.apache.org/licenses/LICENSE-2.0
12   *
13   * Unless required by applicable law or agreed to in writing, software
14   * distributed under the License is distributed on an "AS IS" BASIS,
15   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16   * See the License for the specific language governing permissions and
17   * limitations under the License.
18   */
19  package org.apache.hadoop.hbase.replication;
20  
21  import com.google.protobuf.InvalidProtocolBufferException;
22  import org.apache.commons.logging.Log;
23  import org.apache.commons.logging.LogFactory;
24  import org.apache.hadoop.hbase.Abortable;
25  import org.apache.hadoop.hbase.exceptions.DeserializationException;
26  import org.apache.hadoop.hbase.protobuf.ProtobufUtil;
27  import org.apache.hadoop.hbase.protobuf.generated.ZooKeeperProtos;
28  import org.apache.hadoop.hbase.zookeeper.ZKUtil;
29  import org.apache.hadoop.hbase.zookeeper.ZooKeeperNodeTracker;
30  import org.apache.hadoop.hbase.zookeeper.ZooKeeperWatcher;
31  import org.apache.zookeeper.KeeperException;
32  
33  import java.io.IOException;
34  import java.util.concurrent.atomic.AtomicBoolean;
35  
36  /**
37   * ReplicationStateImpl is responsible for maintaining the replication state
38   * znode.
39   */
40  public class ReplicationStateImpl implements ReplicationStateInterface {
41  
42    private ReplicationStateTracker stateTracker;
43    private final String stateZnode;
44    private final ZooKeeperWatcher zookeeper;
45    private final Abortable abortable;
46    private final AtomicBoolean replicating;
47  
48    private static final Log LOG = LogFactory.getLog(ReplicationStateImpl.class);
49  
50    public ReplicationStateImpl(final ZooKeeperWatcher zk, final String stateZnode,
51        final Abortable abortable, final AtomicBoolean replicating) {
52      this.zookeeper = zk;
53      this.stateZnode = stateZnode;
54      this.abortable = abortable;
55      this.replicating = replicating;
56  
57      // Set a tracker on replicationStateNode
58      this.stateTracker = new ReplicationStateTracker(this.zookeeper, this.stateZnode,
59          this.abortable);
60      stateTracker.start();
61      readReplicationStateZnode();
62    }
63  
64    public boolean getState() throws KeeperException {
65      return getReplication();
66    }
67  
68    public void setState(boolean newState) throws KeeperException {
69      setReplicating(newState);
70    }
71  
72    @Override
73    public void close() throws IOException {
74      if (stateTracker != null) stateTracker.stop();
75    }
76  
77    /**
78     * @param bytes
79     * @return True if the passed in <code>bytes</code> are those of a pb
80     *         serialized ENABLED state.
81     * @throws DeserializationException
82     */
83    private boolean isStateEnabled(final byte[] bytes) throws DeserializationException {
84      ZooKeeperProtos.ReplicationState.State state = parseStateFrom(bytes);
85      return ZooKeeperProtos.ReplicationState.State.ENABLED == state;
86    }
87  
88    /**
89     * @param bytes Content of a state znode.
90     * @return State parsed from the passed bytes.
91     * @throws DeserializationException
92     */
93    private ZooKeeperProtos.ReplicationState.State parseStateFrom(final byte[] bytes)
94        throws DeserializationException {
95      ProtobufUtil.expectPBMagicPrefix(bytes);
96      int pblen = ProtobufUtil.lengthOfPBMagic();
97      ZooKeeperProtos.ReplicationState.Builder builder = ZooKeeperProtos.ReplicationState
98          .newBuilder();
99      ZooKeeperProtos.ReplicationState state;
100     try {
101       state = builder.mergeFrom(bytes, pblen, bytes.length - pblen).build();
102       return state.getState();
103     } catch (InvalidProtocolBufferException e) {
104       throw new DeserializationException(e);
105     }
106   }
107 
108   /**
109    * Set the new replication state for this cluster
110    * @param newState
111    */
112   private void setReplicating(boolean newState) throws KeeperException {
113     ZKUtil.createWithParents(this.zookeeper, this.stateZnode);
114     byte[] stateBytes = (newState == true) ? ReplicationZookeeper.ENABLED_ZNODE_BYTES
115         : ReplicationZookeeper.DISABLED_ZNODE_BYTES;
116     ZKUtil.setData(this.zookeeper, this.stateZnode, stateBytes);
117   }
118 
119   /**
120    * Get the replication status of this cluster. If the state znode doesn't
121    * exist it will also create it and set it true.
122    * @return returns true when it's enabled, else false
123    * @throws KeeperException
124    */
125   private boolean getReplication() throws KeeperException {
126     byte[] data = this.stateTracker.getData(false);
127     if (data == null || data.length == 0) {
128       setReplicating(true);
129       return true;
130     }
131     try {
132       return isStateEnabled(data);
133     } catch (DeserializationException e) {
134       throw ZKUtil.convert(e);
135     }
136   }
137 
138   /**
139    * This reads the state znode for replication and sets the atomic boolean
140    */
141   private void readReplicationStateZnode() {
142     try {
143       this.replicating.set(getReplication());
144       LOG.info("Replication is now " + (this.replicating.get() ? "started" : "stopped"));
145     } catch (KeeperException e) {
146       this.abortable.abort("Failed getting data on from " + this.stateZnode, e);
147     }
148   }
149 
150   /**
151    * Tracker for status of the replication
152    */
153   private class ReplicationStateTracker extends ZooKeeperNodeTracker {
154     public ReplicationStateTracker(ZooKeeperWatcher watcher, String stateZnode, Abortable abortable) {
155       super(watcher, stateZnode, abortable);
156     }
157 
158     @Override
159     public synchronized void nodeDataChanged(String path) {
160       if (path.equals(node)) {
161         super.nodeDataChanged(path);
162         readReplicationStateZnode();
163       }
164     }
165   }
166 }