summaryrefslogtreecommitdiffstats
path: root/configserver
diff options
context:
space:
mode:
authorHenning Baldersheim <balder@yahoo-inc.com>2021-09-01 13:47:37 +0200
committerHenning Baldersheim <balder@yahoo-inc.com>2021-09-01 13:47:37 +0200
commitde376c730c93fd78f75bd8ec863e6dd7ce6b355f (patch)
treeda9ed5a1f5222028a0de911fe5c607c0e7fe9720 /configserver
parent597c10c93251eb88ecc6b850702dea9f63ababcf (diff)
Ensure that only one thread will compute the missing object in the cache. The others will wait.
Diffstat (limited to 'configserver')
-rw-r--r--configserver/src/main/java/com/yahoo/vespa/config/server/ServerCache.java27
-rw-r--r--configserver/src/main/java/com/yahoo/vespa/config/server/application/Application.java11
-rw-r--r--configserver/src/test/java/com/yahoo/vespa/config/server/ServerCacheTest.java6
3 files changed, 31 insertions, 13 deletions
diff --git a/configserver/src/main/java/com/yahoo/vespa/config/server/ServerCache.java b/configserver/src/main/java/com/yahoo/vespa/config/server/ServerCache.java
index ad544005ace..85bf5df3c71 100644
--- a/configserver/src/main/java/com/yahoo/vespa/config/server/ServerCache.java
+++ b/configserver/src/main/java/com/yahoo/vespa/config/server/ServerCache.java
@@ -9,6 +9,7 @@ import com.yahoo.vespa.config.protocol.ConfigResponse;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
+import java.util.function.Function;
/**
* Cache that holds configs and config definitions (builtin and user config definitions).
@@ -23,11 +24,14 @@ public class ServerCache {
// NOTE: The reason we do a double mapping here is to de-dupe configs that have the same md5.
private final Map<ConfigCacheKey, String> md5Sums = new ConcurrentHashMap<>();
private final Map<String, ConfigResponse> md5ToConfig = new ConcurrentHashMap<>();
-
+ private final Object [] stripedLocks = new Object[113];
public ServerCache(ConfigDefinitionRepo builtinConfigDefinitions, ConfigDefinitionRepo userConfigDefinitions) {
this.builtinConfigDefinitions = builtinConfigDefinitions;
this.userConfigDefinitions = userConfigDefinitions;
+ for (int i = 0; i < stripedLocks.length; i++) {
+ stripedLocks[i] = new Object();
+ }
}
// For testing only
@@ -35,17 +39,34 @@ public class ServerCache {
this(new StaticConfigDefinitionRepo(), new UserConfigDefinitionRepo());
}
- public void put(ConfigCacheKey key, ConfigResponse config, String configMd5) {
+ private void put(ConfigCacheKey key, ConfigResponse config) {
+ String configMd5 = config.getConfigMd5();
md5Sums.put(key, configMd5);
md5ToConfig.put(configMd5, config);
}
- public ConfigResponse get(ConfigCacheKey key) {
+ ConfigResponse get(ConfigCacheKey key) {
String md5 = md5Sums.get(key);
if (md5 == null) return null;
return md5ToConfig.get(md5);
}
+ public ConfigResponse computeIfAbsent(ConfigCacheKey key, Function<ConfigCacheKey, ConfigResponse> mappingFunction) {
+ ConfigResponse config = get(key);
+ if (config != null) {
+ return config;
+ }
+ synchronized (stripedLocks[Math.abs(key.hashCode()%stripedLocks.length)]) {
+ String md5 = md5Sums.get(key);
+ if (md5 == null) {
+ config = mappingFunction.apply(key);
+ put(key, config);
+ return config;
+ }
+ return md5ToConfig.get(md5);
+ }
+ }
+
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
diff --git a/configserver/src/main/java/com/yahoo/vespa/config/server/application/Application.java b/configserver/src/main/java/com/yahoo/vespa/config/server/application/Application.java
index 2133850e674..0afb3049f6e 100644
--- a/configserver/src/main/java/com/yahoo/vespa/config/server/application/Application.java
+++ b/configserver/src/main/java/com/yahoo/vespa/config/server/application/Application.java
@@ -111,15 +111,12 @@ public class Application implements ModelResult {
ConfigResponse config;
if (useCache(req)) {
- config = cache.get(cacheKey);
- if (config != null) {
- log.log(Level.FINE, () -> TenantRepository.logPre(getId()) + ("Found config " + cacheKey + " in cache"));
- } else {
- config = createConfigResponse(configKey, req, responseFactory);
- cache.put(cacheKey, config, config.getConfigMd5());
+ config = cache.computeIfAbsent(cacheKey, (ConfigCacheKey key) -> {
+ var response = createConfigResponse(configKey, req, responseFactory);
metricUpdater.setCacheConfigElems(cache.configElems());
metricUpdater.setCacheChecksumElems(cache.checkSumElems());
- }
+ return response;
+ });
} else {
config = createConfigResponse(configKey, req, responseFactory);
}
diff --git a/configserver/src/test/java/com/yahoo/vespa/config/server/ServerCacheTest.java b/configserver/src/test/java/com/yahoo/vespa/config/server/ServerCacheTest.java
index 35449238f78..9fca80b7a11 100644
--- a/configserver/src/test/java/com/yahoo/vespa/config/server/ServerCacheTest.java
+++ b/configserver/src/test/java/com/yahoo/vespa/config/server/ServerCacheTest.java
@@ -48,9 +48,9 @@ public class ServerCacheTest {
cache = new ServerCache(new TestConfigDefinitionRepo(), userConfigDefinitionRepo);
- cache.put(fooBarCacheKey, SlimeConfigResponse.fromConfigPayload(ConfigPayload.empty(), 2, false, configMd5), configMd5);
- cache.put(bazQuuxCacheKey, SlimeConfigResponse.fromConfigPayload(ConfigPayload.empty(), 2, false, configMd5), configMd5);
- cache.put(fooBarCacheKeyDifferentMd5, SlimeConfigResponse.fromConfigPayload(ConfigPayload.empty(), 2, false, configMd5_2), configMd5_2);
+ cache.computeIfAbsent(fooBarCacheKey, (ConfigCacheKey key) -> SlimeConfigResponse.fromConfigPayload(ConfigPayload.empty(), 2, false, configMd5));
+ cache.computeIfAbsent(bazQuuxCacheKey, (ConfigCacheKey key) -> SlimeConfigResponse.fromConfigPayload(ConfigPayload.empty(), 2, false, configMd5));
+ cache.computeIfAbsent(fooBarCacheKeyDifferentMd5, (ConfigCacheKey key) -> SlimeConfigResponse.fromConfigPayload(ConfigPayload.empty(), 2, false, configMd5_2));
}
@Test