bug5627: change ShardingType such that encoding is not idempotent

This commit is contained in:
Axel Uhl
2023-01-03 18:23:03 +01:00
parent 141af431f6
commit 58898968ef
8 changed files with 21 additions and 28 deletions
@@ -28,13 +28,6 @@ public enum ShardingType {
this.prefix = prefix;
}
public String encodeIfNeeded(String shardingInfo) {
if (shardingInfo.startsWith(prefix)) {
return shardingInfo;
}
return encodeShardingInfo(shardingInfo);
}
public String encodeShardingInfo(String shardingInfo) {
return new StringBuilder().append(prefix).append(normalize(shardingInfo)).toString();
}
@@ -59,7 +59,7 @@ public class ShardingContext {
* @param shardingInfo
*/
public static void setShardingConstraint(ShardingType shardingType, String shardingInfo) {
final String encodedShardingInfo = shardingType.encodeIfNeeded(shardingInfo);
final String encodedShardingInfo = shardingType.encodeShardingInfo(shardingInfo);
ThreadLocal<String> shardingHolder = shardingMap.computeIfAbsent(shardingType, t -> new ThreadLocal<>());
checkAndSetShardingInfo(shardingType, encodedShardingInfo, shardingHolder);
}
@@ -89,7 +89,7 @@ public class ShardingContext {
logger.warning("No current sharding constraint for " + type.name());
return;
}
final String encodedShardingInfo = type.encodeIfNeeded(shardingInfo);
final String encodedShardingInfo = type.encodeShardingInfo(shardingInfo);
if (!encodedShardingInfo.equals(currentShardingInfo)) {
logger.log(Level.SEVERE, "Current sharding constraint vialation for " + type.name() + ". Got "
+ shardingInfo + ", shard requires " + currentShardingInfo, new RuntimeException());
@@ -11,6 +11,6 @@ public interface ProvidesLeaderboardRouting extends ServiceRoutingProvider {
String getLeaderboardName();
default String routingSuffixPath() {
return ShardingType.LEADERBOARDNAME.encodeIfNeeded(getLeaderboardName());
return ShardingType.LEADERBOARDNAME.encodeShardingInfo(getLeaderboardName());
}
}
@@ -81,7 +81,7 @@ public class SailingServerImpl extends SecuredServerImpl implements SailingServe
public String getLeaderboardShardingKey(String leaderboardName) throws Exception {
// We could try to acquire this from the "leaderboards" REST API endpoint, field shardingLeaderboardName,
// but we can as well shortcut it by replicating the implementation here:
return ShardingType.LEADERBOARDNAME.encodeIfNeeded(leaderboardName);
return ShardingType.LEADERBOARDNAME.encodeShardingInfo(leaderboardName);
}
/**
@@ -138,7 +138,7 @@ public abstract class AbstractLeaderboardsResource extends AbstractSailingServer
jsonLeaderboard.put("delayToLiveInMillis", leaderboard.getDelayToLiveInMillis());
jsonLeaderboard.put("resultState", resultState.name());
jsonLeaderboard.put("type", leaderboard.getLeaderboardType().name());
jsonLeaderboard.put("shardingLeaderboardName", ShardingType.LEADERBOARDNAME.encodeIfNeeded(leaderboard.getName()));
jsonLeaderboard.put("shardingLeaderboardName", ShardingType.LEADERBOARDNAME.encodeShardingInfo(leaderboard.getName()));
final ResultDiscardingRule resultDiscardingRule = leaderboard.getResultDiscardingRule();
if (resultDiscardingRule instanceof ThresholdBasedResultDiscardingRule) {
final ThresholdBasedResultDiscardingRule thresholdBasedResultDiscardingRule = (ThresholdBasedResultDiscardingRule) resultDiscardingRule;
@@ -8,10 +8,10 @@ import com.sap.sailing.domain.common.sharding.ShardingType;
public class ShardingLeaderBoardEncodingTest {
@Test
public void testEncoding() {
Assert.assertEquals("/leaderboard/pureascistring", ShardingType.LEADERBOARDNAME.encodeIfNeeded("pureascistring"));
Assert.assertEquals("/leaderboard/unpure_asci_string", ShardingType.LEADERBOARDNAME.encodeIfNeeded("unpure asci string"));
Assert.assertEquals("/leaderboard/c_dille", ShardingType.LEADERBOARDNAME.encodeIfNeeded("cédille"));
Assert.assertEquals("/leaderboard/Hello_World", ShardingType.LEADERBOARDNAME.encodeIfNeeded("Hello+World"));
Assert.assertEquals("/leaderboard/Hello_World_", ShardingType.LEADERBOARDNAME.encodeIfNeeded("Hello(World)"));
Assert.assertEquals("/leaderboard/pureascistring", ShardingType.LEADERBOARDNAME.encodeShardingInfo("pureascistring"));
Assert.assertEquals("/leaderboard/unpure_asci_string", ShardingType.LEADERBOARDNAME.encodeShardingInfo("unpure asci string"));
Assert.assertEquals("/leaderboard/c_dille", ShardingType.LEADERBOARDNAME.encodeShardingInfo("cédille"));
Assert.assertEquals("/leaderboard/Hello_World", ShardingType.LEADERBOARDNAME.encodeShardingInfo("Hello+World"));
Assert.assertEquals("/leaderboard/Hello_World_", ShardingType.LEADERBOARDNAME.encodeShardingInfo("Hello(World)"));
}
}
@@ -76,19 +76,19 @@ public class AppendShardingKeyToShard<ShardingKey, MetricsT extends ApplicationP
// check if there is a rule with space left for one or more additional conditions:
for (Rule r : shard.getRules()) {
boolean updateRule = false;
final ArrayList<String> keys = new ArrayList<>();
final ArrayList<String> paths = new ArrayList<>();
for (RuleCondition con : r.conditions()) {
if (con.pathPatternConfig() != null) {
keys.addAll(con.values());
paths.addAll(con.values());
}
}
while (keys.size() < ApplicationLoadBalancer.MAX_CONDITIONS_PER_RULE - NUMBER_OF_STANDARD_CONDITIONS_FOR_SHARDING_RULE
while (paths.size() < ApplicationLoadBalancer.MAX_CONDITIONS_PER_RULE - NUMBER_OF_STANDARD_CONDITIONS_FOR_SHARDING_RULE
&& !mutableShardingKeys.isEmpty()) {
keys.add(mutableShardingKeys.get(0));
paths.add(mutableShardingKeys.get(0));
mutableShardingKeys.remove(0);
updateRule = true;
}
final Collection<RuleCondition> ruleConditions = getShardingRuleConditions(loadBalancer, keys);
final Collection<RuleCondition> ruleConditions = getShardingRuleConditions(loadBalancer, paths);
// construct a rule only for transporting the conditions; no forwarding target is required for modifyRuleConditions
Rule proxyRuleWithNewConditions = Rule.builder().ruleArn(r.ruleArn()).conditions(ruleConditions).build();
if (updateRule) {
@@ -177,12 +177,12 @@ implements ProcedureCreatingLoadBalancerMapping<ShardingKey> {
* a header-field condition that requires the request to be tagged for a replica, plus a path-pattern condition with the
* sharding keys as patterns.
*
* @param shardingKeys their number must not exceed {@link ApplicationLoadBalancer#MAX_CONDITIONS_PER_RULE} - {@link #NUMBER_OF_STANDARD_CONDITIONS_FOR_SHARDING_RULE}
* @param paths their number must not exceed {@link ApplicationLoadBalancer#MAX_CONDITIONS_PER_RULE} - {@link #NUMBER_OF_STANDARD_CONDITIONS_FOR_SHARDING_RULE}
*/
protected Collection<RuleCondition> getShardingRuleConditions(ApplicationLoadBalancer<ShardingKey> loadBalancer, Collection<String> shardingKeys) throws InterruptedException, ExecutionException {
if (shardingKeys.size() > ApplicationLoadBalancer.MAX_CONDITIONS_PER_RULE - NUMBER_OF_RULES_PER_REPLICA_SET) {
throw new IllegalArgumentException("too many sharding keys for the conditions of a single load balancer rule: "+shardingKeys+
"; a maximum of "+(ApplicationLoadBalancer.MAX_CONDITIONS_PER_RULE - NUMBER_OF_RULES_PER_REPLICA_SET)+" is allowed");
protected Collection<RuleCondition> getShardingRuleConditions(ApplicationLoadBalancer<ShardingKey> loadBalancer, Collection<String> paths) throws InterruptedException, ExecutionException {
if (paths.size() > ApplicationLoadBalancer.MAX_CONDITIONS_PER_RULE - NUMBER_OF_STANDARD_CONDITIONS_FOR_SHARDING_RULE) {
throw new IllegalArgumentException("too many sharding keys for the conditions of a single load balancer rule: "+paths+
"; a maximum of "+(ApplicationLoadBalancer.MAX_CONDITIONS_PER_RULE - NUMBER_OF_STANDARD_CONDITIONS_FOR_SHARDING_RULE)+" is allowed");
}
final Collection<RuleCondition> ruleConditions = new ArrayList<>();
ruleConditions.add(loadBalancer.createHostHeaderRuleCondition(replicaSet.getHostname()));
@@ -191,7 +191,7 @@ implements ProcedureCreatingLoadBalancerMapping<ShardingKey> {
.values(HttpRequestHeaderConstants.HEADER_FORWARD_TO_REPLICA.getB()))
.build());
ruleConditions.add(
RuleCondition.builder().field("path-pattern").pathPatternConfig(hhcb -> hhcb.values(shardingKeys)).build());
RuleCondition.builder().field("path-pattern").pathPatternConfig(hhcb -> hhcb.values(paths)).build());
return ruleConditions;
}