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}