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.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(HConnection 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 }