albertogpz commented on a change in pull request #6874:
URL: https://github.com/apache/geode/pull/6874#discussion_r712232163



##########
File path: 
geode-core/src/main/java/org/apache/geode/cache/query/internal/QueryObserverHolder.java
##########
@@ -54,26 +54,26 @@
   /**
    * Set the given observer to be notified of query events. Returns the 
current observer.
    */
-  public static QueryObserver setInstance(QueryObserver observer) {
+  public static synchronized QueryObserver setInstance(QueryObserver observer) 
{
     Support.assertArg(observer != null, "setInstance expects a non-null 
argument!");
     QueryObserver oldObserver = _instance;
     _instance = observer;
     return oldObserver;
   }
 
-  public static boolean hasObserver() {
+  public static synchronized boolean hasObserver() {
     return _instance != NO_OBSERVER;
   }
 
   /** Return the current QueryObserver instance */
-  public static QueryObserver getInstance() {
+  public static synchronized QueryObserver getInstance() {

Review comment:
       > I've wanted to make this class thread-safe too. There is one problem 
with doing so though. `getInstance()` is in the path of every query execution 
and index evaluate call. If you make it `synchronized`, then there will be a 
significant performance penalty inflicted on every query and index evaluation.
   > 
   > To see this, look at the call hierarchy of constructing a new 
ExecutionConext. Every new instance will invoke:
   > 
   > ```java
   > private QueryObserver observer = QueryObserverHolder.getInstance();
   > ```
   > 
   > In order to make this class thread-safe, I think we need to solve the 
problem of how to get queries and index evaluations from hitting those 
`synchronized` blocks on every invocation. I'm not as familiar with querying or 
indexing so you may need to chat about it further with Anil or others.
   > 
   I would expect this to be a problem if the above calls are done many times 
per query. But in this PR, it is proposed to invoke it just once, to get the 
value and then set it in the `ExecutionContext`, right before the query is 
executed. Later, when the query needs the value of the observer, it would get 
it from the `ExecutionContext` using a non-synchronized call given that all the 
calls to get the observer have been changed from 
`QueryObserverHolder.getInstance()` to `context.getObserver()`.
   
   > Another problem is that the new `private QueryObserver observer` field in 
`ExecutionContext` is itself not thread-safe, so the setter and getter you 
added are not thread-safe either.
   > 
   I am assuming that the `ExecutionContext` is not shared between threads and 
therefore it does not need to be thread-safe. I am wrong here?
   > I think your intention is to have a test invoke `setObserver` for one or 
more direct invocations of a query. If that's true, then you're probably better 
off introducing a `ThreadLocal` to `ExecutionContext` for this purpose. Then 
the execution would check that `ThreadLocal` for a non-null value and then use 
it. If it's null, the execution would fallback to using the usual `observer` 
stored in the field.
   > 
   Actually, my intention was just to make this class thread-safe but not 
extend it to have new usages. Nevertheless, the class is documented and used so 
that the observer can be set from any thread and be available to any thread in 
the VM.
   I have proposed the current solution but have also considered the use of a 
`ThreadLocal` variable, not in the `ExecutionContext` class (which did not have 
an `observer` field) but in the `QueryObserverHolder` class to be used in a way 
similar to what you are proposing.
   But I think the lifecycle of the `ThreadLocal` variable would be complex. It 
should be reset after the query execution. But who would do it?
   
   > Then you could make the field itself `final` in the hopes that it would be 
used multiple times. But again, I suspect that every query invocation creates a 
new `ExecutionContext` which will perform poorly because of the `synchronized` 
in `QueryObserverHolder`.
   
   




-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


Reply via email to