View Javadoc

1   /**
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *     http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing, software
13   * distributed under the License is distributed on an "AS IS" BASIS,
14   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15   * See the License for the specific language governing permissions and
16   * limitations under the License.
17   */
18  package org.apache.hadoop.hbase.backup.example;
19  
20  import java.io.IOException;
21  
22  import org.apache.commons.logging.Log;
23  import org.apache.commons.logging.LogFactory;
24  import org.apache.hadoop.hbase.classification.InterfaceAudience;
25  import org.apache.hadoop.conf.Configuration;
26  import org.apache.hadoop.hbase.ZooKeeperConnectionException;
27  import org.apache.hadoop.hbase.client.HConnection;
28  import org.apache.hadoop.hbase.master.cleaner.HFileCleaner;
29  import org.apache.hadoop.hbase.util.Bytes;
30  import org.apache.hadoop.hbase.zookeeper.ZKUtil;
31  import org.apache.hadoop.hbase.zookeeper.ZooKeeperWatcher;
32  import org.apache.zookeeper.KeeperException;
33  
34  /**
35   * Client-side manager for which table's hfiles should be preserved for long-term archive.
36   * @see ZKTableArchiveClient
37   * @see HFileArchiveTableMonitor
38   * @see LongTermArchivingHFileCleaner
39   */
40  @InterfaceAudience.Private
41  class HFileArchiveManager {
42  
43    private final String archiveZnode;
44    private static final Log LOG = LogFactory.getLog(HFileArchiveManager.class);
45    private final ZooKeeperWatcher zooKeeper;
46    private volatile boolean stopped = false;
47  
48    public HFileArchiveManager(HConnection connection, Configuration conf)
49        throws ZooKeeperConnectionException, IOException {
50      this.zooKeeper = new ZooKeeperWatcher(conf, "hfileArchiveManager-on-" + connection.toString(),
51          connection);
52      this.archiveZnode = ZKTableArchiveClient.getArchiveZNode(this.zooKeeper.getConfiguration(),
53        this.zooKeeper);
54    }
55  
56    /**
57     * Turn on auto-backups of HFiles on the specified table.
58     * <p>
59     * When HFiles would be deleted from the hfile archive, they are instead preserved.
60     * @param table name of the table for which to preserve hfiles.
61     * @return <tt>this</tt> for chaining.
62     * @throws KeeperException if we can't reach zookeeper to update the hfile cleaner.
63     */
64    public HFileArchiveManager enableHFileBackup(byte[] table) throws KeeperException {
65      enable(this.zooKeeper, table);
66      return this;
67    }
68  
69    /**
70     * Stop retaining HFiles for the given table in the archive. HFiles will be cleaned up on the next
71     * pass of the {@link HFileCleaner}, if the HFiles are retained by another cleaner.
72     * @param table name of the table for which to disable hfile retention.
73     * @return <tt>this</tt> for chaining.
74     * @throws KeeperException if if we can't reach zookeeper to update the hfile cleaner.
75     */
76    public HFileArchiveManager disableHFileBackup(byte[] table) throws KeeperException {
77        disable(this.zooKeeper, table);
78        return this;
79    }
80  
81    /**
82     * Disable long-term archival of all hfiles for all tables in the cluster.
83     * @return <tt>this</tt> for chaining.
84     * @throws IOException if the number of attempts is exceeded
85     */
86    public HFileArchiveManager disableHFileBackup() throws IOException {
87      LOG.debug("Disabling backups on all tables.");
88      try {
89        ZKUtil.deleteNodeRecursively(this.zooKeeper, archiveZnode);
90        return this;
91      } catch (KeeperException e) {
92        throw new IOException("Unexpected ZK exception!", e);
93      }
94    }
95  
96    /**
97     * Perform a best effort enable of hfile retention, which relies on zookeeper communicating the //
98     * * change back to the hfile cleaner.
99     * <p>
100    * No attempt is made to make sure that backups are successfully created - it is inherently an
101    * <b>asynchronous operation</b>.
102    * @param zooKeeper watcher connection to zk cluster
103    * @param table table name on which to enable archiving
104    * @throws KeeperException
105    */
106   private void enable(ZooKeeperWatcher zooKeeper, byte[] table)
107       throws KeeperException {
108     LOG.debug("Ensuring archiving znode exists");
109     ZKUtil.createAndFailSilent(zooKeeper, archiveZnode);
110 
111     // then add the table to the list of znodes to archive
112     String tableNode = this.getTableNode(table);
113     LOG.debug("Creating: " + tableNode + ", data: []");
114     ZKUtil.createSetData(zooKeeper, tableNode, new byte[0]);
115   }
116 
117   /**
118    * Disable all archiving of files for a given table
119    * <p>
120    * Inherently an <b>asynchronous operation</b>.
121    * @param zooKeeper watcher for the ZK cluster
122    * @param table name of the table to disable
123    * @throws KeeperException if an unexpected ZK connection issues occurs
124    */
125   private void disable(ZooKeeperWatcher zooKeeper, byte[] table) throws KeeperException {
126     // ensure the latest state of the archive node is found
127     zooKeeper.sync(archiveZnode);
128 
129     // if the top-level archive node is gone, then we are done
130     if (ZKUtil.checkExists(zooKeeper, archiveZnode) < 0) {
131       return;
132     }
133     // delete the table node, from the archive
134     String tableNode = this.getTableNode(table);
135     // make sure the table is the latest version so the delete takes
136     zooKeeper.sync(tableNode);
137 
138     LOG.debug("Attempting to delete table node:" + tableNode);
139     ZKUtil.deleteNodeRecursively(zooKeeper, tableNode);
140   }
141 
142   public void stop() {
143     if (!this.stopped) {
144       this.stopped = true;
145       LOG.debug("Stopping HFileArchiveManager...");
146       this.zooKeeper.close();
147     }
148   }
149 
150   /**
151    * Check to see if the table is currently marked for archiving
152    * @param table name of the table to check
153    * @return <tt>true</tt> if the archive znode for that table exists, <tt>false</tt> if not
154    * @throws KeeperException if an unexpected zookeeper error occurs
155    */
156   public boolean isArchivingEnabled(byte[] table) throws KeeperException {
157     String tableNode = this.getTableNode(table);
158     return ZKUtil.checkExists(zooKeeper, tableNode) >= 0;
159   }
160 
161   /**
162    * Get the zookeeper node associated with archiving the given table
163    * @param table name of the table to check
164    * @return znode for the table's archive status
165    */
166   private String getTableNode(byte[] table) {
167     return ZKUtil.joinZNode(archiveZnode, Bytes.toString(table));
168   }
169 }