Skip to content

Commit 630067d

Browse files
authored
Core: Add jitter for cache (prebid#3135)
1 parent ec2670f commit 630067d

File tree

7 files changed

+109
-22
lines changed

7 files changed

+109
-22
lines changed

docs/config-app.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -340,6 +340,7 @@ See [application settings](application-settings.md) for full reference of availa
340340
For caching available next options:
341341
- `settings.in-memory-cache.ttl-seconds` - how long (in seconds) data will be available in LRU cache.
342342
- `settings.in-memory-cache.cache-size` - the size of LRU cache.
343+
- `settings.in-memory-cache.jitter-seconds` - jitter (in seconds) for `settings.in-memory-cache.ttl-seconds` parameter.
343344
- `settings.in-memory-cache.notification-endpoints-enabled` - if equals to `true` two additional endpoints will be
344345
available: [/storedrequests/openrtb2](endpoints/storedrequests/openrtb2.md) and [/storedrequests/amp](endpoints/storedrequests/amp.md).
345346
- `settings.in-memory-cache.account-invalidation-enabled` - if equals to `true` additional admin protected endpoints will be

src/main/java/org/prebid/server/activity/infrastructure/creator/privacy/uscustomlogic/USCustomLogicModuleCreator.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ public USCustomLogicModuleCreator(USCustomLogicGppReaderFactory gppReaderFactory
5555
this.metrics = Objects.requireNonNull(metrics);
5656

5757
jsonLogicNodesCache = cacheTtl != null && cacheSize != null
58-
? SettingsCache.createCache(cacheTtl, cacheSize)
58+
? SettingsCache.createCache(cacheTtl, cacheSize, 0)
5959
: null;
6060
}
6161

src/main/java/org/prebid/server/settings/CachingApplicationSettings.java

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -48,16 +48,21 @@ public CachingApplicationSettings(ApplicationSettings delegate,
4848
SettingsCache videoCache,
4949
Metrics metrics,
5050
int ttl,
51-
int size) {
51+
int size,
52+
int jitter) {
5253

5354
if (ttl <= 0 || size <= 0) {
5455
throw new IllegalArgumentException("ttl and size must be positive");
5556
}
57+
if (jitter < 0 || jitter >= ttl) {
58+
throw new IllegalArgumentException("jitter must match the inequality: 0 <= jitter < ttl");
59+
}
60+
5661
this.delegate = Objects.requireNonNull(delegate);
57-
this.accountCache = SettingsCache.createCache(ttl, size);
58-
this.accountToErrorCache = SettingsCache.createCache(ttl, size);
59-
this.adServerPublisherToErrorCache = SettingsCache.createCache(ttl, size);
60-
this.categoryConfigCache = SettingsCache.createCache(ttl, size);
62+
this.accountCache = SettingsCache.createCache(ttl, size, jitter);
63+
this.accountToErrorCache = SettingsCache.createCache(ttl, size, jitter);
64+
this.adServerPublisherToErrorCache = SettingsCache.createCache(ttl, size, jitter);
65+
this.categoryConfigCache = SettingsCache.createCache(ttl, size, jitter);
6166
this.cache = Objects.requireNonNull(cache);
6267
this.ampCache = Objects.requireNonNull(ampCache);
6368
this.videoCache = Objects.requireNonNull(videoCache);

src/main/java/org/prebid/server/settings/SettingsCache.java

Lines changed: 75 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,18 @@
11
package org.prebid.server.settings;
22

33
import com.github.benmanes.caffeine.cache.Caffeine;
4+
import com.github.benmanes.caffeine.cache.Expiry;
45
import org.apache.commons.collections4.MapUtils;
56
import org.apache.commons.lang3.ObjectUtils;
7+
import org.checkerframework.checker.index.qual.NonNegative;
68
import org.prebid.server.settings.model.StoredItem;
79

810
import java.util.Collections;
911
import java.util.HashSet;
1012
import java.util.List;
1113
import java.util.Map;
1214
import java.util.Set;
13-
import java.util.concurrent.TimeUnit;
15+
import java.util.concurrent.ThreadLocalRandom;
1416

1517
/**
1618
* Just a simple wrapper over in-memory caches for requests and imps.
@@ -20,17 +22,26 @@ public class SettingsCache implements CacheNotificationListener {
2022
private final Map<String, Set<StoredItem>> requestCache;
2123
private final Map<String, Set<StoredItem>> impCache;
2224

23-
public SettingsCache(int ttl, int size) {
25+
public SettingsCache(int ttl, int size, int jitter) {
2426
if (ttl <= 0 || size <= 0) {
2527
throw new IllegalArgumentException("ttl and size must be positive");
2628
}
27-
requestCache = createCache(ttl, size);
28-
impCache = createCache(ttl, size);
29+
if (jitter < 0 || jitter >= ttl) {
30+
throw new IllegalArgumentException("jitter must match the inequality: 0 <= jitter < ttl");
31+
}
32+
33+
requestCache = createCache(ttl, size, jitter);
34+
impCache = createCache(ttl, size, jitter);
2935
}
3036

31-
public static <T> Map<String, T> createCache(int ttl, int size) {
37+
public static <T> Map<String, T> createCache(int ttlSeconds, int size, int jitterSeconds) {
38+
final long expireAfterNanos = (long) (ttlSeconds * 1e9);
39+
final long jitterNanos = jitterSeconds == 0 ? 0L : (long) (jitterSeconds * 1e9);
40+
3241
return Caffeine.newBuilder()
33-
.expireAfterWrite(ttl, TimeUnit.SECONDS)
42+
.expireAfter(jitterNanos == 0L
43+
? new StaticExpiry<>(expireAfterNanos)
44+
: new ExpiryWithJitter<>(expireAfterNanos, jitterNanos))
3445
.maximumSize(size)
3546
.<String, T>build()
3647
.asMap();
@@ -53,7 +64,10 @@ void saveImpCache(String accountId, String impId, String impValue) {
5364
}
5465

5566
private static void saveCachedValue(Map<String, Set<StoredItem>> cache,
56-
String accountId, String id, String value) {
67+
String accountId,
68+
String id,
69+
String value) {
70+
5771
final Set<StoredItem> values = ObjectUtils.defaultIfNull(cache.get(id), new HashSet<>());
5872
values.add(StoredItem.of(accountId, value));
5973
cache.put(id, values);
@@ -79,4 +93,58 @@ public void invalidate(List<String> requests, List<String> imps) {
7993
requests.forEach(requestCache.keySet()::remove);
8094
imps.forEach(impCache.keySet()::remove);
8195
}
96+
97+
private static class StaticExpiry<K, V> implements Expiry<K, V> {
98+
99+
private final long expireAfterNanos;
100+
101+
private StaticExpiry(long expireAfterNanos) {
102+
this.expireAfterNanos = expireAfterNanos;
103+
}
104+
105+
@Override
106+
public long expireAfterCreate(K key, V value, long currentTime) {
107+
return expireAfterNanos;
108+
}
109+
110+
@Override
111+
public long expireAfterUpdate(K key, V value, long currentTime, @NonNegative long currentDuration) {
112+
return expireAfterNanos;
113+
}
114+
115+
@Override
116+
public long expireAfterRead(K key, V value, long currentTime, @NonNegative long currentDuration) {
117+
return currentDuration;
118+
}
119+
}
120+
121+
private static class ExpiryWithJitter<K, V> implements Expiry<K, V> {
122+
123+
private final Expiry<K, V> baseExpiry;
124+
private final long jitterNanos;
125+
126+
private ExpiryWithJitter(long baseExpireAfterNanos, long jitterNanos) {
127+
this.baseExpiry = new StaticExpiry<>(baseExpireAfterNanos);
128+
this.jitterNanos = jitterNanos;
129+
}
130+
131+
@Override
132+
public long expireAfterCreate(K key, V value, long currentTime) {
133+
return baseExpiry.expireAfterCreate(key, value, currentTime) + jitter();
134+
}
135+
136+
@Override
137+
public long expireAfterUpdate(K key, V value, long currentTime, @NonNegative long currentDuration) {
138+
return baseExpiry.expireAfterUpdate(key, value, currentTime, currentDuration) + jitter();
139+
}
140+
141+
@Override
142+
public long expireAfterRead(K key, V value, long currentTime, @NonNegative long currentDuration) {
143+
return baseExpiry.expireAfterRead(key, value, currentTime, currentDuration);
144+
}
145+
146+
private long jitter() {
147+
return ThreadLocalRandom.current().nextLong(-jitterNanos, jitterNanos);
148+
}
149+
}
82150
}

src/main/java/org/prebid/server/spring/config/SettingsConfiguration.java

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -284,7 +284,8 @@ CachingApplicationSettings cachingApplicationSettings(
284284
videoCache,
285285
metrics,
286286
cacheProperties.getTtlSeconds(),
287-
cacheProperties.getCacheSize());
287+
cacheProperties.getCacheSize(),
288+
cacheProperties.getJitterSeconds());
288289
}
289290
}
290291

@@ -306,19 +307,28 @@ static class CacheConfiguration {
306307
@Bean
307308
@Qualifier("settingsCache")
308309
SettingsCache settingsCache(ApplicationSettingsCacheProperties cacheProperties) {
309-
return new SettingsCache(cacheProperties.getTtlSeconds(), cacheProperties.getCacheSize());
310+
return new SettingsCache(
311+
cacheProperties.getTtlSeconds(),
312+
cacheProperties.getCacheSize(),
313+
cacheProperties.getJitterSeconds());
310314
}
311315

312316
@Bean
313317
@Qualifier("ampSettingsCache")
314318
SettingsCache ampSettingsCache(ApplicationSettingsCacheProperties cacheProperties) {
315-
return new SettingsCache(cacheProperties.getTtlSeconds(), cacheProperties.getCacheSize());
319+
return new SettingsCache(
320+
cacheProperties.getTtlSeconds(),
321+
cacheProperties.getCacheSize(),
322+
cacheProperties.getJitterSeconds());
316323
}
317324

318325
@Bean
319326
@Qualifier("videoSettingCache")
320327
SettingsCache videoSettingCache(ApplicationSettingsCacheProperties cacheProperties) {
321-
return new SettingsCache(cacheProperties.getTtlSeconds(), cacheProperties.getCacheSize());
328+
return new SettingsCache(
329+
cacheProperties.getTtlSeconds(),
330+
cacheProperties.getCacheSize(),
331+
cacheProperties.getJitterSeconds());
322332
}
323333
}
324334

@@ -336,5 +346,7 @@ private static class ApplicationSettingsCacheProperties {
336346
@NotNull
337347
@Min(1)
338348
private Integer cacheSize;
349+
@Min(0)
350+
private int jitterSeconds;
339351
}
340352
}

src/test/java/org/prebid/server/settings/CachingApplicationSettingsTest.java

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -61,12 +61,13 @@ public void setUp() {
6161

6262
target = new CachingApplicationSettings(
6363
delegateSettings,
64-
new SettingsCache(360, 100),
65-
new SettingsCache(360, 100),
66-
new SettingsCache(360, 100),
64+
new SettingsCache(360, 100, 0),
65+
new SettingsCache(360, 100, 0),
66+
new SettingsCache(360, 100, 0),
6767
metrics,
6868
360,
69-
100);
69+
100,
70+
0);
7071
}
7172

7273
@Test

src/test/java/org/prebid/server/settings/SettingsCacheTest.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ public class SettingsCacheTest {
1515

1616
@Before
1717
public void setUp() {
18-
settingsCache = new SettingsCache(10, 10);
18+
settingsCache = new SettingsCache(10, 10, 0);
1919
}
2020

2121
@Test

0 commit comments

Comments
 (0)