In my project I recently encountered a problem related to Map with configured QueryCache.
I have entity with two fields:
class AccountingRule {
long key;
String code;
}
Map configuration for it's Map including QueryCache configuration:
MapConfig mapConfig = new MapConfig("AccountingRule")
.setInMemoryFormat(InMemoryFormat.BINARY)
.setReadBackupData(true)
.setBackupCount(1)
.addQueryCacheConfig(new QueryCacheConfig()
.setName("AccountingRule")
.setPredicateConfig(new PredicateConfig(TruePredicate.INSTANCE))
.setIncludeValue(true)
.setPopulate(true)
.setDelaySeconds(0)
);
In main I run hazelcast instance with my configuration and then:
For example:
HazelcastInstance hazelcast = createHazelcastInstance();
IMap<Long, AccountingRule> map = hazelcast.getMap("AccountingRule");
QueryCache<Long, AccountingRule> queryCache = map.getQueryCache("AccountingRule");
queryCache.addIndex("code", false);
while (true) {
AccountingRule ar = newAccountingRule();
map.put(ar.getKey(), ar);
// wait for query cache
AccountingRule fromQueryCache = queryCache.get(ar.getKey());
while (fromQueryCache == null) {
log.info("Waiting for query cache");
fromQueryCache = queryCache.get(AccountingRule.class, ar.getKey());
}
log.info("query cache updated");
// get entity from query cache using predicate
Predicate codePredicate = equal("code", ar.getCode());
AccountingRule fromQueryCacheWithPredicate = getOnlyElement(queryCache.values(codePredicate), null);
if (fromQueryCacheWithPredicate == null) {
log.error("AccountingRule with id {} from query cash is null", ar.getKey());
System.exit(1);
}
}
Unfortunately it fails. QueryCache.get returned entity but query based on predicate on indexed field returns nothing. When I wait a little bit and retry query it's ok. It looks like indexes are updated asynchronously am I right? Is there any option to avoid it?
There are two options when it works:
Code:
MapConfig mapConfig = new MapConfig("AccountingRule")
.setInMemoryFormat(InMemoryFormat.BINARY)
.setReadBackupData(true)
.setBackupCount(1)
.addQueryCacheConfig(new QueryCacheConfig()
.setName("AccountingRule")
.setPredicateConfig(new PredicateConfig(TruePredicate.INSTANCE))
.setIncludeValue(true)
.setPopulate(true)
.setDelaySeconds(0)
.addIndexConfig(new MapIndexConfig("code", false))
);
The question is why when I add index not in configuration it doesn't work properly?
It looks like there is bug regarding this issue. When you execute QueryCache.addIndex
, the index is only created if there is an entry in the query cache. Moreover, indexes originating from Config
(programmatic or declarative) are not created at all and the queries run on the query cache does full scan.
I see that you've already created a Github issue regarding this problem (#12358), please follow it up for the fix.