diff options
author | Henning Baldersheim <balder@yahoo-inc.com> | 2021-09-01 13:47:37 +0200 |
---|---|---|
committer | Henning Baldersheim <balder@yahoo-inc.com> | 2021-09-01 13:47:37 +0200 |
commit | de376c730c93fd78f75bd8ec863e6dd7ce6b355f (patch) | |
tree | da9ed5a1f5222028a0de911fe5c607c0e7fe9720 /configserver | |
parent | 597c10c93251eb88ecc6b850702dea9f63ababcf (diff) |
Ensure that only one thread will compute the missing object in the cache. The others will wait.
Diffstat (limited to 'configserver')
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 |