17
17
*/
18
18
package org .apache .hadoop .hdfs .server .namenode ;
19
19
20
- import org .apache .commons .lang3 .tuple .Pair ;
20
+ import org .apache .commons .lang3 .tuple .Triple ;
21
21
import org .apache .hadoop .hdfs .protocol .HdfsConstants ;
22
22
import org .apache .hadoop .util .Preconditions ;
23
23
import org .apache .hadoop .fs .FileAlreadyExistsException ;
@@ -72,14 +72,25 @@ static RenameResult renameToInt(
72
72
* Verify quota for rename operation where srcInodes[srcInodes.length-1] moves
73
73
* dstInodes[dstInodes.length-1]
74
74
*/
75
- private static Pair <Optional <QuotaCounts >, Optional <QuotaCounts >> verifyQuotaForRename (
76
- FSDirectory fsd , INodesInPath src , INodesInPath dst ) throws QuotaExceededException {
75
+ private static Triple <Boolean , Optional <QuotaCounts >, Optional <QuotaCounts >> verifyQuotaForRename (
76
+ FSDirectory fsd , INodesInPath src , INodesInPath dst , boolean overwrite )
77
+ throws QuotaExceededException {
77
78
Optional <QuotaCounts > srcDelta = Optional .empty ();
78
79
Optional <QuotaCounts > dstDelta = Optional .empty ();
79
80
if (!fsd .getFSNamesystem ().isImageLoaded () || fsd .shouldSkipQuotaChecks ()) {
80
81
// Do not check quota if edits log is still being processed
81
- return Pair .of (srcDelta , dstDelta );
82
+ return Triple .of (false , srcDelta , dstDelta );
82
83
}
84
+
85
+ // Verify srcPath and dstPath without valid 'DirectoryWithQuotaFeature'
86
+ // Note: In overwrite scenarios, quota calculation is still required because:
87
+ // Overwrite operations delete existing content (affecting rootDir's quota)
88
+ if (FSDirectory .verifyPathWithoutValidQuotaFeature (src , src .length () - 1 )
89
+ && FSDirectory .verifyPathWithoutValidQuotaFeature (dst , dst .length () - 1 )
90
+ && !overwrite ) {
91
+ return Triple .of (false , srcDelta , dstDelta );
92
+ }
93
+
83
94
int i = 0 ;
84
95
while (src .getINode (i ) == dst .getINode (i )) {
85
96
i ++;
@@ -108,7 +119,7 @@ private static Pair<Optional<QuotaCounts>, Optional<QuotaCounts>> verifyQuotaFor
108
119
delta .subtract (counts );
109
120
}
110
121
FSDirectory .verifyQuota (dst , dst .length () - 1 , delta , src .getINode (i - 1 ));
111
- return Pair .of (srcDelta , dstDelta );
122
+ return Triple .of (true , srcDelta , dstDelta );
112
123
}
113
124
114
125
/**
@@ -216,10 +227,10 @@ static INodesInPath unprotectedRenameTo(FSDirectory fsd,
216
227
fsd .ezManager .checkMoveValidity (srcIIP , dstIIP );
217
228
// Ensure dst has quota to accommodate rename
218
229
verifyFsLimitsForRename (fsd , srcIIP , dstIIP );
219
- Pair < Optional <QuotaCounts >, Optional <QuotaCounts >> countPair =
220
- verifyQuotaForRename (fsd , srcIIP , dstIIP );
230
+ Triple < Boolean , Optional <QuotaCounts >, Optional <QuotaCounts >> countTriple =
231
+ verifyQuotaForRename (fsd , srcIIP , dstIIP , false );
221
232
222
- RenameOperation tx = new RenameOperation (fsd , srcIIP , dstIIP , countPair );
233
+ RenameOperation tx = new RenameOperation (fsd , srcIIP , dstIIP , countTriple );
223
234
224
235
boolean added = false ;
225
236
@@ -436,10 +447,10 @@ static RenameResult unprotectedRenameTo(FSDirectory fsd,
436
447
437
448
// Ensure dst has quota to accommodate rename
438
449
verifyFsLimitsForRename (fsd , srcIIP , dstIIP );
439
- Pair < Optional <QuotaCounts >, Optional <QuotaCounts >> quotaPair =
440
- verifyQuotaForRename (fsd , srcIIP , dstIIP );
450
+ Triple < Boolean , Optional <QuotaCounts >, Optional <QuotaCounts >> countTriple =
451
+ verifyQuotaForRename (fsd , srcIIP , dstIIP , overwrite );
441
452
442
- RenameOperation tx = new RenameOperation (fsd , srcIIP , dstIIP , quotaPair );
453
+ RenameOperation tx = new RenameOperation (fsd , srcIIP , dstIIP , countTriple );
443
454
444
455
boolean undoRemoveSrc = true ;
445
456
tx .removeSrc ();
@@ -656,13 +667,14 @@ private static class RenameOperation {
656
667
private final boolean srcChildIsReference ;
657
668
private final QuotaCounts oldSrcCountsInSnapshot ;
658
669
private final boolean sameStoragePolicy ;
670
+ private final boolean updateQuota ;
659
671
private final Optional <QuotaCounts > srcSubTreeCount ;
660
672
private final Optional <QuotaCounts > dstSubTreeCount ;
661
673
private INode srcChild ;
662
674
private INode oldDstChild ;
663
675
664
676
RenameOperation (FSDirectory fsd , INodesInPath srcIIP , INodesInPath dstIIP ,
665
- Pair < Optional <QuotaCounts >, Optional <QuotaCounts >> quotaPair ) {
677
+ Triple < Boolean , Optional <QuotaCounts >, Optional <QuotaCounts >> quotaPair ) {
666
678
this .fsd = fsd ;
667
679
this .srcIIP = srcIIP ;
668
680
this .dstIIP = dstIIP ;
@@ -711,9 +723,10 @@ private static class RenameOperation {
711
723
} else {
712
724
withCount = null ;
713
725
}
726
+ this .updateQuota = quotaPair .getLeft ();
714
727
// Set quota for src and dst, ignore src is in Snapshot or is Reference
715
728
this .srcSubTreeCount = withCount == null ?
716
- quotaPair .getLeft () : Optional .empty ();
729
+ quotaPair .getMiddle () : Optional .empty ();
717
730
this .dstSubTreeCount = quotaPair .getRight ();
718
731
}
719
732
@@ -757,7 +770,9 @@ long removeSrc() throws IOException {
757
770
// update the quota count if necessary
758
771
Optional <QuotaCounts > countOp = sameStoragePolicy ?
759
772
srcSubTreeCount : Optional .empty ();
760
- fsd .updateCountForDelete (srcChild , srcIIP , countOp );
773
+ if (updateQuota ) {
774
+ fsd .updateCountForDelete (srcChild , srcIIP , countOp );
775
+ }
761
776
srcIIP = INodesInPath .replace (srcIIP , srcIIP .length () - 1 , null );
762
777
return removedNum ;
763
778
}
@@ -774,7 +789,9 @@ boolean removeSrc4OldRename() {
774
789
// update the quota count if necessary
775
790
Optional <QuotaCounts > countOp = sameStoragePolicy ?
776
791
srcSubTreeCount : Optional .empty ();
777
- fsd .updateCountForDelete (srcChild , srcIIP , countOp );
792
+ if (updateQuota ) {
793
+ fsd .updateCountForDelete (srcChild , srcIIP , countOp );
794
+ }
778
795
srcIIP = INodesInPath .replace (srcIIP , srcIIP .length () - 1 , null );
779
796
return true ;
780
797
}
@@ -785,7 +802,9 @@ long removeDst() {
785
802
if (removedNum != -1 ) {
786
803
oldDstChild = dstIIP .getLastINode ();
787
804
// update the quota count if necessary
788
- fsd .updateCountForDelete (oldDstChild , dstIIP , dstSubTreeCount );
805
+ if (updateQuota ) {
806
+ fsd .updateCountForDelete (oldDstChild , dstIIP , dstSubTreeCount );
807
+ }
789
808
dstIIP = INodesInPath .replace (dstIIP , dstIIP .length () - 1 , null );
790
809
}
791
810
return removedNum ;
@@ -803,7 +822,7 @@ INodesInPath addSourceToDestination() {
803
822
toDst = new INodeReference .DstReference (dstParent .asDirectory (),
804
823
withCount , dstIIP .getLatestSnapshotId ());
805
824
}
806
- return fsd .addLastINodeNoQuotaCheck (dstParentIIP , toDst , srcSubTreeCount );
825
+ return fsd .addLastINodeNoQuotaCheck (dstParentIIP , toDst , srcSubTreeCount , updateQuota );
807
826
}
808
827
809
828
void updateMtimeAndLease (long timestamp ) {
@@ -837,7 +856,7 @@ void restoreSource() {
837
856
// the srcChild back
838
857
Optional <QuotaCounts > countOp = sameStoragePolicy ?
839
858
srcSubTreeCount : Optional .empty ();
840
- fsd .addLastINodeNoQuotaCheck (srcParentIIP , srcChild , countOp );
859
+ fsd .addLastINodeNoQuotaCheck (srcParentIIP , srcChild , countOp , updateQuota );
841
860
}
842
861
}
843
862
@@ -847,7 +866,7 @@ void restoreDst(BlockStoragePolicySuite bsps) {
847
866
if (dstParent .isWithSnapshot ()) {
848
867
dstParent .undoRename4DstParent (bsps , oldDstChild , dstIIP .getLatestSnapshotId ());
849
868
} else {
850
- fsd .addLastINodeNoQuotaCheck (dstParentIIP , oldDstChild , dstSubTreeCount );
869
+ fsd .addLastINodeNoQuotaCheck (dstParentIIP , oldDstChild , dstSubTreeCount , updateQuota );
851
870
}
852
871
if (oldDstChild != null && oldDstChild .isReference ()) {
853
872
final INodeReference removedDstRef = oldDstChild .asReference ();
0 commit comments