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.conf.Configuration;
25  import org.apache.hadoop.hbase.ZooKeeperConnectionException;
26  import org.apache.hadoop.hbase.classification.InterfaceAudience;
27  import org.apache.hadoop.hbase.client.Connection;
28  import org.apache.hadoop.hbase.util.Bytes;
29  import org.apache.hadoop.hbase.zookeeper.ZKUtil;
30  import org.apache.hadoop.hbase.zookeeper.ZooKeeperWatcher;
31  import org.apache.zookeeper.KeeperException;
32  
33  /**
34   * Client-side manager for which table's hfiles should be preserved for long-term archive.
35   * @see ZKTableArchiveClient
36   * @see HFileArchiveTableMonitor
37   * @see LongTermArchivingHFileCleaner
38   */
39  @InterfaceAudience.Private
40  class HFileArchiveManager {
41  
42    private final String archiveZnode;
43    private static final Log LOG = LogFactory.getLog(HFileArchiveManager.class);
44    private final ZooKeeperWatcher zooKeeper;
45    private volatile boolean stopped = false;
46  
47    public HFileArchiveManager(Connection connection, Configuration conf)
48        throws ZooKeeperConnectionException, IOException {
49      this.zooKeeper = new ZooKeeperWatcher(conf, "hfileArchiveManager-on-" + connection.toString(),
50          connection);
51      this.archiveZnode = ZKTableArchiveClient.getArchiveZNode(this.zooKeeper.getConfiguration(),
52        this.zooKeeper);
53    }
54  
55    /**
56     * Turn on auto-backups of HFiles on the specified table.
57     * <p>
58     * When HFiles would be deleted from the hfile archive, they are instead preserved.
59     * @param table name of the table for which to preserve hfiles.
60     * @return <tt>this</tt> for chaining.
61     * @throws KeeperException if we can't reach zookeeper to update the hfile cleaner.
62     */
63    public HFileArchiveManager enableHFileBackup(byte[] table) throws KeeperException {
64      enable(this.zooKeeper, table);
65      return this;
66    }
67  
68    /**
69     * Stop retaining HFiles for the given table in the archive. HFiles will be cleaned up on the next
70     * pass of the {@link HFileCleaner}, if the HFiles are retained by another cleaner.
71     * @param table name of the table for which to disable hfile retention.
72     * @return <tt>this</tt> for chaining.
73     * @throws KeeperException if if we can't reach zookeeper to update the hfile cleaner.
74     */
75    public HFileArchiveManager disableHFileBackup(byte[] table) throws KeeperException {
76        disable(this.zooKeeper, table);
77      return this;
78    }
79  
80    /**
81     * Disable long-term archival of all hfiles for all tables in the cluster.
82     * @return <tt>this</tt> for chaining.
83     * @throws IOException if the number of attempts is exceeded
84     */
85    public HFileArchiveManager disableHFileBackup() throws IOException {
86      LOG.debug("Disabling backups on all tables.");
87      try {
88        ZKUtil.deleteNodeRecursively(this.zooKeeper, archiveZnode);
89        return this;
90      } catch (KeeperException e) {
91        throw new IOException("Unexpected ZK exception!", e);
92      }
93    }
94  
95    /**
96     * Perform a best effort enable of hfile retention, which relies on zookeeper communicating the //
97     * * change back to the hfile cleaner.
98     * <p>
99     * No attempt is made to make sure that backups are successfully created - it is inherently an
100    * <b>asynchronous operation</b>.
101    * @param zooKeeper watcher connection to zk cluster
102    * @param table table name on which to enable archiving
103    * @throws KeeperException
104    */
105   private void enable(ZooKeeperWatcher zooKeeper, byte[] table)
106       throws KeeperException {
107     LOG.debug("Ensuring archiving znode exists");
108     ZKUtil.createAndFailSilent(zooKeeper, archiveZnode);
109 
110     // then add the table to the list of znodes to archive
111     String tableNode = this.getTableNode(table);
112     LOG.debug("Creating: " + tableNode + ", data: []");
113     ZKUtil.createSetData(zooKeeper, tableNode, new byte[0]);
114   }
115 
116   /**
117    * Disable all archiving of files for a given table
118    * <p>
119    * Inherently an <b>asynchronous operation</b>.
120    * @param zooKeeper watcher for the ZK cluster
121    * @param table name of the table to disable
122    * @throws KeeperException if an unexpected ZK connection issues occurs
123    */
124   private void disable(ZooKeeperWatcher zooKeeper, byte[] table) throws KeeperException {
125     // ensure the latest state of the archive node is found
126     zooKeeper.sync(archiveZnode);
127 
128     // if the top-level archive node is gone, then we are done
129     if (ZKUtil.checkExists(zooKeeper, archiveZnode) < 0) {
130       return;
131     }
132     // delete the table node, from the archive
133     String tableNode = this.getTableNode(table);
134     // make sure the table is the latest version so the delete takes
135     zooKeeper.sync(tableNode);
136 
137     LOG.debug("Attempting to delete table node:" + tableNode);
138     ZKUtil.deleteNodeRecursively(zooKeeper, tableNode);
139   }
140 
141   public void stop() {
142     if (!this.stopped) {
143       this.stopped = true;
144       LOG.debug("Stopping HFileArchiveManager...");
145       this.zooKeeper.close();
146     }
147   }
148 
149   /**
150    * Check to see if the table is currently marked for archiving
151    * @param table name of the table to check
152    * @return <tt>true</tt> if the archive znode for that table exists, <tt>false</tt> if not
153    * @throws KeeperException if an unexpected zookeeper error occurs
154    */
155   public boolean isArchivingEnabled(byte[] table) throws KeeperException {
156     String tableNode = this.getTableNode(table);
157     return ZKUtil.checkExists(zooKeeper, tableNode) >= 0;
158   }
159 
160   /**
161    * Get the zookeeper node associated with archiving the given table
162    * @param table name of the table to check
163    * @return znode for the table's archive status
164    */
165   private String getTableNode(byte[] table) {
166     return ZKUtil.joinZNode(archiveZnode, Bytes.toString(table));
167   }
168 }