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.client;
19  
20  import java.io.IOException;
21  import java.util.ArrayList;
22  import java.util.List;
23  import java.util.Map;
24  import java.util.concurrent.Future;
25  
26  import org.apache.commons.lang.StringUtils;
27  import org.apache.commons.logging.Log;
28  import org.apache.commons.logging.LogFactory;
29  import org.apache.hadoop.fs.FileSystem;
30  import org.apache.hadoop.fs.Path;
31  import org.apache.hadoop.hbase.TableName;
32  import org.apache.hadoop.hbase.backup.BackupInfo;
33  import org.apache.hadoop.hbase.backup.BackupInfo.BackupState;
34  import org.apache.hadoop.hbase.backup.BackupRequest;
35  import org.apache.hadoop.hbase.backup.BackupRestoreClientFactory;
36  import org.apache.hadoop.hbase.backup.RestoreClient;
37  import org.apache.hadoop.hbase.backup.RestoreRequest;
38  import org.apache.hadoop.hbase.backup.impl.BackupSystemTable;
39  import org.apache.hadoop.hbase.backup.util.BackupClientUtil;
40  import org.apache.hadoop.hbase.backup.util.BackupSet;
41  import org.apache.hadoop.hbase.classification.InterfaceAudience;
42  import org.apache.hadoop.hbase.classification.InterfaceStability;
43  
44  /**
45   * The administrative API implementation for HBase Backup . Obtain an instance from 
46   * an {@link Admin#getBackupAdmin()} and call {@link #close()} afterwards.
47   * <p>BackupAdmin can be used to create backups, restore data from backups and for 
48   * other backup-related operations. 
49   *
50   * @see Admin
51   * @since 2.0
52   */
53  @InterfaceAudience.Private
54  @InterfaceStability.Evolving
55  
56  public class HBaseBackupAdmin implements BackupAdmin {
57    private static final Log LOG = LogFactory.getLog(HBaseBackupAdmin.class);
58  
59    private final HBaseAdmin admin;
60    private final Connection conn;
61    
62    HBaseBackupAdmin(HBaseAdmin admin) {
63      this.admin = admin;
64      this.conn = admin.getConnection();
65    }
66      
67    
68    @Override
69    public void close() throws IOException {
70    }
71  
72    @Override
73    public BackupInfo getBackupInfo(String backupId) throws IOException {    
74      BackupInfo backupInfo = null;
75      try (final BackupSystemTable table = new BackupSystemTable(conn)) {
76        backupInfo = table.readBackupInfo(backupId);
77        return backupInfo;
78      }   
79    }
80  
81    @Override
82    public int getProgress(String backupId) throws IOException {
83      BackupInfo backupInfo = null;
84      try (final BackupSystemTable table = new BackupSystemTable(conn)) {
85        if (backupId == null) {
86          ArrayList<BackupInfo> recentSessions =
87              table.getBackupContexts(BackupState.RUNNING);
88          if (recentSessions.isEmpty()) {
89            LOG.warn("No ongoing sessions found.");
90            return -1;
91          }
92          // else show status for ongoing session
93          // must be one maximum
94          return recentSessions.get(0).getProgress();
95        } else {
96  
97          backupInfo = table.readBackupInfo(backupId);
98          if (backupInfo != null) {
99            return backupInfo.getProgress();
100         } else {
101           LOG.warn("No information found for backupID=" + backupId);
102           return -1;
103         }
104       }
105     }  
106   }
107 
108   @Override
109   public int deleteBackups(String[] backupIds) throws IOException {
110     BackupInfo backupInfo = null;
111     String backupId = null;
112     int totalDeleted = 0;
113     try (final BackupSystemTable table = new BackupSystemTable(conn)) {
114       for (int i = 0; i < backupIds.length; i++) {
115         backupId = backupIds[i];
116         LOG.info("Deleting backup for backupID=" + backupId + " ...");
117         backupInfo = table.readBackupInfo(backupId);
118         if (backupInfo != null) {
119           BackupClientUtil.cleanupBackupData(backupInfo, admin.getConfiguration());
120 
121           Map<byte[], String> map = table.readBulkLoadedFiles(backupId);
122           FileSystem fs = FileSystem.get(conn.getConfiguration());
123           boolean succ = true;
124           int numDeleted = 0;
125           for (String f : map.values()) {
126             Path p = new Path(f);
127             try {
128               if (!fs.delete(p)) {
129                 if (fs.exists(p)) {
130                   LOG.warn(f + " was not deleted");
131                   succ = false;
132                 }
133               } else {
134                 numDeleted++;
135               }
136             } catch (IOException ioe) {
137               LOG.warn(f + " was not deleted", ioe);
138               succ = false;
139             }
140           }
141           LOG.debug(numDeleted + " bulk loaded files out of " + map.size() + " were deleted");
142           if (succ) {
143             table.deleteBulkLoadedFiles(map);
144           }
145           table.deleteBackupInfo(backupInfo.getBackupId());
146           LOG.info("Delete backup for backupID=" + backupId + " completed.");
147           totalDeleted++;
148         } else {
149           LOG.warn("Delete backup failed: no information found for backupID=" + backupId);
150         }
151       }
152     }
153     return totalDeleted;
154   }
155 
156   @Override
157   public List<BackupInfo> getHistory(int n) throws IOException {
158     try (final BackupSystemTable table = new BackupSystemTable(conn)) {
159       List<BackupInfo> history = table.getBackupHistory();
160       if( history.size() <= n) return history;
161       List<BackupInfo> list = new ArrayList<BackupInfo>();
162       for(int i=0; i < n; i++){
163         list.add(history.get(i));
164       }
165       return list;
166     }  
167   }
168 
169   @Override
170   public List<BackupSet> listBackupSets() throws IOException {
171     try (final BackupSystemTable table = new BackupSystemTable(conn)) {
172       List<String> list = table.listBackupSets();
173       List<BackupSet> bslist = new ArrayList<BackupSet>();
174       for (String s : list) {
175         List<TableName> tables = table.describeBackupSet(s);
176         if(tables != null){
177           bslist.add( new BackupSet(s, tables));
178         }
179       }
180       return bslist;
181     }
182   }
183 
184   @Override
185   public BackupSet getBackupSet(String name) throws IOException {
186     try (final BackupSystemTable table = new BackupSystemTable(conn)) {
187       List<TableName> list = table.describeBackupSet(name);
188       if(list == null) return null;
189       return new BackupSet(name, list);
190     }  
191   }
192 
193   @Override
194   public boolean deleteBackupSet(String name) throws IOException {
195     try (final BackupSystemTable table = new BackupSystemTable(conn)) {
196       if(table.describeBackupSet(name) == null) {
197         return false;
198       }
199       table.deleteBackupSet(name);
200       return true;
201     }  
202   }
203 
204   @Override
205   public void addToBackupSet(String name, TableName[] tables) throws IOException {
206     String[] tableNames = new String[tables.length];
207     for(int i = 0; i < tables.length; i++){
208       tableNames[i] = tables[i].getNameAsString();
209       if (!admin.tableExists(tableNames[i])) {
210         throw new IOException("Cannot add " + tableNames[i] + " because it doesn't exist");
211       }
212     }
213     try (final BackupSystemTable table = new BackupSystemTable(conn)) {
214       table.addToBackupSet(name, tableNames);      
215       LOG.info("Added tables ["+StringUtils.join(tableNames, " ")+"] to '" + name + "' backup set");
216     }  
217   }
218 
219   @Override
220   public void removeFromBackupSet(String name, String[] tables) throws IOException {
221     LOG.info("Removing tables ["+ StringUtils.join(tables, " ")+"] from '" + name + "'");
222     try (final BackupSystemTable table = new BackupSystemTable(conn)) {      
223       table.removeFromBackupSet(name, tables);
224       LOG.info("Removing tables ["+ StringUtils.join(tables, " ")+"] from '" + name + "' completed.");
225     }   
226   }
227 
228   @Override
229   public void restore(RestoreRequest request) throws IOException {
230     RestoreClient client = BackupRestoreClientFactory.getRestoreClient(admin.getConfiguration());
231     client.restore(request.getBackupRootDir(), 
232                    request.getBackupId(), 
233                    request.isCheck(), 
234                    request.getFromTables(), 
235                    request.getToTables(), 
236                    request.isOverwrite());
237     
238   }
239 
240   @Override
241   public String backupTables(final BackupRequest userRequest) 
242       throws IOException {
243    return admin.backupTables(userRequest);
244   }
245   
246   
247   @Override
248   public Future<String> backupTablesAsync(final BackupRequest userRequest) 
249       throws IOException {
250     return admin.backupTablesAsync(userRequest);
251   }
252   
253   
254 }