@Override public void run() { boolean succeeded = false; final FsDatasetImpl dataset = (FsDatasetImpl) datanode.getFSDataset(); try (FsVolumeReference ref = this.targetVolume) { int smallBufferSize = DFSUtil.getSmallBufferSize(EMPTY_HDFS_CONF); // No FsDatasetImpl lock for the file copy File targetFiles[] = FsDatasetImpl.copyBlockFiles( blockId, genStamp, metaFile, blockFile, lazyPersistDir, true, smallBufferSize); // Lock FsDataSetImpl during onCompleteLazyPersist callback dataset.onCompleteLazyPersist( bpId, blockId, creationTime, targetFiles, (FsVolumeImpl) targetVolume.getVolume()); succeeded = true; } catch (Exception e) { FsDatasetImpl.LOG.warn( "LazyWriter failed to async persist RamDisk block pool id: " + bpId + "block Id: " + blockId, e); } finally { if (!succeeded) { dataset.onFailLazyPersist(bpId, blockId); } } }
File addBlock(Block b, File f) throws IOException { File blockDir = DatanodeUtil.idToBlockDir(finalizedDir, b.getBlockId()); if (!blockDir.exists()) { if (!blockDir.mkdirs()) { throw new IOException("Failed to mkdirs " + blockDir); } } File blockFile = FsDatasetImpl.moveBlockFiles(b, f, blockDir); File metaFile = FsDatasetUtil.getMetaFile(blockFile, b.getGenerationStamp()); dfsUsage.incDfsUsed(b.getNumBytes() + metaFile.length()); return blockFile; }
public FsDatasetCache(FsDatasetImpl dataset) { this.dataset = dataset; this.maxBytes = dataset.datanode.getDnConf().getMaxLockedMemory(); ThreadFactory workerFactory = new ThreadFactoryBuilder() .setDaemon(true) .setNameFormat("FsDatasetCache-%d-" + dataset.toString()) .build(); this.usedBytesCount = new UsedBytesCount(); this.uncachingExecutor = new ThreadPoolExecutor( 0, 1, 60, TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>(), workerFactory); this.uncachingExecutor.allowCoreThreadTimeOut(true); }
private void testClose(FsDatasetImpl dataSet, ExtendedBlock[] blocks) throws IOException { long newGS = blocks[FINALIZED].getGenerationStamp() + 1; dataSet.recoverClose(blocks[FINALIZED], newGS, blocks[FINALIZED].getNumBytes()); // successful blocks[FINALIZED].setGenerationStamp(newGS); try { dataSet.recoverClose( blocks[TEMPORARY], blocks[TEMPORARY].getGenerationStamp() + 1, blocks[TEMPORARY].getNumBytes()); Assert.fail("Should not have recovered close a temporary replica " + blocks[TEMPORARY]); } catch (ReplicaNotFoundException e) { Assert.assertTrue( e.getMessage().startsWith(ReplicaNotFoundException.UNFINALIZED_AND_NONRBW_REPLICA)); } newGS = blocks[RBW].getGenerationStamp() + 1; dataSet.recoverClose(blocks[RBW], newGS, blocks[RBW].getNumBytes()); blocks[RBW].setGenerationStamp(newGS); try { dataSet.recoverClose( blocks[RWR], blocks[RWR].getGenerationStamp() + 1, blocks[RBW].getNumBytes()); Assert.fail("Should not have recovered close an RWR replica" + blocks[RWR]); } catch (ReplicaNotFoundException e) { Assert.assertTrue( e.getMessage().startsWith(ReplicaNotFoundException.UNFINALIZED_AND_NONRBW_REPLICA)); } try { dataSet.recoverClose( blocks[RUR], blocks[RUR].getGenerationStamp() + 1, blocks[RUR].getNumBytes()); Assert.fail("Should not have recovered close an RUR replica" + blocks[RUR]); } catch (ReplicaNotFoundException e) { Assert.assertTrue( e.getMessage().startsWith(ReplicaNotFoundException.UNFINALIZED_AND_NONRBW_REPLICA)); } try { dataSet.recoverClose( blocks[NON_EXISTENT], blocks[NON_EXISTENT].getGenerationStamp(), blocks[NON_EXISTENT].getNumBytes()); Assert.fail("Should not have recovered close a non-existent replica " + blocks[NON_EXISTENT]); } catch (ReplicaNotFoundException e) { Assert.assertTrue(e.getMessage().startsWith(ReplicaNotFoundException.NON_EXISTENT_REPLICA)); } }
private void testWriteToTemporary(FsDatasetImpl dataSet, ExtendedBlock[] blocks) throws IOException { try { dataSet.createTemporary(StorageType.DEFAULT, blocks[FINALIZED]); Assert.fail( "Should not have created a temporary replica that was " + "finalized " + blocks[FINALIZED]); } catch (ReplicaAlreadyExistsException e) { } try { dataSet.createTemporary(StorageType.DEFAULT, blocks[TEMPORARY]); Assert.fail( "Should not have created a replica that had created as" + "temporary " + blocks[TEMPORARY]); } catch (ReplicaAlreadyExistsException e) { } try { dataSet.createTemporary(StorageType.DEFAULT, blocks[RBW]); Assert.fail("Should not have created a replica that had created as RBW " + blocks[RBW]); } catch (ReplicaAlreadyExistsException e) { } try { dataSet.createTemporary(StorageType.DEFAULT, blocks[RWR]); Assert.fail( "Should not have created a replica that was waiting to be " + "recovered " + blocks[RWR]); } catch (ReplicaAlreadyExistsException e) { } try { dataSet.createTemporary(StorageType.DEFAULT, blocks[RUR]); Assert.fail("Should not have created a replica that was under recovery " + blocks[RUR]); } catch (ReplicaAlreadyExistsException e) { } dataSet.createTemporary(StorageType.DEFAULT, blocks[NON_EXISTENT]); try { dataSet.createTemporary(StorageType.DEFAULT, blocks[NON_EXISTENT]); Assert.fail( "Should not have created a replica that had already been " + "created " + blocks[NON_EXISTENT]); } catch (Exception e) { Assert.assertTrue(e.getMessage().contains(blocks[NON_EXISTENT].getBlockName())); Assert.assertTrue(e instanceof ReplicaAlreadyExistsException); } long newGenStamp = blocks[NON_EXISTENT].getGenerationStamp() * 10; blocks[NON_EXISTENT].setGenerationStamp(newGenStamp); try { ReplicaInPipelineInterface replicaInfo = dataSet.createTemporary(StorageType.DEFAULT, blocks[NON_EXISTENT]).getReplica(); Assert.assertTrue(replicaInfo.getGenerationStamp() == newGenStamp); Assert.assertTrue(replicaInfo.getBlockId() == blocks[NON_EXISTENT].getBlockId()); } catch (ReplicaAlreadyExistsException e) { Assert.fail( "createRbw() Should have removed the block with the older " + "genstamp and replaced it with the newer one: " + blocks[NON_EXISTENT]); } }
private void testWriteToRbw(FsDatasetImpl dataSet, ExtendedBlock[] blocks) throws IOException { try { dataSet.recoverRbw( blocks[FINALIZED], blocks[FINALIZED].getGenerationStamp() + 1, 0L, blocks[FINALIZED].getNumBytes()); Assert.fail("Should not have recovered a finalized replica " + blocks[FINALIZED]); } catch (ReplicaNotFoundException e) { Assert.assertTrue(e.getMessage().startsWith(ReplicaNotFoundException.NON_RBW_REPLICA)); } try { dataSet.createRbw(StorageType.DEFAULT, blocks[FINALIZED], false); Assert.fail( "Should not have created a replica that's already " + "finalized " + blocks[FINALIZED]); } catch (ReplicaAlreadyExistsException e) { } try { dataSet.recoverRbw( blocks[TEMPORARY], blocks[TEMPORARY].getGenerationStamp() + 1, 0L, blocks[TEMPORARY].getNumBytes()); Assert.fail("Should not have recovered a temporary replica " + blocks[TEMPORARY]); } catch (ReplicaNotFoundException e) { Assert.assertTrue(e.getMessage().startsWith(ReplicaNotFoundException.NON_RBW_REPLICA)); } try { dataSet.createRbw(StorageType.DEFAULT, blocks[TEMPORARY], false); Assert.fail( "Should not have created a replica that had created as " + "temporary " + blocks[TEMPORARY]); } catch (ReplicaAlreadyExistsException e) { } dataSet.recoverRbw( blocks[RBW], blocks[RBW].getGenerationStamp() + 1, 0L, blocks[RBW].getNumBytes()); // expect to be successful try { dataSet.createRbw(StorageType.DEFAULT, blocks[RBW], false); Assert.fail("Should not have created a replica that had created as RBW " + blocks[RBW]); } catch (ReplicaAlreadyExistsException e) { } try { dataSet.recoverRbw( blocks[RWR], blocks[RWR].getGenerationStamp() + 1, 0L, blocks[RWR].getNumBytes()); Assert.fail("Should not have recovered a RWR replica " + blocks[RWR]); } catch (ReplicaNotFoundException e) { Assert.assertTrue(e.getMessage().startsWith(ReplicaNotFoundException.NON_RBW_REPLICA)); } try { dataSet.createRbw(StorageType.DEFAULT, blocks[RWR], false); Assert.fail( "Should not have created a replica that was waiting to be " + "recovered " + blocks[RWR]); } catch (ReplicaAlreadyExistsException e) { } try { dataSet.recoverRbw( blocks[RUR], blocks[RUR].getGenerationStamp() + 1, 0L, blocks[RUR].getNumBytes()); Assert.fail("Should not have recovered a RUR replica " + blocks[RUR]); } catch (ReplicaNotFoundException e) { Assert.assertTrue(e.getMessage().startsWith(ReplicaNotFoundException.NON_RBW_REPLICA)); } try { dataSet.createRbw(StorageType.DEFAULT, blocks[RUR], false); Assert.fail("Should not have created a replica that was under recovery " + blocks[RUR]); } catch (ReplicaAlreadyExistsException e) { } try { dataSet.recoverRbw( blocks[NON_EXISTENT], blocks[NON_EXISTENT].getGenerationStamp() + 1, 0L, blocks[NON_EXISTENT].getNumBytes()); Assert.fail("Cannot recover a non-existent replica " + blocks[NON_EXISTENT]); } catch (ReplicaNotFoundException e) { Assert.assertTrue(e.getMessage().contains(ReplicaNotFoundException.NON_EXISTENT_REPLICA)); } dataSet.createRbw(StorageType.DEFAULT, blocks[NON_EXISTENT], false); }
private void testAppend(String bpid, FsDatasetImpl dataSet, ExtendedBlock[] blocks) throws IOException { long newGS = blocks[FINALIZED].getGenerationStamp() + 1; final FsVolumeImpl v = (FsVolumeImpl) dataSet.volumeMap.get(bpid, blocks[FINALIZED].getLocalBlock()).getVolume(); long available = v.getCapacity() - v.getDfsUsed(); long expectedLen = blocks[FINALIZED].getNumBytes(); try { v.decDfsUsed(bpid, -available); blocks[FINALIZED].setNumBytes(expectedLen + 100); dataSet.append(blocks[FINALIZED], newGS, expectedLen); Assert.fail("Should not have space to append to an RWR replica" + blocks[RWR]); } catch (DiskOutOfSpaceException e) { Assert.assertTrue(e.getMessage().startsWith("Insufficient space for appending to ")); } v.decDfsUsed(bpid, available); blocks[FINALIZED].setNumBytes(expectedLen); newGS = blocks[RBW].getGenerationStamp() + 1; dataSet.append(blocks[FINALIZED], newGS, blocks[FINALIZED].getNumBytes()); // successful blocks[FINALIZED].setGenerationStamp(newGS); try { dataSet.append( blocks[TEMPORARY], blocks[TEMPORARY].getGenerationStamp() + 1, blocks[TEMPORARY].getNumBytes()); Assert.fail("Should not have appended to a temporary replica " + blocks[TEMPORARY]); } catch (ReplicaNotFoundException e) { Assert.assertEquals( ReplicaNotFoundException.UNFINALIZED_REPLICA + blocks[TEMPORARY], e.getMessage()); } try { dataSet.append(blocks[RBW], blocks[RBW].getGenerationStamp() + 1, blocks[RBW].getNumBytes()); Assert.fail("Should not have appended to an RBW replica" + blocks[RBW]); } catch (ReplicaNotFoundException e) { Assert.assertEquals( ReplicaNotFoundException.UNFINALIZED_REPLICA + blocks[RBW], e.getMessage()); } try { dataSet.append(blocks[RWR], blocks[RWR].getGenerationStamp() + 1, blocks[RBW].getNumBytes()); Assert.fail("Should not have appended to an RWR replica" + blocks[RWR]); } catch (ReplicaNotFoundException e) { Assert.assertEquals( ReplicaNotFoundException.UNFINALIZED_REPLICA + blocks[RWR], e.getMessage()); } try { dataSet.append(blocks[RUR], blocks[RUR].getGenerationStamp() + 1, blocks[RUR].getNumBytes()); Assert.fail("Should not have appended to an RUR replica" + blocks[RUR]); } catch (ReplicaNotFoundException e) { Assert.assertEquals( ReplicaNotFoundException.UNFINALIZED_REPLICA + blocks[RUR], e.getMessage()); } try { dataSet.append( blocks[NON_EXISTENT], blocks[NON_EXISTENT].getGenerationStamp(), blocks[NON_EXISTENT].getNumBytes()); Assert.fail("Should not have appended to a non-existent replica " + blocks[NON_EXISTENT]); } catch (ReplicaNotFoundException e) { Assert.assertEquals( ReplicaNotFoundException.NON_EXISTENT_REPLICA + blocks[NON_EXISTENT], e.getMessage()); } newGS = blocks[FINALIZED].getGenerationStamp() + 1; dataSet.recoverAppend(blocks[FINALIZED], newGS, blocks[FINALIZED].getNumBytes()); // successful blocks[FINALIZED].setGenerationStamp(newGS); try { dataSet.recoverAppend( blocks[TEMPORARY], blocks[TEMPORARY].getGenerationStamp() + 1, blocks[TEMPORARY].getNumBytes()); Assert.fail("Should not have appended to a temporary replica " + blocks[TEMPORARY]); } catch (ReplicaNotFoundException e) { Assert.assertTrue( e.getMessage().startsWith(ReplicaNotFoundException.UNFINALIZED_AND_NONRBW_REPLICA)); } newGS = blocks[RBW].getGenerationStamp() + 1; dataSet.recoverAppend(blocks[RBW], newGS, blocks[RBW].getNumBytes()); blocks[RBW].setGenerationStamp(newGS); try { dataSet.recoverAppend( blocks[RWR], blocks[RWR].getGenerationStamp() + 1, blocks[RBW].getNumBytes()); Assert.fail("Should not have appended to an RWR replica" + blocks[RWR]); } catch (ReplicaNotFoundException e) { Assert.assertTrue( e.getMessage().startsWith(ReplicaNotFoundException.UNFINALIZED_AND_NONRBW_REPLICA)); } try { dataSet.recoverAppend( blocks[RUR], blocks[RUR].getGenerationStamp() + 1, blocks[RUR].getNumBytes()); Assert.fail("Should not have appended to an RUR replica" + blocks[RUR]); } catch (ReplicaNotFoundException e) { Assert.assertTrue( e.getMessage().startsWith(ReplicaNotFoundException.UNFINALIZED_AND_NONRBW_REPLICA)); } try { dataSet.recoverAppend( blocks[NON_EXISTENT], blocks[NON_EXISTENT].getGenerationStamp(), blocks[NON_EXISTENT].getNumBytes()); Assert.fail("Should not have appended to a non-existent replica " + blocks[NON_EXISTENT]); } catch (ReplicaNotFoundException e) { Assert.assertTrue(e.getMessage().startsWith(ReplicaNotFoundException.NON_EXISTENT_REPLICA)); } }
/** Test for {@link FsDatasetImpl#updateReplicaUnderRecovery(ExtendedBlock, long, long)} */ @Test public void testUpdateReplicaUnderRecovery() throws IOException { MiniDFSCluster cluster = null; try { cluster = new MiniDFSCluster.Builder(conf).numDataNodes(3).build(); cluster.waitActive(); String bpid = cluster.getNamesystem().getBlockPoolId(); // create a file DistributedFileSystem dfs = (DistributedFileSystem) cluster.getFileSystem(); String filestr = "/foo"; Path filepath = new Path(filestr); DFSTestUtil.createFile(dfs, filepath, 1024L, (short) 3, 0L); // get block info final LocatedBlock locatedblock = getLastLocatedBlock(DFSClientAdapter.getDFSClient(dfs).getNamenode(), filestr); final DatanodeInfo[] datanodeinfo = locatedblock.getLocations(); Assert.assertTrue(datanodeinfo.length > 0); // get DataNode and FSDataset objects final DataNode datanode = cluster.getDataNode(datanodeinfo[0].getIpcPort()); Assert.assertTrue(datanode != null); // initReplicaRecovery final ExtendedBlock b = locatedblock.getBlock(); final long recoveryid = b.getGenerationStamp() + 1; final long newlength = b.getNumBytes() - 1; final FsDatasetSpi<?> fsdataset = DataNodeTestUtils.getFSDataset(datanode); final ReplicaRecoveryInfo rri = fsdataset.initReplicaRecovery(new RecoveringBlock(b, null, recoveryid)); // check replica final ReplicaInfo replica = FsDatasetTestUtil.fetchReplicaInfo(fsdataset, bpid, b.getBlockId()); Assert.assertEquals(ReplicaState.RUR, replica.getState()); // check meta data before update FsDatasetImpl.checkReplicaFiles(replica); // case "THIS IS NOT SUPPOSED TO HAPPEN" // with (block length) != (stored replica's on disk length). { // create a block with same id and gs but different length. final ExtendedBlock tmp = new ExtendedBlock( b.getBlockPoolId(), rri.getBlockId(), rri.getNumBytes() - 1, rri.getGenerationStamp()); try { // update should fail fsdataset.updateReplicaUnderRecovery(tmp, recoveryid, newlength); Assert.fail(); } catch (IOException ioe) { System.out.println("GOOD: getting " + ioe); } } // update final String storageID = fsdataset.updateReplicaUnderRecovery( new ExtendedBlock(b.getBlockPoolId(), rri), recoveryid, newlength); assertTrue(storageID != null); } finally { if (cluster != null) cluster.shutdown(); } }
/** Test {@link FsDatasetImpl#initReplicaRecovery(String, ReplicaMap, Block, long)} */ @Test public void testInitReplicaRecovery() throws IOException { final long firstblockid = 10000L; final long gs = 7777L; final long length = 22L; final ReplicaMap map = new ReplicaMap(this); String bpid = "BP-TEST"; final Block[] blocks = new Block[5]; for (int i = 0; i < blocks.length; i++) { blocks[i] = new Block(firstblockid + i, length, gs); map.add(bpid, createReplicaInfo(blocks[i])); } { // normal case final Block b = blocks[0]; final ReplicaInfo originalInfo = map.get(bpid, b); final long recoveryid = gs + 1; final ReplicaRecoveryInfo recoveryInfo = FsDatasetImpl.initReplicaRecovery(bpid, map, blocks[0], recoveryid); assertEquals(originalInfo, recoveryInfo); final ReplicaUnderRecovery updatedInfo = (ReplicaUnderRecovery) map.get(bpid, b); Assert.assertEquals(originalInfo.getBlockId(), updatedInfo.getBlockId()); Assert.assertEquals(recoveryid, updatedInfo.getRecoveryID()); // recover one more time final long recoveryid2 = gs + 2; final ReplicaRecoveryInfo recoveryInfo2 = FsDatasetImpl.initReplicaRecovery(bpid, map, blocks[0], recoveryid2); assertEquals(originalInfo, recoveryInfo2); final ReplicaUnderRecovery updatedInfo2 = (ReplicaUnderRecovery) map.get(bpid, b); Assert.assertEquals(originalInfo.getBlockId(), updatedInfo2.getBlockId()); Assert.assertEquals(recoveryid2, updatedInfo2.getRecoveryID()); // case RecoveryInProgressException try { FsDatasetImpl.initReplicaRecovery(bpid, map, b, recoveryid); Assert.fail(); } catch (RecoveryInProgressException ripe) { System.out.println("GOOD: getting " + ripe); } } { // BlockRecoveryFI_01: replica not found final long recoveryid = gs + 1; final Block b = new Block(firstblockid - 1, length, gs); ReplicaRecoveryInfo r = FsDatasetImpl.initReplicaRecovery(bpid, map, b, recoveryid); Assert.assertNull("Data-node should not have this replica.", r); } { // BlockRecoveryFI_02: "THIS IS NOT SUPPOSED TO HAPPEN" with recovery id < gs final long recoveryid = gs - 1; final Block b = new Block(firstblockid + 1, length, gs); try { FsDatasetImpl.initReplicaRecovery(bpid, map, b, recoveryid); Assert.fail(); } catch (IOException ioe) { System.out.println("GOOD: getting " + ioe); } } // BlockRecoveryFI_03: Replica's gs is less than the block's gs { final long recoveryid = gs + 1; final Block b = new Block(firstblockid, length, gs + 1); try { FsDatasetImpl.initReplicaRecovery(bpid, map, b, recoveryid); fail( "InitReplicaRecovery should fail because replica's " + "gs is less than the block's gs"); } catch (IOException e) { e.getMessage() .startsWith("replica.getGenerationStamp() < block.getGenerationStamp(), block="); } } }