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; 021import org.apache.hadoop.conf.Configuration; 022import org.apache.hadoop.hbase.ZooKeeperConnectionException; 023import org.apache.hadoop.hbase.client.Connection; 024import org.apache.hadoop.hbase.util.Bytes; 025import org.apache.hadoop.hbase.zookeeper.ZKUtil; 026import org.apache.hadoop.hbase.zookeeper.ZKWatcher; 027import org.apache.hadoop.hbase.zookeeper.ZNodePaths; 028import org.apache.yetus.audience.InterfaceAudience; 029import org.apache.zookeeper.KeeperException; 030import org.slf4j.Logger; 031import org.slf4j.LoggerFactory; 032 033/** 034 * Client-side manager for which table's hfiles should be preserved for long-term archive. 035 * @see ZKTableArchiveClient 036 * @see HFileArchiveTableMonitor 037 * @see LongTermArchivingHFileCleaner 038 */ 039@InterfaceAudience.Private 040class HFileArchiveManager { 041 042 private final String archiveZnode; 043 private static final Logger LOG = LoggerFactory.getLogger(HFileArchiveManager.class); 044 private final ZKWatcher zooKeeper; 045 private volatile boolean stopped = false; 046 047 public HFileArchiveManager(Connection connection, Configuration conf) 048 throws ZooKeeperConnectionException, IOException { 049 this.zooKeeper = 050 new ZKWatcher(conf, "hfileArchiveManager-on-" + connection.toString(), connection); 051 this.archiveZnode = 052 ZKTableArchiveClient.getArchiveZNode(this.zooKeeper.getConfiguration(), this.zooKeeper); 053 } 054 055 /** 056 * Turn on auto-backups of HFiles on the specified table. 057 * <p> 058 * When HFiles would be deleted from the hfile archive, they are instead preserved. 059 * @param table name of the table for which to preserve hfiles. 060 * @return <tt>this</tt> for chaining. 061 * @throws KeeperException if we can't reach zookeeper to update the hfile cleaner. 062 */ 063 public HFileArchiveManager enableHFileBackup(byte[] table) throws KeeperException { 064 enable(this.zooKeeper, table); 065 return this; 066 } 067 068 /** 069 * Stop retaining HFiles for the given table in the archive. HFiles will be cleaned up on the next 070 * pass of the {@link org.apache.hadoop.hbase.master.cleaner.HFileCleaner}, if the HFiles are 071 * retained by another cleaner. 072 * @param table name of the table for which to disable hfile retention. 073 * @return <tt>this</tt> for chaining. 074 * @throws KeeperException if if we can't reach zookeeper to update the hfile cleaner. 075 */ 076 public HFileArchiveManager disableHFileBackup(byte[] table) throws KeeperException { 077 disable(this.zooKeeper, table); 078 return this; 079 } 080 081 /** 082 * Disable long-term archival of all hfiles for all tables in the cluster. 083 * @return <tt>this</tt> for chaining. 084 * @throws IOException if the number of attempts is exceeded 085 */ 086 public HFileArchiveManager disableHFileBackup() throws IOException { 087 LOG.debug("Disabling backups on all tables."); 088 try { 089 ZKUtil.deleteNodeRecursively(this.zooKeeper, archiveZnode); 090 return this; 091 } catch (KeeperException e) { 092 throw new IOException("Unexpected ZK exception!", e); 093 } 094 } 095 096 /** 097 * Perform a best effort enable of hfile retention, which relies on zookeeper communicating the 098 * change back to the hfile cleaner. 099 * <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 if a ZooKeeper operation fails 105 */ 106 private void enable(ZKWatcher zooKeeper, byte[] table) 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(ZKWatcher zooKeeper, byte[] table) throws KeeperException { 125 // ensure the latest state of the archive node is found 126 zooKeeper.syncOrTimeout(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.syncOrTimeout(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 ZNodePaths.joinZNode(archiveZnode, Bytes.toString(table)); 167 } 168}