001/** 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, software 013 * distributed under the License is distributed on an "AS IS" BASIS, 014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 015 * See the License for the specific language governing permissions and 016 * limitations under the License. 017 */ 018package org.apache.hadoop.hbase.backup.example; 019 020import java.io.IOException; 021 022import org.apache.hadoop.conf.Configuration; 023import org.apache.hadoop.hbase.ZooKeeperConnectionException; 024import org.apache.hadoop.hbase.zookeeper.ZKWatcher; 025import org.apache.yetus.audience.InterfaceAudience; 026import org.apache.hadoop.hbase.client.Connection; 027import org.apache.hadoop.hbase.util.Bytes; 028import org.apache.hadoop.hbase.zookeeper.ZKUtil; 029import org.apache.hadoop.hbase.zookeeper.ZNodePaths; 030import org.apache.zookeeper.KeeperException; 031import org.slf4j.Logger; 032import org.slf4j.LoggerFactory; 033 034/** 035 * Client-side manager for which table's hfiles should be preserved for long-term archive. 036 * @see ZKTableArchiveClient 037 * @see HFileArchiveTableMonitor 038 * @see LongTermArchivingHFileCleaner 039 */ 040@InterfaceAudience.Private 041class HFileArchiveManager { 042 043 private final String archiveZnode; 044 private static final Logger LOG = LoggerFactory.getLogger(HFileArchiveManager.class); 045 private final ZKWatcher zooKeeper; 046 private volatile boolean stopped = false; 047 048 public HFileArchiveManager(Connection connection, Configuration conf) 049 throws ZooKeeperConnectionException, IOException { 050 this.zooKeeper = new ZKWatcher(conf, "hfileArchiveManager-on-" + connection.toString(), 051 connection); 052 this.archiveZnode = ZKTableArchiveClient.getArchiveZNode(this.zooKeeper.getConfiguration(), 053 this.zooKeeper); 054 } 055 056 /** 057 * Turn on auto-backups of HFiles on the specified table. 058 * <p> 059 * When HFiles would be deleted from the hfile archive, they are instead preserved. 060 * @param table name of the table for which to preserve hfiles. 061 * @return <tt>this</tt> for chaining. 062 * @throws KeeperException if we can't reach zookeeper to update the hfile cleaner. 063 */ 064 public HFileArchiveManager enableHFileBackup(byte[] table) throws KeeperException { 065 enable(this.zooKeeper, table); 066 return this; 067 } 068 069 /** 070 * Stop retaining HFiles for the given table in the archive. HFiles will be cleaned up on the next 071 * pass of the {@link org.apache.hadoop.hbase.master.cleaner.HFileCleaner}, if the HFiles are retained by another 072 * cleaner. 073 * @param table name of the table for which to disable hfile retention. 074 * @return <tt>this</tt> for chaining. 075 * @throws KeeperException if if we can't reach zookeeper to update the hfile cleaner. 076 */ 077 public HFileArchiveManager disableHFileBackup(byte[] table) throws KeeperException { 078 disable(this.zooKeeper, table); 079 return this; 080 } 081 082 /** 083 * Disable long-term archival of all hfiles for all tables in the cluster. 084 * @return <tt>this</tt> for chaining. 085 * @throws IOException if the number of attempts is exceeded 086 */ 087 public HFileArchiveManager disableHFileBackup() throws IOException { 088 LOG.debug("Disabling backups on all tables."); 089 try { 090 ZKUtil.deleteNodeRecursively(this.zooKeeper, archiveZnode); 091 return this; 092 } catch (KeeperException e) { 093 throw new IOException("Unexpected ZK exception!", e); 094 } 095 } 096 097 /** 098 * Perform a best effort enable of hfile retention, which relies on zookeeper communicating the // 099 * * change back to the hfile cleaner. 100 * <p> 101 * No attempt is made to make sure that backups are successfully created - it is inherently an 102 * <b>asynchronous operation</b>. 103 * @param zooKeeper watcher connection to zk cluster 104 * @param table table name on which to enable archiving 105 * @throws KeeperException 106 */ 107 private void enable(ZKWatcher zooKeeper, byte[] table) 108 throws KeeperException { 109 LOG.debug("Ensuring archiving znode exists"); 110 ZKUtil.createAndFailSilent(zooKeeper, archiveZnode); 111 112 // then add the table to the list of znodes to archive 113 String tableNode = this.getTableNode(table); 114 LOG.debug("Creating: " + tableNode + ", data: []"); 115 ZKUtil.createSetData(zooKeeper, tableNode, new byte[0]); 116 } 117 118 /** 119 * Disable all archiving of files for a given table 120 * <p> 121 * Inherently an <b>asynchronous operation</b>. 122 * @param zooKeeper watcher for the ZK cluster 123 * @param table name of the table to disable 124 * @throws KeeperException if an unexpected ZK connection issues occurs 125 */ 126 private void disable(ZKWatcher zooKeeper, byte[] table) throws KeeperException { 127 // ensure the latest state of the archive node is found 128 zooKeeper.sync(archiveZnode); 129 130 // if the top-level archive node is gone, then we are done 131 if (ZKUtil.checkExists(zooKeeper, archiveZnode) < 0) { 132 return; 133 } 134 // delete the table node, from the archive 135 String tableNode = this.getTableNode(table); 136 // make sure the table is the latest version so the delete takes 137 zooKeeper.sync(tableNode); 138 139 LOG.debug("Attempting to delete table node:" + tableNode); 140 ZKUtil.deleteNodeRecursively(zooKeeper, tableNode); 141 } 142 143 public void stop() { 144 if (!this.stopped) { 145 this.stopped = true; 146 LOG.debug("Stopping HFileArchiveManager..."); 147 this.zooKeeper.close(); 148 } 149 } 150 151 /** 152 * Check to see if the table is currently marked for archiving 153 * @param table name of the table to check 154 * @return <tt>true</tt> if the archive znode for that table exists, <tt>false</tt> if not 155 * @throws KeeperException if an unexpected zookeeper error occurs 156 */ 157 public boolean isArchivingEnabled(byte[] table) throws KeeperException { 158 String tableNode = this.getTableNode(table); 159 return ZKUtil.checkExists(zooKeeper, tableNode) >= 0; 160 } 161 162 /** 163 * Get the zookeeper node associated with archiving the given table 164 * @param table name of the table to check 165 * @return znode for the table's archive status 166 */ 167 private String getTableNode(byte[] table) { 168 return ZNodePaths.joinZNode(archiveZnode, Bytes.toString(table)); 169 } 170}