Skip to content

Commit 2cb85bc

Browse files
committed
Make ObserverHolder thread safe by having a thread local observer member
1 parent d0113fc commit 2cb85bc

File tree

3 files changed

+71
-16
lines changed

3 files changed

+71
-16
lines changed

geode-core/src/integrationTest/java/org/apache/geode/cache/query/internal/QueryTraceJUnitTest.java

Lines changed: 60 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
package org.apache.geode.cache.query.internal;
1616

1717
import static org.apache.geode.cache.Region.SEPARATOR;
18+
import static org.assertj.core.api.Assertions.assertThat;
1819
import static org.junit.Assert.assertEquals;
1920
import static org.junit.Assert.assertFalse;
2021
import static org.junit.Assert.assertTrue;
@@ -60,10 +61,12 @@ public class QueryTraceJUnitTest {
6061
@Before
6162
public void setUp() throws Exception {
6263
CacheUtils.startCache();
64+
DefaultQuery.testHook = new BeforeQueryExecutionHook();
6365
}
6466

6567
@After
6668
public void tearDown() throws Exception {
69+
DefaultQuery.testHook = null;
6770
CacheUtils.closeCache();
6871
}
6972

@@ -104,7 +107,11 @@ public void testTraceOnPartitionedRegionWithTracePrefix() throws Exception {
104107
assertTrue(((DefaultQuery) query).isTraced());
105108

106109
SelectResults results = (SelectResults) query.execute();
107-
assertTrue(QueryObserverHolder.getInstance() instanceof IndexTrackingQueryObserver);
110+
111+
// The IndexTrackingObserver should have been set
112+
BeforeQueryExecutionHook hook = (BeforeQueryExecutionHook) DefaultQuery.testHook;
113+
assertThat(hook.getObserver()).isInstanceOf(IndexTrackingQueryObserver.class);
114+
108115
// The query should return all elements in region.
109116
assertEquals(region.size(), results.size());
110117
QueryObserverHolder.reset();
@@ -141,7 +148,11 @@ public void testTraceOnLocalRegionWithTracePrefix() throws Exception {
141148
assertTrue(((DefaultQuery) query).isTraced());
142149

143150
SelectResults results = (SelectResults) query.execute();
144-
assertTrue(QueryObserverHolder.getInstance() instanceof IndexTrackingQueryObserver);
151+
152+
// The IndexTrackingObserver should have been set
153+
BeforeQueryExecutionHook hook = (BeforeQueryExecutionHook) DefaultQuery.testHook;
154+
assertThat(hook.getObserver()).isInstanceOf(IndexTrackingQueryObserver.class);
155+
145156
// The query should return all elements in region.
146157
assertEquals(region.size(), results.size());
147158
QueryObserverHolder.reset();
@@ -183,7 +194,11 @@ public void testNegTraceOnPartitionedRegionWithTracePrefix() throws Exception {
183194
assertFalse(((DefaultQuery) query).isTraced());
184195

185196
SelectResults results = (SelectResults) query.execute();
186-
assertFalse(QueryObserverHolder.getInstance() instanceof IndexTrackingQueryObserver);
197+
198+
// The IndexTrackingObserver should not have been set
199+
BeforeQueryExecutionHook hook = (BeforeQueryExecutionHook) DefaultQuery.testHook;
200+
assertThat(hook.getObserver()).isNotInstanceOf(IndexTrackingQueryObserver.class);
201+
187202
// The query should return all elements in region.
188203
assertEquals(region.size(), results.size());
189204
QueryObserverHolder.reset();
@@ -223,7 +238,11 @@ public void testNegTraceOnLocalRegionWithTracePrefix() throws Exception {
223238
assertFalse(((DefaultQuery) query).isTraced());
224239

225240
SelectResults results = (SelectResults) query.execute();
226-
assertFalse(QueryObserverHolder.getInstance() instanceof IndexTrackingQueryObserver);
241+
242+
// The IndexTrackingObserver should not have been set
243+
BeforeQueryExecutionHook hook = (BeforeQueryExecutionHook) DefaultQuery.testHook;
244+
assertThat(hook.getObserver()).isNotInstanceOf(IndexTrackingQueryObserver.class);
245+
227246
// The query should return all elements in region.
228247
assertEquals(region.size(), results.size());
229248
QueryObserverHolder.reset();
@@ -262,7 +281,11 @@ public void testTraceOnPartitionedRegionWithTracePrefixNoComments() throws Excep
262281
assertTrue(((DefaultQuery) query).isTraced());
263282

264283
SelectResults results = (SelectResults) query.execute();
265-
assertTrue(QueryObserverHolder.getInstance() instanceof IndexTrackingQueryObserver);
284+
285+
// The IndexTrackingObserver should have been set
286+
BeforeQueryExecutionHook hook = (BeforeQueryExecutionHook) DefaultQuery.testHook;
287+
assertThat(hook.getObserver()).isInstanceOf(IndexTrackingQueryObserver.class);
288+
266289
// The query should return all elements in region.
267290
assertEquals(region.size(), results.size());
268291
QueryObserverHolder.reset();
@@ -296,8 +319,11 @@ public void testTraceOnLocalRegionWithTracePrefixNoComments() throws Exception {
296319
assertTrue(((DefaultQuery) query).isTraced());
297320

298321
SelectResults results = (SelectResults) query.execute();
299-
assertTrue(QueryObserverHolder.getInstance() instanceof IndexTrackingQueryObserver);
300-
// The query should return all elements in region.
322+
323+
// The IndexTrackingObserver should have been set
324+
BeforeQueryExecutionHook hook = (BeforeQueryExecutionHook) DefaultQuery.testHook;
325+
assertThat(hook.getObserver()).isInstanceOf(IndexTrackingQueryObserver.class);
326+
301327
assertEquals(region.size(), results.size());
302328
QueryObserverHolder.reset();
303329
}
@@ -331,7 +357,11 @@ public void testTraceOnPartitionedRegionWithSmallTracePrefixNoComments() throws
331357
assertTrue(((DefaultQuery) query).isTraced());
332358

333359
SelectResults results = (SelectResults) query.execute();
334-
assertTrue(QueryObserverHolder.getInstance() instanceof IndexTrackingQueryObserver);
360+
361+
// The IndexTrackingObserver should have been set
362+
BeforeQueryExecutionHook hook = (BeforeQueryExecutionHook) DefaultQuery.testHook;
363+
assertThat(hook.getObserver()).isInstanceOf(IndexTrackingQueryObserver.class);
364+
335365
// The query should return all elements in region.
336366
assertEquals(region.size(), results.size());
337367
QueryObserverHolder.reset();
@@ -366,7 +396,11 @@ public void testTraceOnLocalRegionWithSmallTracePrefixNoComments() throws Except
366396
assertTrue(((DefaultQuery) query).isTraced());
367397

368398
SelectResults results = (SelectResults) query.execute();
369-
assertTrue(QueryObserverHolder.getInstance() instanceof IndexTrackingQueryObserver);
399+
400+
// The IndexTrackingObserver should have been set
401+
BeforeQueryExecutionHook hook = (BeforeQueryExecutionHook) DefaultQuery.testHook;
402+
assertThat(hook.getObserver()).isInstanceOf(IndexTrackingQueryObserver.class);
403+
370404
// The query should return all elements in region.
371405
assertEquals(region.size(), results.size());
372406
QueryObserverHolder.reset();
@@ -438,4 +472,21 @@ public void testQueryFailLocalRegionWithSmallTracePrefixNoSpace() throws Excepti
438472
}
439473
}
440474

475+
private class BeforeQueryExecutionHook implements DefaultQuery.TestHook {
476+
private QueryObserver observer = null;
477+
478+
@Override
479+
public void doTestHook(final SPOTS spot, final DefaultQuery _ignored,
480+
final ExecutionContext executionContext) {
481+
switch (spot) {
482+
case BEFORE_QUERY_EXECUTION:
483+
observer = QueryObserverHolder.getInstance();
484+
break;
485+
}
486+
}
487+
488+
public QueryObserver getObserver() {
489+
return observer;
490+
}
491+
}
441492
}

geode-core/src/main/java/org/apache/geode/cache/query/internal/QueryObserverHolder.java

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -49,31 +49,31 @@ public class QueryObserverHolder {
4949
* The current observer which will be notified of all query events.
5050
*/
5151
@MakeNotStatic
52-
private static QueryObserver _instance = NO_OBSERVER;
52+
private static ThreadLocal<QueryObserver> _instance = ThreadLocal.withInitial(() -> NO_OBSERVER);
5353

5454
/**
5555
* Set the given observer to be notified of query events. Returns the current observer.
5656
*/
5757
public static QueryObserver setInstance(QueryObserver observer) {
5858
Support.assertArg(observer != null, "setInstance expects a non-null argument!");
59-
QueryObserver oldObserver = _instance;
60-
_instance = observer;
59+
QueryObserver oldObserver = _instance.get();
60+
_instance.set(observer);
6161
return oldObserver;
6262
}
6363

6464
public static boolean hasObserver() {
65-
return _instance != NO_OBSERVER;
65+
return _instance.get() != NO_OBSERVER;
6666
}
6767

6868
/** Return the current QueryObserver instance */
6969
public static QueryObserver getInstance() {
70-
return _instance;
70+
return _instance.get();
7171
}
7272

7373
/**
7474
* Only for test purposes.
7575
*/
7676
public static void reset() {
77-
_instance = NO_OBSERVER;
77+
_instance.set(NO_OBSERVER);
7878
}
7979
}

geode-gfsh/src/main/java/org/apache/geode/management/internal/cli/functions/DataCommandFunction.java

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -205,12 +205,13 @@ private DataCommandResult select(InternalCache cache, Object principal, String q
205205
Query query = qs.newQuery(queryString);
206206
DefaultQuery tracedQuery = (DefaultQuery) query;
207207
WrappedIndexTrackingQueryObserver queryObserver = null;
208+
QueryObserver origQueryObserver = null;
208209
String queryVerboseMsg = null;
209210
long startTime = -1;
210211
if (tracedQuery.isTraced()) {
211212
startTime = NanoTimer.getTime();
212213
queryObserver = new WrappedIndexTrackingQueryObserver();
213-
QueryObserverHolder.setInstance(queryObserver);
214+
origQueryObserver = QueryObserverHolder.setInstance(queryObserver);
214215
}
215216
List<SelectResultRow> list = new ArrayList<>();
216217

@@ -237,6 +238,9 @@ private DataCommandResult select(InternalCache cache, Object principal, String q
237238
if (queryObserver != null) {
238239
QueryObserverHolder.reset();
239240
}
241+
if (tracedQuery.isTraced()) {
242+
QueryObserverHolder.setInstance(origQueryObserver);
243+
}
240244
}
241245
}
242246

0 commit comments

Comments
 (0)