use of org.apache.hadoop.hive.ql.parse.repl.load.FailoverMetaData in project hive by apache.
the class TestReplicationScenariosAcidTables method testFailoverFailureBeforeReverseReplication.
@Test
public void testFailoverFailureBeforeReverseReplication() throws Throwable {
List<String> failoverConfigs = Arrays.asList("'" + HiveConf.ConfVars.HIVE_REPL_FAILOVER_START + "'='true'", "'" + HiveConf.ConfVars.REPL_RETAIN_PREV_DUMP_DIR + "'='true'", "'" + HiveConf.ConfVars.REPL_RETAIN_PREV_DUMP_DIR_COUNT + "'='1'");
List<String> retainPrevDumpDir = Arrays.asList("'" + HiveConf.ConfVars.REPL_RETAIN_PREV_DUMP_DIR + "'='true'", "'" + HiveConf.ConfVars.REPL_RETAIN_PREV_DUMP_DIR_COUNT + "'='1'");
WarehouseInstance.Tuple dumpData = primary.run("use " + primaryDbName).run("create table t1 (id int) clustered by(id) into 3 buckets stored as orc " + "tblproperties (\"transactional\"=\"true\")").run("create table t2 (rank int) partitioned by (name string) tblproperties(\"transactional\"=\"true\", " + "\"transactional_properties\"=\"insert_only\")").dump(primaryDbName, failoverConfigs);
// This dump is not failover ready as target db can be used for replication only after first incremental load.
FileSystem fs = new Path(dumpData.dumpLocation).getFileSystem(conf);
Path dumpPath = new Path(dumpData.dumpLocation, ReplUtils.REPL_HIVE_BASE_DIR);
assertFalse(fs.exists(new Path(dumpPath, FailoverMetaData.FAILOVER_METADATA)));
assertFalse(fs.exists(new Path(dumpPath, ReplAck.FAILOVER_READY_MARKER.toString())));
assertFalse(MetaStoreUtils.isDbBeingFailedOver(primary.getDatabase(primaryDbName)));
replica.load(replicatedDbName, primaryDbName).run("use " + replicatedDbName).run("show tables").verifyResults(new String[] { "t1", "t2" }).run("repl status " + replicatedDbName).verifyResult(dumpData.lastReplicationId);
assertTrue(MetaStoreUtils.isTargetOfReplication(replica.getDatabase(replicatedDbName)));
dumpData = primary.run("use " + primaryDbName).run("insert into t1 values(1)").run("insert into t2 partition(name='Bob') values(11)").dump(primaryDbName, failoverConfigs);
dumpPath = new Path(dumpData.dumpLocation, ReplUtils.REPL_HIVE_BASE_DIR);
Path dumpAckFile = new Path(dumpPath, DUMP_ACKNOWLEDGEMENT.toString());
Path failoverMdFile = new Path(dumpPath, FailoverMetaData.FAILOVER_METADATA);
assertTrue(fs.exists(dumpAckFile));
assertTrue(fs.exists(failoverMdFile));
assertTrue(fs.exists(new Path(dumpPath, ReplAck.FAILOVER_READY_MARKER.toString())));
assertTrue(MetaStoreUtils.isDbBeingFailedOverAtEndpoint(primary.getDatabase(primaryDbName), MetaStoreUtils.FailoverEndpoint.SOURCE));
FailoverMetaData previousFmd = new FailoverMetaData(dumpPath, conf);
Long failoverEventId = previousFmd.getFailoverEventId();
assertTrue(failoverEventId >= Long.parseLong(dumpData.lastReplicationId));
Long failoverMdModifTime = fs.getFileStatus(failoverMdFile).getModificationTime();
fs.delete(dumpAckFile, false);
dumpData = primary.run("use " + primaryDbName).run("insert into t2 partition(name='Carl') values(10)").run("create table t3 (id int)").run("insert into t3 values (2)").dump(primaryDbName, failoverConfigs);
dumpPath = new Path(dumpData.dumpLocation, ReplUtils.REPL_HIVE_BASE_DIR);
failoverMdFile = new Path(dumpPath, FailoverMetaData.FAILOVER_METADATA);
assertTrue(fs.exists(new Path(dumpPath, DUMP_ACKNOWLEDGEMENT.toString())));
assertTrue(fs.exists(failoverMdFile));
Assert.assertEquals(failoverMdModifTime, (Long) fs.getFileStatus(failoverMdFile).getModificationTime());
assertTrue(fs.exists(new Path(dumpPath, ReplAck.FAILOVER_READY_MARKER.toString())));
assertTrue(MetaStoreUtils.isDbBeingFailedOverAtEndpoint(primary.getDatabase(primaryDbName), MetaStoreUtils.FailoverEndpoint.SOURCE));
assertTrue(failoverEventId >= Long.parseLong(dumpData.lastReplicationId));
FailoverMetaData currentFmd = new FailoverMetaData(dumpPath, conf);
assertTrue(currentFmd.equals(previousFmd));
replica.load(replicatedDbName, primaryDbName, failoverConfigs).run("use " + replicatedDbName).run("show tables").verifyResults(new String[] { "t1", "t2" }).run("repl status " + replicatedDbName).verifyResult(dumpData.lastReplicationId).run("select id from t1").verifyResults(new String[] { "1" }).run("select rank from t2 order by rank").verifyResults(new String[] { "11" });
Database db = replica.getDatabase(replicatedDbName);
assertTrue(MetaStoreUtils.isTargetOfReplication(db));
assertTrue(MetaStoreUtils.isDbBeingFailedOverAtEndpoint(db, MetaStoreUtils.FailoverEndpoint.TARGET));
assertTrue(fs.exists(new Path(dumpPath, ReplAck.LOAD_ACKNOWLEDGEMENT.toString())));
primary.run("drop database if exists " + primaryDbName + " cascade");
WarehouseInstance.Tuple reverseDumpData = replica.run("use " + replicatedDbName).run("insert into t2 partition(name='Carl') values(12)").run("create table t3 (id int)").run("insert into t3 values (10)").dump(replicatedDbName, retainPrevDumpDir);
assertNotEquals(reverseDumpData.dumpLocation, dumpData.dumpLocation);
assertTrue(fs.exists(dumpPath));
assertTrue(fs.exists(new Path(dumpPath, ReplAck.FAILOVER_READY_MARKER.toString())));
dumpPath = new Path(reverseDumpData.dumpLocation, ReplUtils.REPL_HIVE_BASE_DIR);
dumpAckFile = new Path(dumpPath, DUMP_ACKNOWLEDGEMENT.toString());
assertTrue(fs.exists(dumpAckFile));
assertFalse(fs.exists(new Path(dumpPath, ReplAck.FAILOVER_READY_MARKER.toString())));
assertTrue(new DumpMetaData(dumpPath, conf).getDumpType() == DumpType.BOOTSTRAP);
db = replica.getDatabase(replicatedDbName);
assertTrue(MetaStoreUtils.isDbBeingFailedOverAtEndpoint(db, MetaStoreUtils.FailoverEndpoint.TARGET));
assertFalse(MetaStoreUtils.isTargetOfReplication(db));
primary.load(primaryDbName, replicatedDbName).run("use " + primaryDbName).run("show tables").verifyResults(new String[] { "t1", "t2", "t3" }).run("repl status " + primaryDbName).verifyResult(reverseDumpData.lastReplicationId).run("select id from t1").verifyResults(new String[] { "1" }).run("select rank from t2 order by rank").verifyResults(new String[] { "11", "12" }).run("select id from t3").verifyResults(new String[] { "10" });
assertTrue(fs.exists(new Path(dumpPath, LOAD_ACKNOWLEDGEMENT.toString())));
reverseDumpData = replica.run("insert into t3 values (15)").dump(replicatedDbName, retainPrevDumpDir);
dumpPath = new Path(reverseDumpData.dumpLocation, ReplUtils.REPL_HIVE_BASE_DIR);
fs.exists(new Path(dumpPath, DUMP_ACKNOWLEDGEMENT.toString()));
assertFalse(MetaStoreUtils.isDbBeingFailedOver(replica.getDatabase(replicatedDbName)));
primary.load(primaryDbName, replicatedDbName).run("select id from t3").verifyResults(new String[] { "10", "15" });
;
assertTrue(fs.exists(new Path(dumpPath, LOAD_ACKNOWLEDGEMENT.toString())));
}
use of org.apache.hadoop.hive.ql.parse.repl.load.FailoverMetaData in project hive by apache.
the class TestReplicationScenariosAcidTables method testCompleteFailoverWithReverseBootstrap.
@Test
public void testCompleteFailoverWithReverseBootstrap() throws Throwable {
HiveConf primaryConf = primary.getConf();
TxnStore txnHandler = TxnUtils.getTxnStore(primary.getConf());
List<String> failoverConfigs = Arrays.asList("'" + HiveConf.ConfVars.HIVE_REPL_FAILOVER_START + "'='true'");
WarehouseInstance.Tuple dumpData = primary.run("use " + primaryDbName).run("create table t1 (id int) clustered by(id) into 3 buckets stored as orc " + "tblproperties (\"transactional\"=\"true\")").run("create table t2 (rank int) partitioned by (name string) tblproperties(\"transactional\"=\"true\", " + "\"transactional_properties\"=\"insert_only\")").dump(primaryDbName, failoverConfigs);
// This dump is not failover ready as target db can be used for replication only after first incremental load.
FileSystem fs = new Path(dumpData.dumpLocation).getFileSystem(conf);
Path dumpPath = new Path(dumpData.dumpLocation, ReplUtils.REPL_HIVE_BASE_DIR);
assertFalse(fs.exists(new Path(dumpPath, ReplAck.FAILOVER_READY_MARKER.toString())));
assertFalse(MetaStoreUtils.isDbBeingFailedOver(primary.getDatabase(primaryDbName)));
replica.load(replicatedDbName, primaryDbName, failoverConfigs).run("use " + replicatedDbName).run("show tables").verifyResults(new String[] { "t1", "t2" }).run("repl status " + replicatedDbName).verifyResult(dumpData.lastReplicationId);
Database db = replica.getDatabase(replicatedDbName);
assertTrue(MetaStoreUtils.isTargetOfReplication(db));
assertFalse(MetaStoreUtils.isDbBeingFailedOver(db));
primary.run("use " + primaryDbName).run("insert into t1 values(1)").run("insert into t2 partition(name='Bob') values(11)").run("insert into t2 partition(name='Carl') values(10)");
/**
*Open transactions can be of two types:
* Case 1) Txns that have not acquired HIVE LOCKS or they belong to different db: These txns would be captured in
* _failovermetadata file inside dump directory.
* Case 2) Txns that have acquired HIVE LOCKS and belong to db under replication: These txns would be aborted by hive
* as part of dump operation.
*/
// Open 3 txns for Database which is not under replication
int numTxnsForSecDb = 3;
List<Long> txnsForSecDb = openTxns(numTxnsForSecDb, txnHandler, primaryConf);
// Allocate write ids for both tables of secondary db for 3 txns
// t1=5 and t2=5
Map<String, Long> tablesInSecDb = new HashMap<>();
tablesInSecDb.put("t1", (long) numTxnsForSecDb);
tablesInSecDb.put("t2", (long) numTxnsForSecDb);
List<Long> lockIdsForSecDb = allocateWriteIdsForTablesAndAcquireLocks(primaryDbName + "_extra", tablesInSecDb, txnHandler, txnsForSecDb, primaryConf);
// Open 2 txns for Primary Db
int numTxnsForPrimaryDb = 2;
List<Long> txnsForPrimaryDb = openTxns(numTxnsForPrimaryDb, txnHandler, primaryConf);
// Allocate write ids for both tables of primary db for 2 txns
// t1=5 and t2=5
Map<String, Long> tablesInPrimaryDb = new HashMap<>();
tablesInPrimaryDb.put("t1", (long) numTxnsForPrimaryDb + 1);
tablesInPrimaryDb.put("t2", (long) numTxnsForPrimaryDb + 2);
List<Long> lockIdsForPrimaryDb = allocateWriteIdsForTablesAndAcquireLocks(primaryDbName, tablesInPrimaryDb, txnHandler, txnsForPrimaryDb, primaryConf);
// Open 1 txn with no hive locks acquired
List<Long> txnsWithNoLocks = openTxns(1, txnHandler, primaryConf);
dumpData = primary.dump(primaryDbName, failoverConfigs);
dumpPath = new Path(dumpData.dumpLocation, ReplUtils.REPL_HIVE_BASE_DIR);
assertTrue(fs.exists(new Path(dumpPath, DUMP_ACKNOWLEDGEMENT.toString())));
assertTrue(fs.exists(new Path(dumpPath, FailoverMetaData.FAILOVER_METADATA)));
assertTrue(fs.exists(new Path(dumpPath, ReplAck.FAILOVER_READY_MARKER.toString())));
assertTrue(MetaStoreUtils.isDbBeingFailedOverAtEndpoint(primary.getDatabase(primaryDbName), MetaStoreUtils.FailoverEndpoint.SOURCE));
FailoverMetaData failoverMD = new FailoverMetaData(dumpPath, conf);
List<Long> openTxns = failoverMD.getOpenTxns();
List<Long> txnsAborted = failoverMD.getAbortedTxns();
assertTrue(txnsAborted.size() == 2);
assertTrue(txnsAborted.containsAll(txnsForPrimaryDb));
assertTrue(openTxns.size() == 4);
assertTrue(openTxns.containsAll(txnsForSecDb));
assertTrue(openTxns.containsAll(txnsWithNoLocks));
assertTrue(failoverMD.getTxnsWithoutLock().equals(txnsWithNoLocks));
// TxnsForPrimaryDb and txnsWithNoLocks would have been aborted by dump operation.
verifyAllOpenTxnsAborted(txnsForPrimaryDb, primaryConf);
verifyAllOpenTxnsNotAborted(txnsForSecDb, primaryConf);
verifyAllOpenTxnsNotAborted(txnsWithNoLocks, primaryConf);
// Abort the txns
txnHandler.abortTxns(new AbortTxnsRequest(txnsForSecDb));
txnHandler.abortTxns(new AbortTxnsRequest(txnsWithNoLocks));
verifyAllOpenTxnsAborted(txnsForSecDb, primaryConf);
verifyAllOpenTxnsAborted(txnsWithNoLocks, primaryConf);
releaseLocks(txnHandler, lockIdsForSecDb);
replica.load(replicatedDbName, primaryDbName, failoverConfigs).run("use " + replicatedDbName).run("show tables").verifyResults(new String[] { "t1", "t2" }).run("repl status " + replicatedDbName).verifyResult(dumpData.lastReplicationId).run("select id from t1").verifyResults(new String[] { "1" }).run("select rank from t2 order by rank").verifyResults(new String[] { "10", "11" });
db = replica.getDatabase(replicatedDbName);
assertTrue(MetaStoreUtils.isTargetOfReplication(db));
assertTrue(MetaStoreUtils.isDbBeingFailedOverAtEndpoint(db, MetaStoreUtils.FailoverEndpoint.TARGET));
assertTrue(fs.exists(new Path(dumpPath, ReplAck.LOAD_ACKNOWLEDGEMENT.toString())));
Path dbRootDir = new Path(dumpData.dumpLocation).getParent();
long prevDumpDirModifTime = getLatestDumpDirModifTime(dbRootDir);
primary.run("REPL DUMP " + primaryDbName + " with ('" + HiveConf.ConfVars.HIVE_REPL_FAILOVER_START + "' = 'true')");
Assert.assertEquals(dumpData.dumpLocation, ReplUtils.getLatestDumpPath(dbRootDir, conf).toString());
Assert.assertEquals(prevDumpDirModifTime, getLatestDumpDirModifTime(dbRootDir));
dumpPath = new Path(dumpData.dumpLocation, ReplUtils.REPL_HIVE_BASE_DIR);
assertTrue(fs.exists(new Path(dumpPath, ReplAck.LOAD_ACKNOWLEDGEMENT.toString())));
assertTrue(MetaStoreUtils.isDbBeingFailedOverAtEndpoint(primary.getDatabase(primaryDbName), MetaStoreUtils.FailoverEndpoint.SOURCE));
primary.run("drop database if exists " + primaryDbName + " cascade");
assertTrue(primary.getDatabase(primaryDbName) == null);
assertFalse(ReplChangeManager.isSourceOfReplication(replica.getDatabase(replicatedDbName)));
WarehouseInstance.Tuple reverseDumpData = replica.run("create table t3 (id int)").run("insert into t2 partition(name='Bob') values(20)").run("insert into t3 values (2)").dump(replicatedDbName);
assertNotEquals(reverseDumpData.dumpLocation, dumpData.dumpLocation);
assertTrue(fs.exists(new Path(dumpPath, ReplAck.FAILOVER_READY_MARKER.toString())));
dumpPath = new Path(reverseDumpData.dumpLocation, ReplUtils.REPL_HIVE_BASE_DIR);
assertFalse(fs.exists(new Path(dumpPath, ReplAck.FAILOVER_READY_MARKER.toString())));
assertTrue(new DumpMetaData(dumpPath, conf).getDumpType() == DumpType.BOOTSTRAP);
assertTrue(fs.exists(new Path(dumpPath, DUMP_ACKNOWLEDGEMENT.toString())));
db = replica.getDatabase(replicatedDbName);
assertTrue(MetaStoreUtils.isDbBeingFailedOverAtEndpoint(db, MetaStoreUtils.FailoverEndpoint.TARGET));
assertFalse(MetaStoreUtils.isTargetOfReplication(db));
primary.load(primaryDbName, replicatedDbName).run("use " + primaryDbName).run("show tables").verifyResults(new String[] { "t1", "t2", "t3" }).run("repl status " + primaryDbName).verifyResult(reverseDumpData.lastReplicationId).run("select id from t1").verifyResults(new String[] { "1" }).run("select rank from t2 order by rank").verifyResults(new String[] { "10", "11", "20" }).run("select id from t3").verifyResults(new String[] { "2" });
Database primaryDb = primary.getDatabase(primaryDbName);
assertFalse(primaryDb == null);
assertTrue(ReplUtils.isFirstIncPending(primaryDb.getParameters()));
assertTrue(MetaStoreUtils.isTargetOfReplication(primaryDb));
assertFalse(MetaStoreUtils.isDbBeingFailedOver(primaryDb));
assertTrue(fs.exists(new Path(dumpPath, LOAD_ACKNOWLEDGEMENT.toString())));
assertFalse(ReplChangeManager.isSourceOfReplication(primaryDb));
assertTrue(ReplChangeManager.isSourceOfReplication(replica.getDatabase(replicatedDbName)));
reverseDumpData = replica.run("insert into t3 values (3)").run("insert into t2 partition(name='Bob') values(30)").dump(replicatedDbName);
assertFalse(MetaStoreUtils.isDbBeingFailedOver(replica.getDatabase(replicatedDbName)));
primary.load(primaryDbName, replicatedDbName).run("select rank from t2 order by rank").verifyResults(new String[] { "10", "11", "20", "30" }).run("select id from t3").verifyResults(new String[] { "2", "3" }).run("repl status " + primaryDbName).verifyResult(reverseDumpData.lastReplicationId);
assertFalse(ReplUtils.isFirstIncPending(primary.getDatabase(primaryDbName).getParameters()));
}
use of org.apache.hadoop.hive.ql.parse.repl.load.FailoverMetaData in project hive by apache.
the class ReplDumpTask method fetchFailoverMetadata.
private void fetchFailoverMetadata(Hive hiveDb) throws HiveException, IOException, TException {
Path hiveDumpDir = new Path(work.getCurrentDumpPath(), ReplUtils.REPL_HIVE_BASE_DIR);
FailoverMetaData fmd = new FailoverMetaData(hiveDumpDir, conf);
FileSystem fs = hiveDumpDir.getFileSystem(conf);
if (fs.exists(new Path(hiveDumpDir, FailoverMetaData.FAILOVER_METADATA)) && fmd.isValidMetadata()) {
work.setFailoverMetadata(fmd);
return;
}
List<Long> txnsForDb = getOpenTxns(getTxnMgr().getValidTxns(excludedTxns), work.dbNameOrPattern);
if (!txnsForDb.isEmpty()) {
LOG.debug("Going to abort transactions: {} for database: {}.", txnsForDb, work.dbNameOrPattern);
hiveDb.abortTransactions(txnsForDb);
}
fmd.setAbortedTxns(txnsForDb);
fmd.setCursorPoint(currentNotificationId(hiveDb));
ValidTxnList allValidTxns = getTxnMgr().getValidTxns(excludedTxns);
List<Long> openTxns = getOpenTxns(allValidTxns);
fmd.setOpenTxns(openTxns);
fmd.setTxnsWithoutLock(getTxnsNotPresentInHiveLocksTable(openTxns));
txnsForDb = getOpenTxns(allValidTxns, work.dbNameOrPattern);
if (!txnsForDb.isEmpty()) {
LOG.debug("Going to abort transactions: {} for database: {}.", txnsForDb, work.dbNameOrPattern);
hiveDb.abortTransactions(txnsForDb);
fmd.addToAbortedTxns(txnsForDb);
}
fmd.setFailoverEventId(currentNotificationId(hiveDb));
fmd.write();
work.setFailoverMetadata(fmd);
}
Aggregations