Skip to content

Commit a9a8f66

Browse files
committed
Dynamic bucket id builder processing initial logic.
1 parent b49a7b0 commit a9a8f66

File tree

3 files changed

+60
-15
lines changed

3 files changed

+60
-15
lines changed

xds/src/main/java/io/grpc/xds/internal/rlqs/RlqsBucketId.java

+14-8
Original file line numberDiff line numberDiff line change
@@ -24,19 +24,25 @@
2424

2525
@AutoValue
2626
public abstract class RlqsBucketId {
27+
// No class loading deadlock, see
28+
// https://github.com/google/error-prone/issues/2062#issuecomment-1566253739
29+
public static final RlqsBucketId EMPTY = create(ImmutableMap.of());
30+
2731
public abstract ImmutableMap<String, String> bucketId();
2832

29-
public static RlqsBucketId create(ImmutableMap<String, String> bucketId) {
30-
return new AutoValue_RlqsBucketId(bucketId);
33+
public static RlqsBucketId create(Map<String, String> bucketIdMap) {
34+
if (bucketIdMap.isEmpty()) {
35+
return EMPTY;
36+
}
37+
return new AutoValue_RlqsBucketId(ImmutableMap.copyOf(bucketIdMap));
3138
}
3239

33-
public static RlqsBucketId fromEnvoyProto(BucketId envoyProto) {
34-
ImmutableMap.Builder<String, String> bucketId = ImmutableMap.builder();
35-
for (Map.Entry<String, String> entry : envoyProto.getBucketMap().entrySet()) {
36-
bucketId.put(entry.getKey(), entry.getValue());
37-
}
38-
return RlqsBucketId.create(bucketId.build());
40+
public final boolean isEmpty() {
41+
return bucketId().isEmpty();
42+
}
3943

44+
public static RlqsBucketId fromEnvoyProto(BucketId envoyProto) {
45+
return RlqsBucketId.create(ImmutableMap.copyOf(envoyProto.getBucketMap().entrySet()));
4046
}
4147

4248
@Memoized

xds/src/main/java/io/grpc/xds/internal/rlqs/RlqsBucketSettings.java

+44-5
Original file line numberDiff line numberDiff line change
@@ -17,22 +17,32 @@
1717
package io.grpc.xds.internal.rlqs;
1818

1919
import com.google.auto.value.AutoValue;
20-
import com.google.common.base.Function;
2120
import com.google.common.collect.ImmutableMap;
2221
import com.google.protobuf.Duration;
2322
import com.google.protobuf.util.Durations;
2423
import io.grpc.xds.internal.datatype.RateLimitStrategy;
2524
import io.grpc.xds.internal.matchers.HttpMatchInput;
2625
import io.grpc.xds.internal.rlqs.RlqsRateLimitResult.DenyResponse;
26+
import java.util.function.Function;
27+
import javax.annotation.Nullable;
2728

2829
@AutoValue
2930
public abstract class RlqsBucketSettings {
3031
// TODO(sergiitk): [IMPL] this misses most of the parsing and implementation.
3132

33+
@Nullable
3234
public abstract ImmutableMap<String, Function<HttpMatchInput, String>> bucketIdBuilder();
3335

34-
public RlqsBucketId toBucketId(HttpMatchInput input) {
35-
return null;
36+
abstract RlqsBucketId staticBucketId();
37+
38+
public abstract long reportingIntervalMillis();
39+
40+
public final RlqsBucketId toBucketId(HttpMatchInput input) {
41+
if (bucketIdBuilder() == null) {
42+
return staticBucketId();
43+
}
44+
ImmutableMap<String, String> bucketMap = processBucketBuilder(bucketIdBuilder(), input);
45+
return bucketMap != null ? RlqsBucketId.create(bucketMap) : RlqsBucketId.EMPTY;
3646
}
3747

3848
public RateLimitStrategy noAssignmentStrategy() {
@@ -47,11 +57,40 @@ public RateLimitStrategy expiredAssignmentStrategy() {
4757
return null;
4858
}
4959

50-
public abstract long reportingIntervalMillis();
5160

5261
public static RlqsBucketSettings create(
5362
ImmutableMap<String, Function<HttpMatchInput, String>> bucketIdBuilder,
5463
Duration reportingInterval) {
55-
return new AutoValue_RlqsBucketSettings(bucketIdBuilder, Durations.toMillis(reportingInterval));
64+
// TODO(sergiitk): instead of create, use Builder pattern.
65+
RlqsBucketId staticBucketId = generateStaticId(bucketIdBuilder);
66+
return new AutoValue_RlqsBucketSettings(
67+
staticBucketId.isEmpty() ? bucketIdBuilder : null,
68+
staticBucketId,
69+
Durations.toMillis(reportingInterval));
70+
}
71+
72+
private static RlqsBucketId generateStaticId(
73+
ImmutableMap<String, Function<HttpMatchInput, String>> bucketIdBuilder) {
74+
ImmutableMap<String, String> bucketIdMap = processBucketBuilder(bucketIdBuilder, null);
75+
return bucketIdMap.isEmpty() ? RlqsBucketId.EMPTY : RlqsBucketId.create(bucketIdMap);
76+
}
77+
78+
private static ImmutableMap<String, String> processBucketBuilder(
79+
ImmutableMap<String, Function<HttpMatchInput, String>> bucketIdBuilder,
80+
HttpMatchInput input) {
81+
ImmutableMap.Builder<String, String> result = ImmutableMap.builder();
82+
if (input == null) {
83+
// TODO(sergiitk): [IMPL] calculate static map
84+
return result.build();
85+
}
86+
for (String key : bucketIdBuilder.keySet()) {
87+
Function<HttpMatchInput, String> fn = bucketIdBuilder.get(key);
88+
String value = null;
89+
if (fn != null) {
90+
value = fn.apply(input);
91+
}
92+
result.put(key, value != null ? value : "");
93+
}
94+
return result.build();
5695
}
5796
}

xds/src/main/java/io/grpc/xds/internal/rlqs/RlqsEngine.java

+2-2
Original file line numberDiff line numberDiff line change
@@ -56,8 +56,8 @@ public RlqsEngine(
5656
public RlqsRateLimitResult rateLimit(HttpMatchInput input) {
5757
RlqsBucketSettings bucketSettings = bucketMatchers.match(input);
5858
RlqsBucketId bucketId = bucketSettings.toBucketId(input);
59-
// Special case when bucket id builder not set.
60-
if (bucketId == null) {
59+
// Special case when bucket id builder not set, or has no values.
60+
if (bucketId.isEmpty()) {
6161
return rateLimitWithoutReports(bucketSettings);
6262
}
6363
RlqsBucket bucket = bucketCache.getOrCreate(bucketId, bucketSettings, newBucket -> {

0 commit comments

Comments
 (0)