Skip to content

Commit 07747c5

Browse files
authored
xds: Fix WeakReference bug in SharedCallCounterMap (grpc#8466)
Fixes grpc#8397. grpc#8397 is caused by mistakenly clearing up a map entry right after the entry is recreated after gc. Reproduced in regression test.
1 parent 2faa748 commit 07747c5

2 files changed

Lines changed: 29 additions & 2 deletions

File tree

xds/src/main/java/io/grpc/xds/SharedCallCounterMap.java

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -58,8 +58,14 @@ public synchronized AtomicLong getOrCreate(String cluster, @Nullable String edsS
5858
counters.put(cluster, clusterCounters);
5959
}
6060
CounterReference ref = clusterCounters.get(edsServiceName);
61-
AtomicLong counter;
62-
if (ref == null || (counter = ref.get()) == null) {
61+
AtomicLong counter = null;
62+
if (ref != null) {
63+
counter = ref.get();
64+
if (counter == null) {
65+
ref.enqueue();
66+
}
67+
}
68+
if (counter == null) {
6369
counter = new AtomicLong();
6470
ref = new CounterReference(counter, refQueue, cluster, edsServiceName);
6571
clusterCounters.put(edsServiceName, ref);
@@ -73,6 +79,9 @@ void cleanQueue() {
7379
CounterReference ref;
7480
while ((ref = (CounterReference) refQueue.poll()) != null) {
7581
Map<String, CounterReference> clusterCounter = counters.get(ref.cluster);
82+
if (clusterCounter.get(ref.edsServiceName) != ref) {
83+
continue;
84+
}
7685
clusterCounter.remove(ref.edsServiceName);
7786
if (clusterCounter.isEmpty()) {
7887
counters.remove(ref.cluster);

xds/src/test/java/io/grpc/xds/SharedCallCounterMapTest.java

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,4 +62,22 @@ public boolean isDone() {
6262
map.cleanQueue();
6363
assertThat(counters).isEmpty();
6464
}
65+
66+
@Test
67+
public void gcAndRecreate() {
68+
@SuppressWarnings("UnusedVariable") // assign to null for GC only
69+
AtomicLong counter = map.getOrCreate(CLUSTER, EDS_SERVICE_NAME);
70+
final CounterReference ref = counters.get(CLUSTER).get(EDS_SERVICE_NAME);
71+
assertThat(counter.get()).isEqualTo(0);
72+
counter = null;
73+
GcFinalization.awaitDone(new FinalizationPredicate() {
74+
@Override
75+
public boolean isDone() {
76+
return ref.isEnqueued();
77+
}
78+
});
79+
map.getOrCreate(CLUSTER, EDS_SERVICE_NAME);
80+
assertThat(counters.get(CLUSTER)).isNotNull();
81+
assertThat(counters.get(CLUSTER).get(EDS_SERVICE_NAME)).isNotNull();
82+
}
6583
}

0 commit comments

Comments
 (0)