Skip to content

Commit df5fac6

Browse files
authored
Store cache status info in a map by type url (#135)
Signed-off-by: Sebastian Schepens <[email protected]>
1 parent 4d38183 commit df5fac6

File tree

4 files changed

+64
-9
lines changed

4 files changed

+64
-9
lines changed
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
package io.envoyproxy.controlplane.cache;
2+
3+
import java.util.ArrayList;
4+
import java.util.Collection;
5+
import javax.annotation.concurrent.ThreadSafe;
6+
7+
/**
8+
* {@code GroupCacheStatusInfo} provides an implementation of {@link StatusInfo} for a group of {@link CacheStatusInfo}.
9+
*/
10+
@ThreadSafe
11+
class GroupCacheStatusInfo<T> implements StatusInfo<T> {
12+
private final Collection<CacheStatusInfo<T>> statuses;
13+
14+
public GroupCacheStatusInfo(Collection<CacheStatusInfo<T>> statuses) {
15+
this.statuses = new ArrayList<>(statuses);
16+
}
17+
18+
/**
19+
* {@inheritDoc}
20+
*/
21+
@Override
22+
public long lastWatchRequestTime() {
23+
return statuses.stream().mapToLong(CacheStatusInfo::lastWatchRequestTime).max().orElse(0);
24+
}
25+
26+
/**
27+
* {@inheritDoc}
28+
*/
29+
@Override
30+
public T nodeGroup() {
31+
return statuses.stream().map(CacheStatusInfo::nodeGroup).findFirst().orElse(null);
32+
}
33+
34+
/**
35+
* {@inheritDoc}
36+
*/
37+
@Override
38+
public int numWatches() {
39+
return statuses.stream().mapToInt(CacheStatusInfo::numWatches).sum();
40+
}
41+
}

cache/src/main/java/io/envoyproxy/controlplane/cache/SimpleCache.java

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ public class SimpleCache<T> implements SnapshotCache<T> {
4343

4444
@GuardedBy("lock")
4545
private final Map<T, Snapshot> snapshots = new HashMap<>();
46-
private final ConcurrentMap<T, CacheStatusInfo<T>> statuses = new ConcurrentHashMap<>();
46+
private final ConcurrentMap<T, ConcurrentMap<String, CacheStatusInfo<T>>> statuses = new ConcurrentHashMap<>();
4747

4848
private AtomicLong watchCount = new AtomicLong();
4949

@@ -64,10 +64,10 @@ public boolean clearSnapshot(T group) {
6464
// we take a writeLock to prevent watches from being created
6565
writeLock.lock();
6666
try {
67-
CacheStatusInfo<T> status = statuses.get(group);
67+
Map<String, CacheStatusInfo<T>> status = statuses.get(group);
6868

6969
// If we don't know about this group, do nothing.
70-
if (status != null && status.numWatches() > 0) {
70+
if (status != null && status.values().stream().mapToLong(CacheStatusInfo::numWatches).sum() > 0) {
7171
LOGGER.warn("tried to clear snapshot for group with existing watches, group={}", group);
7272

7373
return false;
@@ -106,7 +106,8 @@ public Watch createWatch(
106106
// doesn't conflict
107107
readLock.lock();
108108
try {
109-
CacheStatusInfo<T> status = statuses.computeIfAbsent(group, g -> new CacheStatusInfo<>(group));
109+
CacheStatusInfo<T> status = statuses.computeIfAbsent(group, g -> new ConcurrentHashMap<>())
110+
.computeIfAbsent(request.getTypeUrl(), s -> new CacheStatusInfo<>(group));
110111
status.setLastWatchRequestTime(System.currentTimeMillis());
111112

112113
Snapshot snapshot = snapshots.get(group);
@@ -212,7 +213,7 @@ public Collection<T> groups() {
212213
@Override
213214
public synchronized void setSnapshot(T group, Snapshot snapshot) {
214215
// we take a writeLock to prevent watches from being created while we update the snapshot
215-
CacheStatusInfo<T> status;
216+
ConcurrentMap<String, CacheStatusInfo<T>> status;
216217
writeLock.lock();
217218
try {
218219
// Update the existing snapshot entry.
@@ -238,15 +239,26 @@ public StatusInfo statusInfo(T group) {
238239
readLock.lock();
239240

240241
try {
241-
return statuses.get(group);
242+
ConcurrentMap<String, CacheStatusInfo<T>> statusMap = statuses.get(group);
243+
if (statusMap == null || statusMap.isEmpty()) {
244+
return null;
245+
}
246+
247+
return new GroupCacheStatusInfo<>(statusMap.values());
242248
} finally {
243249
readLock.unlock();
244250
}
245251
}
246252

247253
@VisibleForTesting
248-
protected void respondWithSpecificOrder(T group, Snapshot snapshot, CacheStatusInfo<T> status) {
254+
protected void respondWithSpecificOrder(T group, Snapshot snapshot,
255+
ConcurrentMap<String, CacheStatusInfo<T>> statusMap) {
249256
for (String typeUrl : Resources.TYPE_URLS) {
257+
CacheStatusInfo<T> status = statusMap.get(typeUrl);
258+
if (status == null) {
259+
continue;
260+
}
261+
250262
status.watchesRemoveIf((id, watch) -> {
251263
if (!watch.request().getTypeUrl().equals(typeUrl)) {
252264
return false;

server/src/test/java/io/envoyproxy/controlplane/server/DiscoveryServerAdsWarmingClusterIT.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
import io.envoyproxy.envoy.api.v2.core.Http2ProtocolOptions;
2525
import io.grpc.netty.NettyServerBuilder;
2626
import io.restassured.http.ContentType;
27+
import java.util.concurrent.ConcurrentMap;
2728
import java.util.concurrent.CountDownLatch;
2829
import java.util.concurrent.ExecutorService;
2930
import java.util.concurrent.Executors;
@@ -192,7 +193,8 @@ public CustomCache(NodeGroup<T> groups) {
192193
}
193194

194195
@Override
195-
protected void respondWithSpecificOrder(T group, Snapshot snapshot, CacheStatusInfo<T> status) {
196+
protected void respondWithSpecificOrder(T group, Snapshot snapshot,
197+
ConcurrentMap<String, CacheStatusInfo<T>> status) {
196198
// This code has been removed to show specific case which is hard to reproduce in integration test:
197199
// 1. Envoy connects to control-plane
198200
// 2. Snapshot already exists in control-plane <- other instance share same group

server/src/test/java/io/envoyproxy/controlplane/server/EnvoyContainer.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ class EnvoyContainer extends GenericContainer<EnvoyContainer> {
2424
private final Supplier<Integer> controlPlanePortSupplier;
2525

2626
EnvoyContainer(String config, Supplier<Integer> controlPlanePortSupplier) {
27-
super("envoyproxy/envoy-alpine:latest");
27+
super("envoyproxy/envoy-alpine-dev:latest");
2828

2929
this.config = config;
3030
this.controlPlanePortSupplier = controlPlanePortSupplier;

0 commit comments

Comments
 (0)