Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.hadoop.hbase.backup.impl;
import java.io.Closeable;
import java.io.IOException;
import java.io.InterruptedIOException;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Objects;
import java.util.Set;
import java.util.TreeMap;
import java.util.TreeSet;
import java.util.stream.Collectors;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.hbase.Cell;
import org.apache.hadoop.hbase.CellUtil;
import org.apache.hadoop.hbase.HBaseConfiguration;
import org.apache.hadoop.hbase.NamespaceDescriptor;
import org.apache.hadoop.hbase.NamespaceExistException;
import org.apache.hadoop.hbase.ServerName;
import org.apache.hadoop.hbase.TableExistsException;
import org.apache.hadoop.hbase.TableName;
import org.apache.hadoop.hbase.backup.BackupInfo;
import org.apache.hadoop.hbase.backup.BackupInfo.BackupState;
import org.apache.hadoop.hbase.backup.BackupRestoreConstants;
import org.apache.hadoop.hbase.backup.BackupType;
import org.apache.hadoop.hbase.backup.util.BackupUtils;
import org.apache.hadoop.hbase.client.Admin;
import org.apache.hadoop.hbase.client.ColumnFamilyDescriptor;
import org.apache.hadoop.hbase.client.ColumnFamilyDescriptorBuilder;
import org.apache.hadoop.hbase.client.Connection;
import org.apache.hadoop.hbase.client.Delete;
import org.apache.hadoop.hbase.client.Get;
import org.apache.hadoop.hbase.client.Put;
import org.apache.hadoop.hbase.client.Result;
import org.apache.hadoop.hbase.client.ResultScanner;
import org.apache.hadoop.hbase.client.Scan;
import org.apache.hadoop.hbase.client.SnapshotDescription;
import org.apache.hadoop.hbase.client.Table;
import org.apache.hadoop.hbase.client.TableDescriptor;
import org.apache.hadoop.hbase.client.TableDescriptorBuilder;
import org.apache.hadoop.hbase.util.Bytes;
import org.apache.hadoop.hbase.util.EnvironmentEdgeManager;
import org.apache.hadoop.hbase.util.Pair;
import org.apache.yetus.audience.InterfaceAudience;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.apache.hbase.thirdparty.com.google.common.base.Splitter;
import org.apache.hbase.thirdparty.com.google.common.collect.Iterators;
import org.apache.hadoop.hbase.shaded.protobuf.generated.BackupProtos;
import org.apache.hadoop.hbase.shaded.protobuf.generated.HBaseProtos;
/**
* This class provides API to access backup system table
* Backup system table schema:
*
*
*
1. Backup sessions rowkey= "session:"+backupId; value =serialized BackupInfo
*
2. Backup start code rowkey = "startcode:"+backupRoot; value = startcode
*
3. Incremental backup set rowkey="incrbackupset:"+backupRoot; value=[list of tables]
*
4. Table-RS-timestamp map rowkey="trslm:"+backupRoot+table_name; value = map[RS-%3E last WAL
* timestamp]
*
5. RS - WAL ts map rowkey="rslogts:"+backupRoot +server; value = last WAL timestamp
*
6. WALs recorded rowkey="wals:"+WAL unique file name; value = backupId and full WAL file
* name
*
*
*/
@InterfaceAudience.Private
public final class BackupSystemTable implements Closeable {
private static final Logger LOG = LoggerFactory.getLogger(BackupSystemTable.class);
static class WALItem {
String backupId;
String walFile;
String backupRoot;
WALItem(String backupId, String walFile, String backupRoot) {
this.backupId = backupId;
this.walFile = walFile;
this.backupRoot = backupRoot;
}
public String getBackupId() {
return backupId;
}
public String getWalFile() {
return walFile;
}
public String getBackupRoot() {
return backupRoot;
}
@Override
public String toString() {
return Path.SEPARATOR + backupRoot + Path.SEPARATOR + backupId + Path.SEPARATOR + walFile;
}
}
/**
* Backup system table (main) name
*/
private TableName tableName;
/**
* Backup System table name for bulk loaded files. We keep all bulk loaded file references in a
* separate table because we have to isolate general backup operations: create, merge etc from
* activity of RegionObserver, which controls process of a bulk loading
* {@link org.apache.hadoop.hbase.backup.BackupObserver}
*/
private TableName bulkLoadTableName;
/**
* Stores backup sessions (contexts)
*/
final static byte[] SESSIONS_FAMILY = Bytes.toBytes("session");
/**
* Stores other meta
*/
final static byte[] META_FAMILY = Bytes.toBytes("meta");
final static byte[] BULK_LOAD_FAMILY = Bytes.toBytes("bulk");
/**
* Connection to HBase cluster, shared among all instances
*/
private final Connection connection;
private final static String BACKUP_INFO_PREFIX = "session:";
private final static String START_CODE_ROW = "startcode:";
private final static byte[] ACTIVE_SESSION_ROW = Bytes.toBytes("activesession:");
private final static byte[] ACTIVE_SESSION_COL = Bytes.toBytes("c");
private final static byte[] ACTIVE_SESSION_YES = Bytes.toBytes("yes");
private final static byte[] ACTIVE_SESSION_NO = Bytes.toBytes("no");
private final static String INCR_BACKUP_SET = "incrbackupset:";
private final static String TABLE_RS_LOG_MAP_PREFIX = "trslm:";
private final static String RS_LOG_TS_PREFIX = "rslogts:";
private final static String BULK_LOAD_PREFIX = "bulk:";
private final static byte[] BULK_LOAD_PREFIX_BYTES = Bytes.toBytes(BULK_LOAD_PREFIX);
private final static byte[] DELETE_OP_ROW = Bytes.toBytes("delete_op_row");
private final static byte[] MERGE_OP_ROW = Bytes.toBytes("merge_op_row");
final static byte[] TBL_COL = Bytes.toBytes("tbl");
final static byte[] FAM_COL = Bytes.toBytes("fam");
final static byte[] PATH_COL = Bytes.toBytes("path");
final static byte[] STATE_COL = Bytes.toBytes("state");
// the two states a bulk loaded file can be
final static byte[] BL_PREPARE = Bytes.toBytes("R");
final static byte[] BL_COMMIT = Bytes.toBytes("D");
private final static String SET_KEY_PREFIX = "backupset:";
// separator between BULK_LOAD_PREFIX and ordinals
private final static String BLK_LD_DELIM = ":";
private final static byte[] EMPTY_VALUE = new byte[] {};
// Safe delimiter in a string
private final static String NULL = "\u0000";
public BackupSystemTable(Connection conn) throws IOException {
this.connection = conn;
Configuration conf = this.connection.getConfiguration();
tableName = BackupSystemTable.getTableName(conf);
bulkLoadTableName = BackupSystemTable.getTableNameForBulkLoadedData(conf);
checkSystemTable();
}
private void checkSystemTable() throws IOException {
try (Admin admin = connection.getAdmin()) {
verifyNamespaceExists(admin);
Configuration conf = connection.getConfiguration();
if (!admin.tableExists(tableName)) {
TableDescriptor backupHTD = BackupSystemTable.getSystemTableDescriptor(conf);
createSystemTable(admin, backupHTD);
}
if (!admin.tableExists(bulkLoadTableName)) {
TableDescriptor blHTD = BackupSystemTable.getSystemTableForBulkLoadedDataDescriptor(conf);
createSystemTable(admin, blHTD);
}
waitForSystemTable(admin, tableName);
waitForSystemTable(admin, bulkLoadTableName);
}
}
private void createSystemTable(Admin admin, TableDescriptor descriptor) throws IOException {
try {
admin.createTable(descriptor);
} catch (TableExistsException e) {
// swallow because this class is initialized in concurrent environments (i.e. bulkloads),
// so may be subject to race conditions where one caller succeeds in creating the
// table and others fail because it now exists
LOG.debug("Table {} already exists, ignoring", descriptor.getTableName(), e);
}
}
private void verifyNamespaceExists(Admin admin) throws IOException {
String namespaceName = tableName.getNamespaceAsString();
NamespaceDescriptor ns = NamespaceDescriptor.create(namespaceName).build();
NamespaceDescriptor[] list = admin.listNamespaceDescriptors();
boolean exists = false;
for (NamespaceDescriptor nsd : list) {
if (nsd.getName().equals(ns.getName())) {
exists = true;
break;
}
}
if (!exists) {
try {
admin.createNamespace(ns);
} catch (NamespaceExistException e) {
// swallow because this class is initialized in concurrent environments (i.e. bulkloads),
// so may be subject to race conditions where one caller succeeds in creating the
// namespace and others fail because it now exists
LOG.debug("Namespace {} already exists, ignoring", ns.getName(), e);
}
}
}
private void waitForSystemTable(Admin admin, TableName tableName) throws IOException {
// Return fast if the table is available and avoid a log message
if (admin.tableExists(tableName) && admin.isTableAvailable(tableName)) {
return;
}
long TIMEOUT = 60000;
long startTime = EnvironmentEdgeManager.currentTime();
LOG.debug("Backup table {} is not present and available, waiting for it to become so",
tableName);
while (!admin.tableExists(tableName) || !admin.isTableAvailable(tableName)) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
throw (IOException) new InterruptedIOException().initCause(e);
}
if (EnvironmentEdgeManager.currentTime() - startTime > TIMEOUT) {
throw new IOException(
"Failed to create backup system table " + tableName + " after " + TIMEOUT + "ms");
}
}
LOG.debug("Backup table {} exists and available", tableName);
}
@Override
public void close() {
// do nothing
}
/**
* Updates status (state) of a backup session in backup system table table
* @param info backup info
* @throws IOException exception
*/
public void updateBackupInfo(BackupInfo info) throws IOException {
if (LOG.isTraceEnabled()) {
LOG.trace("update backup status in backup system table for: " + info.getBackupId()
+ " set status=" + info.getState());
}
try (Table table = connection.getTable(tableName)) {
Put put = createPutForBackupInfo(info);
table.put(put);
}
}
/*
* @param backupId the backup Id
* @return Map of rows to path of bulk loaded hfile
*/
Map readBulkLoadedFiles(String backupId) throws IOException {
Scan scan = BackupSystemTable.createScanForBulkLoadedFiles(backupId);
try (Table table = connection.getTable(bulkLoadTableName);
ResultScanner scanner = table.getScanner(scan)) {
Result res = null;
Map map = new TreeMap<>(Bytes.BYTES_COMPARATOR);
while ((res = scanner.next()) != null) {
res.advance();
byte[] row = CellUtil.cloneRow(res.listCells().get(0));
for (Cell cell : res.listCells()) {
if (
CellUtil.compareQualifiers(cell, BackupSystemTable.PATH_COL, 0,
BackupSystemTable.PATH_COL.length) == 0
) {
map.put(row, Bytes.toString(CellUtil.cloneValue(cell)));
}
}
}
return map;
}
}
/*
* Used during restore
* @param backupId the backup Id
* @param sTableList List of tables
* @return array of Map of family to List of Paths
*/
public Map>[] readBulkLoadedFiles(String backupId, List sTableList)
throws IOException {
Scan scan = BackupSystemTable.createScanForBulkLoadedFiles(backupId);
@SuppressWarnings("unchecked")
Map>[] mapForSrc = new Map[sTableList == null ? 1 : sTableList.size()];
try (Table table = connection.getTable(bulkLoadTableName);
ResultScanner scanner = table.getScanner(scan)) {
Result res = null;
while ((res = scanner.next()) != null) {
res.advance();
TableName tbl = null;
byte[] fam = null;
String path = null;
for (Cell cell : res.listCells()) {
if (
CellUtil.compareQualifiers(cell, BackupSystemTable.TBL_COL, 0,
BackupSystemTable.TBL_COL.length) == 0
) {
tbl = TableName.valueOf(CellUtil.cloneValue(cell));
} else if (
CellUtil.compareQualifiers(cell, BackupSystemTable.FAM_COL, 0,
BackupSystemTable.FAM_COL.length) == 0
) {
fam = CellUtil.cloneValue(cell);
} else if (
CellUtil.compareQualifiers(cell, BackupSystemTable.PATH_COL, 0,
BackupSystemTable.PATH_COL.length) == 0
) {
path = Bytes.toString(CellUtil.cloneValue(cell));
}
}
int srcIdx = IncrementalTableBackupClient.getIndex(tbl, sTableList);
if (srcIdx == -1) {
// the table is not among the query
continue;
}
if (mapForSrc[srcIdx] == null) {
mapForSrc[srcIdx] = new TreeMap<>(Bytes.BYTES_COMPARATOR);
}
List files;
if (!mapForSrc[srcIdx].containsKey(fam)) {
files = new ArrayList();
mapForSrc[srcIdx].put(fam, files);
} else {
files = mapForSrc[srcIdx].get(fam);
}
files.add(new Path(path));
if (LOG.isDebugEnabled()) {
LOG.debug("found bulk loaded file : " + tbl + " " + Bytes.toString(fam) + " " + path);
}
}
return mapForSrc;
}
}
/**
* Deletes backup status from backup system table table
* @param backupId backup id
* @throws IOException exception
*/
public void deleteBackupInfo(String backupId) throws IOException {
if (LOG.isTraceEnabled()) {
LOG.trace("delete backup status in backup system table for " + backupId);
}
try (Table table = connection.getTable(tableName)) {
Delete del = createDeleteForBackupInfo(backupId);
table.delete(del);
}
}
/*
* For postBulkLoadHFile() hook.
* @param tabName table name
* @param region the region receiving hfile
* @param finalPaths family and associated hfiles
*/
public void writePathsPostBulkLoad(TableName tabName, byte[] region,
Map> finalPaths) throws IOException {
if (LOG.isDebugEnabled()) {
LOG.debug("write bulk load descriptor to backup " + tabName + " with " + finalPaths.size()
+ " entries");
}
try (Table table = connection.getTable(bulkLoadTableName)) {
List puts = BackupSystemTable.createPutForCommittedBulkload(tabName, region, finalPaths);
table.put(puts);
LOG.debug("written " + puts.size() + " rows for bulk load of " + tabName);
}
}
/*
* For preCommitStoreFile() hook
* @param tabName table name
* @param region the region receiving hfile
* @param family column family
* @param pairs list of paths for hfiles
*/
public void writeFilesForBulkLoadPreCommit(TableName tabName, byte[] region, final byte[] family,
final List> pairs) throws IOException {
if (LOG.isDebugEnabled()) {
LOG.debug(
"write bulk load descriptor to backup " + tabName + " with " + pairs.size() + " entries");
}
try (Table table = connection.getTable(bulkLoadTableName)) {
List puts =
BackupSystemTable.createPutForPreparedBulkload(tabName, region, family, pairs);
table.put(puts);
LOG.debug("written " + puts.size() + " rows for bulk load of " + tabName);
}
}
/*
* Removes rows recording bulk loaded hfiles from backup table
* @param lst list of table names
* @param rows the rows to be deleted
*/
public void deleteBulkLoadedRows(List rows) throws IOException {
try (Table table = connection.getTable(bulkLoadTableName)) {
List lstDels = new ArrayList<>();
for (byte[] row : rows) {
Delete del = new Delete(row);
lstDels.add(del);
LOG.debug("orig deleting the row: " + Bytes.toString(row));
}
table.delete(lstDels);
LOG.debug("deleted " + rows.size() + " original bulkload rows");
}
}
/*
* Reads the rows from backup table recording bulk loaded hfiles
* @param tableList list of table names
* @return The keys of the Map are table, region and column family. Value of the map reflects
* whether the hfile was recorded by preCommitStoreFile hook (true)
*/
public Pair