/*
* Copyright (c) 2008-2017, Hazelcast, Inc. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.hazelcast.map.impl.querycache.subscriber;
import com.hazelcast.config.QueryCacheConfig;
import com.hazelcast.core.IMap;
import com.hazelcast.core.PartitioningStrategy;
import com.hazelcast.internal.eviction.EvictionListener;
import com.hazelcast.internal.serialization.InternalSerializationService;
import com.hazelcast.map.impl.proxy.MapProxyImpl;
import com.hazelcast.map.impl.querycache.QueryCacheConfigurator;
import com.hazelcast.map.impl.querycache.QueryCacheContext;
import com.hazelcast.map.impl.querycache.QueryCacheEventService;
import com.hazelcast.map.impl.querycache.subscriber.record.QueryCacheRecord;
import com.hazelcast.nio.serialization.Data;
import com.hazelcast.query.Predicate;
import com.hazelcast.query.impl.CachedQueryEntry;
import com.hazelcast.query.impl.Indexes;
import com.hazelcast.query.impl.getters.Extractors;
import java.util.AbstractMap;
import java.util.Map;
import java.util.Set;
import static com.hazelcast.core.EntryEventType.EVICTED;
/**
* Contains helper methods for {@link InternalQueryCache} main implementation.
*
* @param <K> the key type for this {@link InternalQueryCache}
* @param <V> the value type for this {@link InternalQueryCache}
*/
abstract class AbstractInternalQueryCache<K, V> implements InternalQueryCache<K, V> {
protected final boolean includeValue;
protected final String mapName;
protected final String cacheName;
protected final String userGivenCacheName;
protected final IMap delegate;
protected final QueryCacheContext context;
protected final QueryCacheRecordStore recordStore;
protected final Indexes indexes;
protected final InternalSerializationService serializationService;
protected final PartitioningStrategy partitioningStrategy;
/**
* Id of registered listener on publisher side.
*/
protected String publisherListenerId;
public AbstractInternalQueryCache(String cacheName, String userGivenCacheName, IMap delegate, QueryCacheContext context) {
this.cacheName = cacheName;
this.userGivenCacheName = userGivenCacheName;
this.mapName = delegate.getName();
this.delegate = delegate;
this.context = context;
this.serializationService = context.getSerializationService();
this.indexes = new Indexes(serializationService, Extractors.empty());
this.includeValue = isIncludeValue();
this.partitioningStrategy = getPartitioningStrategy();
this.recordStore = new DefaultQueryCacheRecordStore(serializationService, indexes, getQueryCacheConfig(),
getEvictionListener());
}
@Override
public void setPublisherListenerId(String publisherListenerId) {
this.publisherListenerId = publisherListenerId;
}
protected Predicate getPredicate() {
return getQueryCacheConfig().getPredicateConfig().getImplementation();
}
private QueryCacheConfig getQueryCacheConfig() {
QueryCacheConfigurator queryCacheConfigurator = context.getQueryCacheConfigurator();
return queryCacheConfigurator.getOrCreateConfiguration(mapName, userGivenCacheName);
}
private EvictionListener getEvictionListener() {
return new EvictionListener<Data, QueryCacheRecord>() {
@Override
public void onEvict(Data dataKey, QueryCacheRecord record, boolean wasExpired) {
EventPublisherHelper.publishEntryEvent(context, mapName, cacheName, dataKey, null, record, EVICTED);
}
};
}
PartitioningStrategy getPartitioningStrategy() {
if (delegate instanceof MapProxyImpl) {
return ((MapProxyImpl) delegate).getPartitionStrategy();
}
return null;
}
protected void doFullKeyScan(Predicate predicate, Set<K> resultingSet) {
InternalSerializationService serializationService = this.serializationService;
CachedQueryEntry queryEntry = new CachedQueryEntry();
Set<Map.Entry<Data, QueryCacheRecord>> entries = recordStore.entrySet();
for (Map.Entry<Data, QueryCacheRecord> entry : entries) {
Data keyData = entry.getKey();
QueryCacheRecord record = entry.getValue();
Object value = record.getValue();
queryEntry.init(serializationService, keyData, value, Extractors.empty());
boolean valid = predicate.apply(queryEntry);
if (valid) {
resultingSet.add((K) queryEntry.getKey());
}
}
}
protected void doFullEntryScan(Predicate predicate, Set<Map.Entry<K, V>> resultingSet) {
InternalSerializationService serializationService = this.serializationService;
CachedQueryEntry queryEntry = new CachedQueryEntry();
Set<Map.Entry<Data, QueryCacheRecord>> entries = recordStore.entrySet();
for (Map.Entry<Data, QueryCacheRecord> entry : entries) {
Data keyData = entry.getKey();
QueryCacheRecord record = entry.getValue();
Object value = record.getValue();
queryEntry.init(serializationService, keyData, value, Extractors.empty());
boolean valid = predicate.apply(queryEntry);
if (valid) {
Object keyObject = queryEntry.getKey();
Object valueObject = queryEntry.getValue();
Map.Entry simpleEntry = new AbstractMap.SimpleEntry(keyObject, valueObject);
resultingSet.add(simpleEntry);
}
}
}
protected void doFullValueScan(Predicate predicate, Set<V> resultingSet) {
InternalSerializationService serializationService = this.serializationService;
CachedQueryEntry queryEntry = new CachedQueryEntry();
Set<Map.Entry<Data, QueryCacheRecord>> entries = recordStore.entrySet();
for (Map.Entry<Data, QueryCacheRecord> entry : entries) {
Data keyData = entry.getKey();
QueryCacheRecord record = entry.getValue();
Object value = record.getValue();
queryEntry.init(serializationService, keyData, value, Extractors.empty());
boolean valid = predicate.apply(queryEntry);
if (valid) {
Object valueObject = queryEntry.getValue();
resultingSet.add((V) valueObject);
}
}
}
private boolean isIncludeValue() {
QueryCacheConfig config = getQueryCacheConfig();
return config.isIncludeValue();
}
protected QueryCacheEventService getEventService() {
SubscriberContext subscriberContext = context.getSubscriberContext();
return subscriberContext.getEventService();
}
protected <T> T toObject(Object valueInRecord) {
return serializationService.toObject(valueInRecord);
}
protected Data toData(Object key) {
return serializationService.toData(key, partitioningStrategy);
}
@Override
public void clear() {
recordStore.clear();
indexes.clearIndexes();
}
}