/** * Demonstrate that we reject snapshot requests if there is a snapshot already running on the same * table currently running and that concurrent snapshots on different tables can both succeed * concurretly. */ @Test public void testConcurrentSnapshottingAttempts() throws IOException, InterruptedException { final TableName TABLE2_NAME = TableName.valueOf(TABLE_NAME + "2"); int ssNum = 20; // make sure we don't fail on listing snapshots SnapshotTestingUtils.assertNoSnapshots(admin); // create second testing table SnapshotTestingUtils.createTable(UTIL, TABLE2_NAME, TEST_FAM); // load the table so we have some data SnapshotTestingUtils.loadData(UTIL, TABLE_NAME, DEFAULT_NUM_ROWS, TEST_FAM); SnapshotTestingUtils.loadData(UTIL, TABLE2_NAME, DEFAULT_NUM_ROWS, TEST_FAM); final CountDownLatch toBeSubmitted = new CountDownLatch(ssNum); // We'll have one of these per thread class SSRunnable implements Runnable { SnapshotDescription ss; SSRunnable(SnapshotDescription ss) { this.ss = ss; } @Override public void run() { try { LOG.info( "Submitting snapshot request: " + ClientSnapshotDescriptionUtils.toString( ProtobufUtil.createHBaseProtosSnapshotDesc(ss))); admin.takeSnapshotAsync(ss); } catch (Exception e) { LOG.info( "Exception during snapshot request: " + ClientSnapshotDescriptionUtils.toString( ProtobufUtil.createHBaseProtosSnapshotDesc(ss)) + ". This is ok, we expect some", e); } LOG.info( "Submitted snapshot request: " + ClientSnapshotDescriptionUtils.toString( ProtobufUtil.createHBaseProtosSnapshotDesc(ss))); toBeSubmitted.countDown(); } }; // build descriptions SnapshotDescription[] descs = new SnapshotDescription[ssNum]; for (int i = 0; i < ssNum; i++) { if (i % 2 == 0) { descs[i] = new SnapshotDescription("ss" + i, TABLE_NAME, SnapshotType.FLUSH); } else { descs[i] = new SnapshotDescription("ss" + i, TABLE2_NAME, SnapshotType.FLUSH); } } // kick each off its own thread for (int i = 0; i < ssNum; i++) { new Thread(new SSRunnable(descs[i])).start(); } // wait until all have been submitted toBeSubmitted.await(); // loop until all are done. while (true) { int doneCount = 0; for (SnapshotDescription ss : descs) { try { if (admin.isSnapshotFinished(ss)) { doneCount++; } } catch (Exception e) { LOG.warn("Got an exception when checking for snapshot " + ss.getName(), e); doneCount++; } } if (doneCount == descs.length) { break; } Thread.sleep(100); } // dump for debugging UTIL.getHBaseCluster().getMaster().getMasterFileSystem().logFileSystemState(LOG); List<SnapshotDescription> taken = admin.listSnapshots(); int takenSize = taken.size(); LOG.info("Taken " + takenSize + " snapshots: " + taken); assertTrue( "We expect at least 1 request to be rejected because of we concurrently" + " issued many requests", takenSize < ssNum && takenSize > 0); // Verify that there's at least one snapshot per table int t1SnapshotsCount = 0; int t2SnapshotsCount = 0; for (SnapshotDescription ss : taken) { if (ss.getTableName().equals(TABLE_NAME)) { t1SnapshotsCount++; } else if (ss.getTableName().equals(TABLE2_NAME)) { t2SnapshotsCount++; } } assertTrue("We expect at least 1 snapshot of table1 ", t1SnapshotsCount > 0); assertTrue("We expect at least 1 snapshot of table2 ", t2SnapshotsCount > 0); UTIL.deleteTable(TABLE2_NAME); }