Skip to content

Commit 72fa965

Browse files
authored
HDDS-15602. Read pipeline ID does not need to use secure random (#10571)
1 parent 08a23a9 commit 72fa965

7 files changed

Lines changed: 73 additions & 42 deletions

File tree

hadoop-hdds/common/src/main/java/org/apache/hadoop/hdds/scm/pipeline/PipelineID.java

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,14 @@
1818
package org.apache.hadoop.hdds.scm.pipeline;
1919

2020
import com.fasterxml.jackson.annotation.JsonIgnore;
21+
import java.nio.ByteBuffer;
2122
import java.util.UUID;
2223
import java.util.function.Supplier;
2324
import org.apache.hadoop.hdds.protocol.proto.HddsProtos;
2425
import org.apache.hadoop.hdds.utils.db.Codec;
2526
import org.apache.hadoop.hdds.utils.db.DelegatedCodec;
2627
import org.apache.hadoop.hdds.utils.db.UuidCodec;
28+
import org.apache.hadoop.ozone.util.UUIDUtil;
2729
import org.apache.ratis.util.MemoizedSupplier;
2830

2931
/**
@@ -52,6 +54,19 @@ public static PipelineID randomId() {
5254
return new PipelineID(UUID.randomUUID());
5355
}
5456

57+
/**
58+
* Generates a random PipelineID using {@link java.util.Random} instead of
59+
* {@link java.security.SecureRandom}. This avoids contention on the shared
60+
* {@code SecureRandom} instance and is suitable for non-sensitive,
61+
* throwaway IDs such as read pipelines, where predictability of the next
62+
* ID has no security impact.
63+
*/
64+
public static PipelineID insecureRandomId() {
65+
byte[] bytes = UUIDUtil.insecureRandomUUIDBytes();
66+
ByteBuffer buf = ByteBuffer.wrap(bytes);
67+
return new PipelineID(new UUID(buf.getLong(), buf.getLong()));
68+
}
69+
5570
public static PipelineID valueOf(UUID id) {
5671
return new PipelineID(id);
5772
}

hadoop-hdds/common/src/main/java/org/apache/hadoop/ozone/util/UUIDUtil.java

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,16 +18,27 @@
1818
package org.apache.hadoop.ozone.util;
1919

2020
import java.security.SecureRandom;
21+
import java.util.Random;
22+
import java.util.function.Consumer;
2123

2224
/**
2325
* Helper methods to deal with random UUIDs.
2426
*/
2527
public final class UUIDUtil {
2628
private static final ThreadLocal<SecureRandom> GENERATOR = ThreadLocal.withInitial(SecureRandom::new);
29+
private static final ThreadLocal<Random> INSECURE_GENERATOR = ThreadLocal.withInitial(Random::new);
2730

2831
public static byte[] randomUUIDBytes() {
32+
return getUUIDBytes(GENERATOR.get()::nextBytes);
33+
}
34+
35+
public static byte[] insecureRandomUUIDBytes() {
36+
return getUUIDBytes(INSECURE_GENERATOR.get()::nextBytes);
37+
}
38+
39+
private static byte[] getUUIDBytes(Consumer<byte[]> generator) {
2940
final byte[] bytes = new byte[16];
30-
GENERATOR.get().nextBytes(bytes);
41+
generator.accept(bytes);
3142
// See RFC 4122 section 4.4
3243
bytes[6] &= 0x0f;
3344
bytes[6] |= 0x40;

hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/container/ContainerReplica.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,10 @@
1717

1818
package org.apache.hadoop.hdds.scm.container;
1919

20+
import java.util.List;
2021
import java.util.Objects;
22+
import java.util.Set;
23+
import java.util.stream.Collectors;
2124
import org.apache.commons.lang3.builder.CompareToBuilder;
2225
import org.apache.commons.lang3.builder.EqualsBuilder;
2326
import org.apache.commons.lang3.builder.HashCodeBuilder;
@@ -165,6 +168,12 @@ public int compareTo(ContainerReplica that) {
165168
.build();
166169
}
167170

171+
public static List<DatanodeDetails> toDatanodeDetailsList(Set<ContainerReplica> replicas) {
172+
return replicas.stream()
173+
.map(ContainerReplica::getDatanodeDetails)
174+
.collect(Collectors.toList());
175+
}
176+
168177
/**
169178
* Returns a new Builder to construct ContainerReplica.
170179
*

hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/pipeline/ECPipelineProvider.java

Lines changed: 9 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,10 @@ protected Pipeline create(ECReplicationConfig replicationConfig,
103103
ecIndex++;
104104
}
105105

106-
return createPipelineInternal(replicationConfig, nodes, dnIndexes);
106+
return newPipelineBuilder(replicationConfig, nodes)
107+
.setId(PipelineID.randomId())
108+
.setReplicaIndexes(dnIndexes)
109+
.build();
107110
}
108111

109112
@Override
@@ -130,17 +133,11 @@ public Pipeline createForRead(
130133

131134
dns.sort(Comparator.comparing(nodeStatusMap::get, CREATE_FOR_READ_COMPARATOR));
132135

133-
return createPipelineInternal(replicationConfig, dns, map);
134-
}
135-
136-
private Pipeline createPipelineInternal(ECReplicationConfig repConfig,
137-
List<DatanodeDetails> dns, Map<DatanodeDetails, Integer> indexes) {
138-
return Pipeline.newBuilder()
139-
.setId(PipelineID.randomId())
140-
.setState(Pipeline.PipelineState.ALLOCATED)
141-
.setReplicationConfig(repConfig)
142-
.setNodes(dns)
143-
.setReplicaIndexes(indexes)
136+
// Use insecureRandomId for throwaway read pipeline IDs to avoid
137+
// contention on the shared SecureRandom instance.
138+
return newPipelineBuilder(replicationConfig, dns)
139+
.setId(PipelineID.insecureRandomId())
140+
.setReplicaIndexes(map)
144141
.build();
145142
}
146143

hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/pipeline/PipelineProvider.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,4 +139,11 @@ List<DatanodeDetails> pickAllNodesNotUsed(
139139
}
140140
return dns;
141141
}
142+
143+
protected Pipeline.Builder newPipelineBuilder(ReplicationConfig replicationConfig, List<DatanodeDetails> nodes) {
144+
return Pipeline.newBuilder()
145+
.setNodes(nodes)
146+
.setReplicationConfig(replicationConfig)
147+
.setState(Pipeline.PipelineState.ALLOCATED);
148+
}
142149
}

hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/pipeline/RatisPipelineProvider.java

Lines changed: 8 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@
2323
import java.util.Collections;
2424
import java.util.List;
2525
import java.util.Set;
26-
import java.util.stream.Collectors;
2726
import org.apache.hadoop.hdds.client.RatisReplicationConfig;
2827
import org.apache.hadoop.hdds.conf.ConfigurationSource;
2928
import org.apache.hadoop.hdds.conf.StorageUnit;
@@ -182,13 +181,9 @@ public synchronized Pipeline create(RatisReplicationConfig replicationConfig,
182181

183182
DatanodeDetails suggestedLeader = leaderChoosePolicy.chooseLeader(dns);
184183

185-
Pipeline pipeline = Pipeline.newBuilder()
184+
Pipeline pipeline = newPipelineBuilder(RatisReplicationConfig.getInstance(factor), dns)
186185
.setId(PipelineID.randomId())
187-
.setState(PipelineState.ALLOCATED)
188-
.setReplicationConfig(RatisReplicationConfig.getInstance(factor))
189-
.setNodes(dns)
190-
.setSuggestedLeaderId(
191-
suggestedLeader != null ? suggestedLeader.getID() : null)
186+
.setSuggestedLeaderId(suggestedLeader != null ? suggestedLeader.getID() : null)
192187
.build();
193188

194189
// Send command to datanodes to create pipeline
@@ -213,22 +208,20 @@ public synchronized Pipeline create(RatisReplicationConfig replicationConfig,
213208
@Override
214209
public Pipeline create(RatisReplicationConfig replicationConfig,
215210
List<DatanodeDetails> nodes) {
216-
return Pipeline.newBuilder()
211+
return newPipelineBuilder(replicationConfig, nodes)
217212
.setId(PipelineID.randomId())
218-
.setState(PipelineState.ALLOCATED)
219-
.setReplicationConfig(replicationConfig)
220-
.setNodes(nodes)
221213
.build();
222214
}
223215

224216
@Override
225217
public Pipeline createForRead(
226218
RatisReplicationConfig replicationConfig,
227219
Set<ContainerReplica> replicas) {
228-
return create(replicationConfig, replicas
229-
.stream()
230-
.map(ContainerReplica::getDatanodeDetails)
231-
.collect(Collectors.toList()));
220+
// Use insecureRandomId for throwaway read pipeline IDs to avoid
221+
// contention on the shared SecureRandom instance.
222+
return newPipelineBuilder(replicationConfig, ContainerReplica.toDatanodeDetailsList(replicas))
223+
.setId(PipelineID.insecureRandomId())
224+
.build();
232225
}
233226

234227
private List<DatanodeDetails> filterPipelineEngagement() {

hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/pipeline/SimplePipelineProvider.java

Lines changed: 13 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
import java.util.Collections;
2222
import java.util.List;
2323
import java.util.Set;
24-
import java.util.stream.Collectors;
24+
import org.apache.hadoop.hdds.client.ReplicationConfig;
2525
import org.apache.hadoop.hdds.client.StandaloneReplicationConfig;
2626
import org.apache.hadoop.hdds.protocol.DatanodeDetails;
2727
import org.apache.hadoop.hdds.scm.container.ContainerReplica;
@@ -61,38 +61,37 @@ public Pipeline create(StandaloneReplicationConfig replicationConfig,
6161
}
6262

6363
Collections.shuffle(dns);
64-
return Pipeline.newBuilder()
64+
return newPipelineBuilder(replicationConfig, dns.subList(0, replicationConfig.getReplicationFactor().getNumber()))
6565
.setId(PipelineID.randomId())
66-
.setState(PipelineState.OPEN)
67-
.setReplicationConfig(replicationConfig)
68-
.setNodes(dns.subList(0,
69-
replicationConfig.getReplicationFactor().getNumber()))
7066
.build();
7167
}
7268

7369
@Override
7470
public Pipeline create(StandaloneReplicationConfig replicationConfig,
7571
List<DatanodeDetails> nodes) {
76-
return Pipeline.newBuilder()
72+
return newPipelineBuilder(replicationConfig, nodes)
7773
.setId(PipelineID.randomId())
78-
.setState(PipelineState.OPEN)
79-
.setReplicationConfig(replicationConfig)
80-
.setNodes(nodes)
8174
.build();
8275
}
8376

8477
@Override
8578
public Pipeline createForRead(StandaloneReplicationConfig replicationConfig,
8679
Set<ContainerReplica> replicas) {
87-
return create(replicationConfig, replicas
88-
.stream()
89-
.map(ContainerReplica::getDatanodeDetails)
90-
.collect(Collectors.toList()));
80+
// Use insecureRandomId for throwaway read pipeline IDs to avoid
81+
// contention on the shared SecureRandom instance.
82+
return newPipelineBuilder(replicationConfig, ContainerReplica.toDatanodeDetailsList(replicas))
83+
.setId(PipelineID.insecureRandomId())
84+
.build();
9185
}
9286

9387
@Override
9488
public void close(Pipeline pipeline) throws IOException {
9589

9690
}
9791

92+
@Override
93+
protected Pipeline.Builder newPipelineBuilder(ReplicationConfig replicationConfig, List<DatanodeDetails> nodes) {
94+
return super.newPipelineBuilder(replicationConfig, nodes)
95+
.setState(PipelineState.OPEN);
96+
}
9897
}

0 commit comments

Comments
 (0)