@Override public void run() { Random rand = new Random(); TestProcedure proc; do { // After HBASE-15579 there may be gap in the procId sequence, trying to simulate that. long procId = procCounter.addAndGet(1 + rand.nextInt(3)); proc = new TestProcedure(procId); // Insert procStore.insert(proc, null); // Update for (int i = 0, nupdates = rand.nextInt(10); i <= nupdates; ++i) { try { Thread.sleep(0, rand.nextInt(15)); } catch (InterruptedException e) {} procStore.update(proc); } // Delete procStore.delete(proc.getProcId()); } while (proc.getProcId() < LAST_PROC_ID); } };
@Ignore @Test // REENABLE after merge of // https://github.com/google/protobuf/issues/2228#issuecomment-252058282 public void testEntrySizeLimit() throws Exception { final int NITEMS = 20; for (int i = 1; i <= NITEMS; ++i) { final byte[] data = new byte[256 << i]; LOG.info(String.format("Writing %s", StringUtils.humanSize(data.length))); TestProcedure proc = new TestProcedure(i, 0, data); procStore.insert(proc, null); } // check that we are able to read the big proc-blobs ProcedureTestingUtility.storeRestartAndAssert(procStore, NITEMS, NITEMS, 0, 0); } }
new ProcedureTestingUtility.TestProcedure(procId); proc.setData(serializedState); store.insert(proc, null); store.update(proc);
private void writeWals() throws IOException { List<Integer> procStates = shuffleProcWriteSequence(); TestProcedure[] procs = new TestProcedure[numProcs + 1]; // 0 is not used. int numProcsPerWal = numWals > 0 ? procStates.size() / numWals : Integer.MAX_VALUE; long startTime = currentTimeMillis(); long lastTime = startTime; for (int i = 0; i < procStates.size(); ++i) { int procId = procStates.get(i); if (procId < 0) { store.delete(procs[-procId].getProcId()); procs[-procId] = null; } else if (procs[procId] == null) { procs[procId] = new TestProcedure(procId, 0); procs[procId].setData(serializedState); store.insert(procs[procId], null); } else { store.update(procs[procId]); } if (i > 0 && i % numProcsPerWal == 0) { long currentTime = currentTimeMillis(); System.out.println("Forcing wall roll. Time taken on last WAL: " + (currentTime - lastTime) / 1000.0f + " sec"); store.rollWriterForTesting(); lastTime = currentTime; } } long timeTaken = currentTimeMillis() - startTime; System.out.println("\n\nDone writing WALs.\nNum procs : " + numProcs + "\nTotal time taken : " + StringUtils.humanTimeDiff(timeTaken) + "\n\n"); }
@Test public void testWalRollOnLowReplication() throws Exception { UTIL.getConfiguration().setInt("dfs.namenode.replication.min", 1); setupDFS(); int dnCount = 0; store.insert(new TestProcedure(1, -1), null); UTIL.getDFSCluster().restartDataNode(dnCount); for (long i = 2; i < 100; ++i) { store.insert(new TestProcedure(i, -1), null); waitForNumReplicas(3); Thread.sleep(100); if ((i % 30) == 0) { LOG.info("Restart Data Node"); UTIL.getDFSCluster().restartDataNode(++dnCount % 3); } } assertTrue(store.isRunning()); }
@Test public void testWalCleanerUpdates() throws Exception { TestSequentialProcedure p1 = new TestSequentialProcedure(); TestSequentialProcedure p2 = new TestSequentialProcedure(); procStore.insert(p1, null); procStore.insert(p2, null); procStore.rollWriterForTesting(); ProcedureWALFile firstLog = procStore.getActiveLogs().get(0); procStore.update(p1); procStore.rollWriterForTesting(); procStore.update(p2); procStore.rollWriterForTesting(); procStore.removeInactiveLogsForTesting(); assertFalse(procStore.getActiveLogs().contains(firstLog)); }
@Test(expected=RuntimeException.class) public void testWalAbortOnLowReplication() throws Exception { setupDFS(); assertEquals(3, UTIL.getDFSCluster().getDataNodes().size()); LOG.info("Stop DataNode"); UTIL.getDFSCluster().stopDataNode(0); assertEquals(2, UTIL.getDFSCluster().getDataNodes().size()); store.insert(new TestProcedure(1, -1), null); for (long i = 2; store.isRunning(); ++i) { assertEquals(2, UTIL.getDFSCluster().getDataNodes().size()); store.insert(new TestProcedure(i, -1), null); Thread.sleep(100); } assertFalse(store.isRunning()); }
/** * Tests that tracker for all old logs are loaded back after procedure store is restarted. */ @Test public void trackersLoadedForAllOldLogs() throws Exception { for (int i = 0; i <= 20; ++i) { procStore.insert(new TestProcedure(i), null); if (i > 0 && (i % 5) == 0) { LoadCounter loader = new LoadCounter(); storeRestart(loader); } } assertEquals(5, procStore.getActiveLogs().size()); for (int i = 0; i < procStore.getActiveLogs().size() - 1; ++i) { ProcedureStoreTracker tracker = procStore.getActiveLogs().get(i).getTracker(); assertTrue(tracker != null && !tracker.isEmpty()); } }
@Test public void testWalCleanerSequentialClean() throws Exception { final Procedure<?>[] procs = new Procedure[5]; ArrayList<ProcedureWALFile> logs = null; // Insert procedures and roll wal after every insert. for (int i = 0; i < procs.length; i++) { procs[i] = new TestSequentialProcedure(); procStore.insert(procs[i], null); procStore.rollWriterForTesting(); logs = procStore.getActiveLogs(); assertEquals(logs.size(), i + 2); // Extra 1 for current ongoing wal. } // Delete procedures in sequential order make sure that only the corresponding wal is deleted // from logs list. final int[] deleteOrder = new int[] { 0, 1, 2, 3, 4 }; for (int i = 0; i < deleteOrder.length; i++) { procStore.delete(procs[deleteOrder[i]].getProcId()); procStore.removeInactiveLogsForTesting(); assertFalse(logs.get(deleteOrder[i]).toString(), procStore.getActiveLogs().contains(logs.get(deleteOrder[i]))); assertEquals(procStore.getActiveLogs().size(), procs.length - i); } }
@Test public void testWalCleanerUpdatesDontLeaveHoles() throws Exception { TestSequentialProcedure p1 = new TestSequentialProcedure(); TestSequentialProcedure p2 = new TestSequentialProcedure(); procStore.insert(p1, null); procStore.insert(p2, null); procStore.rollWriterForTesting(); // generates first log with p1 + p2 ProcedureWALFile log1 = procStore.getActiveLogs().get(0); procStore.update(p2); procStore.rollWriterForTesting(); // generates second log with p2 ProcedureWALFile log2 = procStore.getActiveLogs().get(1); procStore.update(p2); procStore.rollWriterForTesting(); // generates third log with p2 procStore.removeInactiveLogsForTesting(); // Shouldn't remove 2nd log. assertEquals(4, procStore.getActiveLogs().size()); procStore.update(p1); procStore.rollWriterForTesting(); // generates fourth log with p1 procStore.removeInactiveLogsForTesting(); // Should remove first two logs. assertEquals(3, procStore.getActiveLogs().size()); assertFalse(procStore.getActiveLogs().contains(log1)); assertFalse(procStore.getActiveLogs().contains(log2)); }
@Test public void testRollAndRemove() throws IOException { // Insert something in the log Procedure<?> proc1 = new TestSequentialProcedure(); procStore.insert(proc1, null); Procedure<?> proc2 = new TestSequentialProcedure(); procStore.insert(proc2, null); // roll the log, now we have 2 procStore.rollWriterForTesting(); assertEquals(2, procStore.getActiveLogs().size()); // everything will be up to date in the second log // so we can remove the first one procStore.update(proc1); procStore.update(proc2); assertEquals(1, procStore.getActiveLogs().size()); // roll the log, now we have 2 procStore.rollWriterForTesting(); assertEquals(2, procStore.getActiveLogs().size()); // remove everything active // so we can remove all the logs procStore.delete(proc1.getProcId()); procStore.delete(proc2.getProcId()); assertEquals(1, procStore.getActiveLogs().size()); }
@Test public void testWalCleanerNoHoles() throws Exception { final Procedure<?>[] procs = new Procedure[5]; ArrayList<ProcedureWALFile> logs = null; // Insert procedures and roll wal after every insert. for (int i = 0; i < procs.length; i++) { procs[i] = new TestSequentialProcedure(); procStore.insert(procs[i], null); procStore.rollWriterForTesting(); logs = procStore.getActiveLogs(); assertEquals(i + 2, logs.size()); // Extra 1 for current ongoing wal. } for (int i = 1; i < procs.length; i++) { procStore.delete(procs[i].getProcId()); } assertEquals(procs.length + 1, procStore.getActiveLogs().size()); procStore.delete(procs[0].getProcId()); assertEquals(1, procStore.getActiveLogs().size()); }
procStore2.insert(proc2, null);
@Test public void testWalCleanerWithEmptyRolls() throws Exception { final Procedure<?>[] procs = new Procedure[3]; for (int i = 0; i < procs.length; ++i) { procs[i] = new TestSequentialProcedure(); procStore.insert(procs[i], null); } assertEquals(1, procStore.getActiveLogs().size()); procStore.rollWriterForTesting(); assertEquals(2, procStore.getActiveLogs().size()); procStore.rollWriterForTesting(); assertEquals(3, procStore.getActiveLogs().size()); for (int i = 0; i < procs.length; ++i) { procStore.update(procs[i]); procStore.rollWriterForTesting(); procStore.rollWriterForTesting(); if (i < (procs.length - 1)) { assertEquals(3 + ((i + 1) * 2), procStore.getActiveLogs().size()); } } assertEquals(7, procStore.getActiveLogs().size()); for (int i = 0; i < procs.length; ++i) { procStore.delete(procs[i].getProcId()); assertEquals(7 - ((i + 1) * 2), procStore.getActiveLogs().size()); } assertEquals(1, procStore.getActiveLogs().size()); }
@Test public void testBatchInsert() throws Exception { final int count = 10; final TestProcedure[] procs = new TestProcedure[count]; for (int i = 0; i < procs.length; ++i) { procs[i] = new TestProcedure(i + 1); } procStore.insert(procs); restartAndAssert(count, count, 0, 0); for (int i = 0; i < procs.length; ++i) { final long procId = procs[i].getProcId(); procStore.delete(procId); restartAndAssert(procId != count ? count : 0, count - (i + 1), 0, 0); } procStore.removeInactiveLogsForTesting(); assertEquals("WALs=" + procStore.getActiveLogs(), 1, procStore.getActiveLogs().size()); }
@Test public void testCorruptedTrailer() throws Exception { // Insert something for (int i = 0; i < 100; ++i) { procStore.insert(new TestSequentialProcedure(), null); } // Stop the store procStore.stop(false); // Remove 4 byte from the trailer FileStatus[] logs = fs.listStatus(logDir); assertEquals(1, logs.length); corruptLog(logs[0], 4); LoadCounter loader = new LoadCounter(); storeRestart(loader); assertEquals(100, loader.getLoadedCount()); assertEquals(0, loader.getCorruptedCount()); }
@Test public void testCorruptedEntries() throws Exception { // Insert something for (int i = 0; i < 100; ++i) { procStore.insert(new TestSequentialProcedure(), null); } // Stop the store procStore.stop(false); // Remove some byte from the log // (enough to cut the trailer and corrupt some entries) FileStatus[] logs = fs.listStatus(logDir); assertEquals(1, logs.length); corruptLog(logs[0], 1823); LoadCounter loader = new LoadCounter(); storeRestart(loader); assertTrue(procStore.getCorruptedLogs() != null); assertEquals(1, procStore.getCorruptedLogs().size()); assertEquals(87, loader.getLoadedCount()); assertEquals(0, loader.getCorruptedCount()); }
@Test public void testProcIdHoles() throws Exception { // Insert for (int i = 0; i < 100; i += 2) { procStore.insert(new TestProcedure(i), null); if (i > 0 && (i % 10) == 0) { LoadCounter loader = new LoadCounter(); storeRestart(loader); assertEquals(0, loader.getCorruptedCount()); assertEquals((i / 2) + 1, loader.getLoadedCount()); } } assertEquals(10, procStore.getActiveLogs().size()); // Delete for (int i = 0; i < 100; i += 2) { procStore.delete(i); } assertEquals(1, procStore.getActiveLogs().size()); LoadCounter loader = new LoadCounter(); storeRestart(loader); assertEquals(0, loader.getLoadedCount()); assertEquals(0, loader.getCorruptedCount()); }
@Test public void testLoadChildren() throws Exception { TestProcedure a = new TestProcedure(1, 0); TestProcedure b = new TestProcedure(2, 1); TestProcedure c = new TestProcedure(3, 1); // INIT procStore.insert(a, null); // Run A first step a.addStackId(0); procStore.update(a); // Run A second step a.addStackId(1); procStore.insert(a, new Procedure[] { b, c }); // Run B first step b.addStackId(2); procStore.update(b); // Run C first and last step c.addStackId(3); procStore.update(c); // Run B second setp b.addStackId(4); procStore.update(b); // back to A a.addStackId(5); a.setSuccessState(); procStore.delete(a, new long[] { b.getProcId(), c.getProcId() }); restartAndAssert(3, 0, 1, 0); }