2929import  org .apache .hadoop .hdfs .protocol .HdfsConstants ;
3030import  org .apache .hadoop .hdfs .server .blockmanagement .BlockStoragePolicySuite ;
3131import  org .apache .hadoop .hdfs .server .namenode .snapshot .Snapshot ;
32+ import  org .apache .hadoop .ipc .RemoteException ;
3233import  org .apache .hadoop .test .GenericTestUtils ;
3334import  org .apache .hadoop .test .PathUtils ;
3435import  org .junit .jupiter .api .BeforeAll ;
3536import  org .junit .jupiter .api .Test ;
37+ import  org .mockito .Mockito ;
3638
3739import  java .io .IOException ;
3840
3941import  static  org .apache .hadoop .hdfs .protocol .HdfsConstants .HOT_STORAGE_POLICY_NAME ;
4042import  static  org .apache .hadoop .hdfs .protocol .HdfsConstants .ONESSD_STORAGE_POLICY_NAME ;
4143import  static  org .junit .jupiter .api .Assertions .assertEquals ;
44+ import  static  org .junit .jupiter .api .Assertions .assertFalse ;
45+ import  static  org .junit .jupiter .api .Assertions .assertThrows ;
4246import  static  org .junit .jupiter .api .Assertions .assertTrue ;
47+ import  static  org .mockito .ArgumentMatchers .anyBoolean ;
48+ import  static  org .mockito .ArgumentMatchers .anyInt ;
4349
4450public  class  TestCorrectnessOfQuotaAfterRenameOp  {
4551  private  static  MiniDFSCluster  cluster ;
@@ -193,7 +199,7 @@ public void testRenameWithoutValidFeature() throws Exception {
193199    QuotaUsage  rootQuotaUsage1  = dfs .getQuotaUsage (new  Path ("/" ));
194200    ContentSummary  contentSummary1  = dfs .getContentSummary (testParentDir1 );
195201    // srcDir=/testRename/testDir1/src-dir 
196-     // dstDir=/testRename/testDir2/dst-dir dstDir1  not exist 
202+     // dstDir=/testRename/testDir2/dst-dir dstDir  not exist 
197203    final  Path  dstDir2  = new  Path (testParentDir2 , "dst-dir" );
198204    assertTrue (dfs .rename (srcDir , dstDir2 ));
199205    ContentSummary  contentSummary2  = dfs .getContentSummary (testParentDir2 );
@@ -208,19 +214,106 @@ public void testRenameWithoutValidFeature() throws Exception {
208214    // 2. Test rename2 
209215    final  Path  dstDir3  = new  Path (testParentDir3 , "dst-dir" );
210216    assertTrue (dfs .mkdirs (dstDir3 ));
211-     long  originDstDir2Usage  = dfs .getQuotaUsage (dstDir3 ).getFileAndDirectoryCount ();
212-     // Exclude dstDir2  usage 
213-     long  rootINodeCount1  =
214-         dfs .getQuotaUsage (new  Path ("/" )).getFileAndDirectoryCount () - originDstDir2Usage ;
217+     long  originDstDirUsage  = dfs .getQuotaUsage (dstDir3 ).getFileAndDirectoryCount ();
218+     // Overwrite the rename destination, the  usage of dstDir3 should be excluded  
219+     long  expectedCount  =
220+         dfs .getQuotaUsage (new  Path ("/" )).getFileAndDirectoryCount () - originDstDirUsage ;
215221    ContentSummary  contentSummary3  = dfs .getContentSummary (testParentDir2 );
216222
217-     // Src and dst must be same (all file or all dir)  
218-     // dstDir2=/testRename/testDir3 /dst-dir 
223+     // Src and dst must be same 
224+     // dstDir2=/testRename/testDir2 /dst-dir 
219225    // dstDir3=/testRename/testDir3/dst-dir 
220226    dfs .rename (dstDir2 , dstDir3 , Options .Rename .OVERWRITE );
221-     long  rootINodeCount2  = dfs .getQuotaUsage (new  Path ("/" )).getFileAndDirectoryCount ();
222-     assertEquals (rootINodeCount1 ,  rootINodeCount2 );
227+     long  actualCount  = dfs .getQuotaUsage (new  Path ("/" )).getFileAndDirectoryCount ();
228+     assertEquals (expectedCount ,  actualCount );
223229    ContentSummary  contentSummary4  = dfs .getContentSummary (testParentDir3 );
224230    assertEquals (contentSummary3 , contentSummary4 );
225231  }
232+ 
233+   @ Test 
234+   public  void  testRenameUndoWithoutValidFeature () throws  Exception  {
235+     final  int  fileLen  = 1024 ;
236+     final  short  replication  = 3 ;
237+     final  Path  root  = new  Path ("/testRenameUndo" );
238+     assertTrue (dfs .mkdirs (root ));
239+ 
240+     Path  testParentDir1  = new  Path (root , "testDir1" );
241+     assertTrue (dfs .mkdirs (testParentDir1 ));
242+     Path  testParentDir2  = new  Path (root , "testDir2" );
243+     assertTrue (dfs .mkdirs (testParentDir2 ));
244+     Path  testParentDir3  = new  Path (root , "testDir3" );
245+     assertTrue (dfs .mkdirs (testParentDir3 ));
246+     Path  testParentDir4  = new  Path (root , "testDir4" );
247+     assertTrue (dfs .mkdirs (testParentDir4 ));
248+ 
249+     final  Path  srcDir1  = new  Path (testParentDir1 , "src-dir" );
250+     for  (int  i  = 0 ; i  < 2 ; i ++) {
251+       Path  file1  = new  Path (srcDir1 , "file"  + i );
252+       DFSTestUtil .createFile (dfs , file1 , fileLen , replication , 0 );
253+     }
254+ 
255+     final  Path  srcDir3  = new  Path (testParentDir3 , "src-dir" );
256+     for  (int  i  = 0 ; i  < 2 ; i ++) {
257+       Path  file1  = new  Path (srcDir3 , "file"  + i );
258+       DFSTestUtil .createFile (dfs , file1 , fileLen , replication , 0 );
259+     }
260+     
261+     // Test rename1 
262+     ContentSummary  rootContentSummary1  = dfs .getContentSummary (new  Path ("/" ));
263+     QuotaUsage  rootQuotaUsage1  = dfs .getQuotaUsage (new  Path ("/" ));
264+     ContentSummary  contentSummary1  = dfs .getContentSummary (testParentDir1 );
265+     
266+     FSNamesystem  fsn  = cluster .getNamesystem ();
267+     FSDirectory  fsDirectory  = fsn .getFSDirectory ();
268+     
269+     // Replace INode, expected addChild return false 
270+     INodeDirectory  dir  = fsDirectory .getINode4Write (testParentDir2 .toString ()).asDirectory ();
271+     INodeDirectory  mockDir  = Mockito .spy (dir );
272+     INode  srcInode  = fsDirectory .getINode (srcDir3 .toString ());
273+     // Fail the rename but succeed in undo 
274+     Mockito .doReturn (false ).when (mockDir ).addChild (Mockito .eq (srcInode ), anyBoolean (), anyInt ());
275+     INodeDirectory  rootDir  = fsDirectory .getINode4Write (root .toString ()).asDirectory ();
276+     rootDir .replaceChild (dir , mockDir , fsDirectory .getINodeMap ());
277+     mockDir .setParent (rootDir );
278+ 
279+     // srcDir=/testRenameUndo/testDir1/src-dir 
280+     // dstDir=/testRenameUndo/testDir2/ 
281+     assertFalse (dfs .rename (srcDir3 , testParentDir2 ));
282+ 
283+     ContentSummary  rootContentSummary2  = dfs .getContentSummary (new  Path ("/" ));
284+     QuotaUsage  rootQuotaUsage2  = dfs .getQuotaUsage (new  Path ("/" ));
285+     ContentSummary  contentSummary2  = dfs .getContentSummary (testParentDir1 );
286+     assertEquals (rootContentSummary1 .toString (), rootContentSummary2 .toString ());
287+     assertEquals (rootQuotaUsage1 .toString (), rootQuotaUsage2 .toString ());
288+     assertEquals (contentSummary1 .toString (), contentSummary2 .toString ());
289+     assertEquals (rootContentSummary1 .getFileAndDirectoryCount (),
290+         rootQuotaUsage2 .getFileAndDirectoryCount ());
291+ 
292+     // Test rename2 
293+     final  Path  dstDir4  = new  Path (testParentDir4 , "src-dir" );
294+     assertTrue (dfs .mkdirs (dstDir4 ));
295+     ContentSummary  rootContentSummary3  = dfs .getContentSummary (new  Path ("/" ));
296+     QuotaUsage  rootQuotaUsage3  = dfs .getQuotaUsage (new  Path ("/" ));
297+     ContentSummary  contentSummary3  = dfs .getContentSummary (testParentDir3 );
298+ 
299+     // Replace INode, expected addChild return false 
300+     INodeDirectory  dir4  = fsDirectory .getINode4Write (testParentDir4 .toString ()).asDirectory ();
301+     INodeDirectory  mockDir4  = Mockito .spy (dir4 );
302+     INode  srcInode3  = fsDirectory .getINode (srcDir3 .toString ());
303+     Mockito .doReturn (false ).when (mockDir4 ).addChild (Mockito .eq (srcInode3 ), anyBoolean (), anyInt ());
304+     rootDir .replaceChild (dir4 , mockDir4 , fsDirectory .getINodeMap ());
305+     mockDir4 .setParent (rootDir );
306+     // srcDir=/testRenameUndo/testDir3/src-dir 
307+     // dstDir=/testRenameUndo/testDir4/src-dir dstDir exist 
308+     assertThrows (RemoteException .class ,
309+         () -> dfs .rename (srcDir3 , dstDir4 , Options .Rename .OVERWRITE ));
310+     ContentSummary  rootContentSummary4  = dfs .getContentSummary (new  Path ("/" ));
311+     QuotaUsage  rootQuotaUsage4  = dfs .getQuotaUsage (new  Path ("/" ));
312+     ContentSummary  contentSummary4  = dfs .getContentSummary (testParentDir3 );
313+     assertEquals (rootContentSummary3 .toString (), rootContentSummary4 .toString ());
314+     assertEquals (rootQuotaUsage3 .toString (), rootQuotaUsage4 .toString ());
315+     assertEquals (contentSummary3 .toString (), contentSummary4 .toString ());
316+     assertEquals (rootContentSummary3 .getFileAndDirectoryCount (),
317+         rootQuotaUsage4 .getFileAndDirectoryCount ());
318+   }
226319}
0 commit comments