Skip to content

Commit 0c19a9b

Browse files
HDDS-15076. Fix Incorrect pending deletion size for EC blocks in DN (#10105)
1 parent 72e69f0 commit 0c19a9b

18 files changed

Lines changed: 394 additions & 209 deletions

File tree

hadoop-hdds/container-service/src/main/java/org/apache/hadoop/ozone/container/common/statemachine/commandhandler/DeleteBlocksCommandHandler.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -649,16 +649,16 @@ private void updateMetaData(KeyValueContainerData containerData,
649649
// Update pending deletion blocks count, blocks bytes and delete transaction ID in in-memory container status.
650650
// Persist pending bytes only if the feature is finalized.
651651
if (VersionedDatanodeFeatures.isFinalized(
652-
HDDSLayoutFeature.STORAGE_SPACE_DISTRIBUTION) && delTX.hasTotalBlockSize()) {
652+
HDDSLayoutFeature.STORAGE_SPACE_DISTRIBUTION) && delTX.hasTotalSizePerReplica()) {
653653
long pendingBytes = containerData.getBlockPendingDeletionBytes();
654-
pendingBytes += delTX.getTotalBlockSize();
654+
pendingBytes += delTX.getTotalSizePerReplica();
655655
metadataTable
656656
.putWithBatch(batchOperation,
657657
containerData.getPendingDeleteBlockBytesKey(),
658658
pendingBytes);
659659
}
660660
containerData.incrPendingDeletionBlocks(newDeletionBlocks,
661-
delTX.hasTotalBlockSize() ? delTX.getTotalBlockSize() : 0);
661+
delTX.hasTotalSizePerReplica() ? delTX.getTotalSizePerReplica() : 0);
662662
containerData.updateDeleteTransactionId(delTX.getTxID());
663663
}
664664
}

hadoop-hdds/framework/src/main/java/org/apache/hadoop/ozone/common/BlockGroup.java

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ public KeyBlocks getProto() {
5050
kbb.addBlocks(deletedBlock.getBlockID().getProtobuf());
5151
kbb.addSize(deletedBlock.getSize());
5252
kbb.addReplicatedSize(deletedBlock.getReplicatedSize());
53+
kbb.addSizePerReplica(deletedBlock.getSizePerReplica());
5354
}
5455
return kbb.setKey(groupID).build();
5556
}
@@ -62,17 +63,21 @@ public KeyBlocks getProto() {
6263
public static BlockGroup getFromProto(KeyBlocks proto) {
6364
List<DeletedBlock> deletedBlocksList = new ArrayList<>();
6465
for (int i = 0; i < proto.getBlocksCount(); i++) {
65-
long repSize = SIZE_NOT_AVAILABLE;
6666
long size = SIZE_NOT_AVAILABLE;
67+
long repSize = SIZE_NOT_AVAILABLE;
68+
long sizePerReplica = SIZE_NOT_AVAILABLE;
6769
if (proto.getSizeCount() > i) {
6870
size = proto.getSize(i);
6971
}
7072
if (proto.getReplicatedSizeCount() > i) {
7173
repSize = proto.getReplicatedSize(i);
7274
}
75+
if (proto.getSizePerReplicaCount() > i) {
76+
sizePerReplica = proto.getSizePerReplica(i);
77+
}
7378
BlockID block = new BlockID(proto.getBlocks(i).getContainerBlockID().getContainerID(),
7479
proto.getBlocks(i).getContainerBlockID().getLocalID());
75-
deletedBlocksList.add(new DeletedBlock(block, size, repSize));
80+
deletedBlocksList.add(new DeletedBlock(block, size, repSize, sizePerReplica));
7681
}
7782
return BlockGroup.newBuilder().setKeyName(proto.getKey())
7883
.addAllDeletedBlocks(deletedBlocksList)

hadoop-hdds/framework/src/main/java/org/apache/hadoop/ozone/common/DeletedBlock.java

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,11 +27,13 @@ public class DeletedBlock {
2727
private BlockID blockID;
2828
private long size;
2929
private long replicatedSize;
30+
private long sizePerReplica;
3031

31-
public DeletedBlock(BlockID blockID, long size, long replicatedSize) {
32+
public DeletedBlock(BlockID blockID, long size, long replicatedSize, long sizePerReplica) {
3233
this.blockID = blockID;
3334
this.size = size;
3435
this.replicatedSize = replicatedSize;
36+
this.sizePerReplica = sizePerReplica;
3537
}
3638

3739
public BlockID getBlockID() {
@@ -46,13 +48,18 @@ public long getReplicatedSize() {
4648
return this.replicatedSize;
4749
}
4850

51+
public long getSizePerReplica() {
52+
return this.sizePerReplica;
53+
}
54+
4955
@Override
5056
public String toString() {
5157
StringBuilder sb = new StringBuilder(64);
5258
sb.append(" localID: ").append(blockID.getContainerBlockID().getLocalID())
5359
.append(" containerID: ").append(blockID.getContainerBlockID().getContainerID())
5460
.append(" size: ").append(size)
55-
.append(" replicatedSize: ").append(replicatedSize);
61+
.append(" replicatedSize: ").append(replicatedSize)
62+
.append(" sizePerReplica: ").append(sizePerReplica);
5663
return sb.toString();
5764
}
5865
}

hadoop-hdds/interface-server/src/main/proto/ScmServerDatanodeHeartbeatProtocol.proto

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -377,6 +377,7 @@ message DeletedBlocksTransaction {
377377
optional int32 count = 4 [deprecated=true];
378378
optional uint64 totalBlockSize = 5;
379379
optional uint64 totalBlockReplicatedSize = 6;
380+
optional uint64 totalSizePerReplica = 7;
380381
}
381382

382383
// ACK message datanode sent to SCM, contains the result of

hadoop-hdds/interface-server/src/main/proto/ScmServerProtocol.proto

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,7 @@ message KeyBlocks {
183183
repeated BlockID blocks = 2;
184184
repeated uint64 size = 3;
185185
repeated uint64 replicatedSize = 4;
186+
repeated uint64 sizePerReplica = 5;
186187
}
187188

188189
/**

hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/block/DeletedBlockLogImpl.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,11 @@ private DeletedBlocksTransaction constructNewTransaction(
171171
builder.setTotalBlockReplicatedSize(replicatedSize);
172172
builder.setTotalBlockSize(blocks.stream().mapToLong(DeletedBlock::getSize).sum());
173173
}
174+
175+
long sizePerReplica = blocks.stream().mapToLong(DeletedBlock::getSizePerReplica).sum();
176+
if (sizePerReplica >= 0) {
177+
builder.setTotalSizePerReplica(sizePerReplica);
178+
}
174179
}
175180
return builder.build();
176181
}

hadoop-hdds/server-scm/src/test/java/org/apache/hadoop/hdds/scm/block/TestDeletedBlockLog.java

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -231,7 +231,8 @@ private Map<Long, List<DeletedBlock>> generateData(int txCount,
231231
updateContainerMetadata(containerID, state);
232232
for (int j = 0; j < BLOCKS_PER_TXN; j++) {
233233
long localID = localIDBase + j;
234-
blocks.add(new DeletedBlock(new BlockID(containerID, localID), blockSize + j, blockSize + j));
234+
blocks.add(new DeletedBlock(new BlockID(containerID, localID),
235+
blockSize + j, blockSize + j, blockSize + j));
235236
}
236237
blockMap.put(containerID, blocks);
237238
}
@@ -733,7 +734,8 @@ public void testDeletedBlockTransactions() throws IOException {
733734
Map<Long, List<DeletedBlock>> deletedBlocksMap = new HashMap<>();
734735
long localId = RandomUtils.secure().randomLong();
735736
List<DeletedBlock> blockIDList = new ArrayList<>();
736-
blockIDList.add(new DeletedBlock(new BlockID(containerID, localId), SIZE_NOT_AVAILABLE, SIZE_NOT_AVAILABLE));
737+
blockIDList.add(new DeletedBlock(new BlockID(containerID, localId),
738+
SIZE_NOT_AVAILABLE, SIZE_NOT_AVAILABLE, SIZE_NOT_AVAILABLE));
737739
deletedBlocksMap.put(containerID, blockIDList);
738740
addTransactions(deletedBlocksMap, true);
739741
blocks = getTransactions(txNum * BLOCKS_PER_TXN * ONE);
@@ -808,7 +810,8 @@ public void testTransactionSerializedSize(int blockCount) {
808810
long containerID = 1000000;
809811
List<DeletedBlock> blocks = new ArrayList<>();
810812
for (int i = 0; i < blockCount; i++) {
811-
blocks.add(new DeletedBlock(new BlockID(containerID, 100000000 + i), 128 * 1024 * 1024, 128 * 1024 * 1024));
813+
blocks.add(new DeletedBlock(new BlockID(containerID, 100000000 + i),
814+
128 * 1024 * 1024, 128 * 1024 * 1024, 128 * 1024 * 1024));
812815
}
813816
List<Long> localIdList = blocks.stream().map(b -> b.getBlockID().getLocalID()).collect(Collectors.toList());
814817
DeletedBlocksTransaction tx1 = DeletedBlocksTransaction.newBuilder()
@@ -818,6 +821,7 @@ public void testTransactionSerializedSize(int blockCount) {
818821
.setCount(0)
819822
.setTotalBlockSize(blocks.stream().mapToLong(DeletedBlock::getSize).sum())
820823
.setTotalBlockReplicatedSize(blocks.stream().mapToLong(DeletedBlock::getReplicatedSize).sum())
824+
.setTotalSizePerReplica(blocks.stream().mapToLong(DeletedBlock::getSizePerReplica).sum())
821825
.build();
822826
DeletedBlocksTransaction tx2 = DeletedBlocksTransaction.newBuilder()
823827
.setTxID(txID)

hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/om/helpers/QuotaUtil.java

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,27 @@ public static long getReplicatedSize(
6666
}
6767
}
6868

69+
/**
70+
* Calculate the physical bytes stored on a single DataNode for one block.
71+
* For RATIS each DN holds a full copy, so the per-replica size equals the
72+
* logical block size. For EC each DN holds one chunk per stripe, so the
73+
* per-replica size is {@code replicatedSize / requiredNodes}.
74+
*
75+
* @param dataSize logical (unreplicated) block size in bytes
76+
* @param repConfig replication configuration
77+
* @return bytes stored on a single DN for this block
78+
*/
79+
public static long getSizePerReplica(long dataSize, ReplicationConfig repConfig) {
80+
if (repConfig.getReplicationType() == RATIS) {
81+
return dataSize;
82+
}
83+
int requiredNodes = repConfig.getRequiredNodes();
84+
if (requiredNodes <= 0) {
85+
return dataSize;
86+
}
87+
return getReplicatedSize(dataSize, repConfig) / requiredNodes;
88+
}
89+
6990
/**
7091
* Get an estimated data size (before replication) from the replicated size.
7192
* An (inaccurate) reverse of getReplicatedSize().

hadoop-ozone/common/src/test/java/org/apache/hadoop/ozone/om/helpers/TestQuotaUtil.java

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,4 +97,28 @@ public void testECPartialSingleBeyondFirstChunk() {
9797
assertEquals(dataSize + ONE_MB * 2, replicatedSize);
9898
}
9999

100+
@Test
101+
public void testGetSizePerReplicaRatisThree() {
102+
ReplicationConfig repConfig = RatisReplicationConfig.getInstance(THREE);
103+
// Each of the 3 DNs holds the full block, so per-replica == logical size.
104+
assertEquals(123 * ONE_MB, QuotaUtil.getSizePerReplica(123 * ONE_MB, repConfig));
105+
}
106+
107+
@Test
108+
public void testGetSizePerReplicaRatisOne() {
109+
ReplicationConfig repConfig = RatisReplicationConfig.getInstance(ONE);
110+
assertEquals(123 * ONE_MB, QuotaUtil.getSizePerReplica(123 * ONE_MB, repConfig));
111+
}
112+
113+
@Test
114+
public void testGetSizePerReplicaEC() {
115+
// EC(3,2): 5 nodes total. replicatedSize = dataSize + parity overhead.
116+
// Per-replica = replicatedSize / 5.
117+
ECReplicationConfig repConfig = new ECReplicationConfig(3, 2, RS, ONE_MB);
118+
long dataSize = ONE_MB * 3 * 10; // 10 full stripes
119+
long replicatedSize = QuotaUtil.getReplicatedSize(dataSize, repConfig);
120+
long expected = replicatedSize / repConfig.getRequiredNodes(); // / 5
121+
assertEquals(expected, QuotaUtil.getSizePerReplica(dataSize, repConfig));
122+
}
123+
100124
}

0 commit comments

Comments
 (0)