
com.hazelcast.query.impl.BaseIndexStore Maven / Gradle / Ivy
/*
* Copyright (c) 2008-2024, 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.query.impl;
import com.hazelcast.internal.serialization.Data;
import com.hazelcast.internal.util.MapUtil;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import static com.hazelcast.query.impl.AbstractIndex.NULL;
/**
* Base class for concrete index store implementations
*/
public abstract class BaseIndexStore implements IndexStore {
static final float LOAD_FACTOR = 0.75F;
private final ReentrantReadWriteLock lock;
private final ReentrantReadWriteLock.ReadLock readLock;
private final ReentrantReadWriteLock.WriteLock writeLock;
private final CopyFunctor resultCopyFunctor;
BaseIndexStore(IndexCopyBehavior copyOn, boolean enableGlobalLock) {
if (copyOn == IndexCopyBehavior.COPY_ON_WRITE || copyOn == IndexCopyBehavior.NEVER) {
resultCopyFunctor = new PassThroughFunctor();
} else {
resultCopyFunctor = new CopyInputFunctor();
}
lock = enableGlobalLock ? new ReentrantReadWriteLock() : null;
readLock = enableGlobalLock ? lock.readLock() : null;
writeLock = enableGlobalLock ? lock.writeLock() : null;
}
/**
* Canonicalizes the given value for storing it in this index store.
*
* The method is used by hash indexes to achieve the canonical
* representation of mixed-type numeric values, so {@code equals} and {@code
* hashCode} logic can work properly.
*
* The main difference comparing to {@link IndexStore#canonicalizeQueryArgumentScalar}
* is that this method is specifically designed to support the
* canonicalization of persistent index values (think of map entry attribute
* values), so a more suitable value representation may chosen.
*
* @param value the value to canonicalize.
* @return the canonicalized value.
*/
abstract Comparable canonicalizeScalarForStorage(Comparable value);
void takeWriteLock() {
if (lock != null) {
writeLock.lock();
}
}
void releaseWriteLock() {
if (lock != null) {
writeLock.unlock();
}
}
void takeReadLock() {
if (lock != null) {
readLock.lock();
}
}
void releaseReadLock() {
if (lock != null) {
readLock.unlock();
}
}
final void copyToMultiResultSet(MultiResultSet resultSet, Map records) {
resultSet.addResultSet(resultCopyFunctor.invoke(records));
}
final Set toSingleResultSet(Map records) {
return new SingleResultSet(resultCopyFunctor.invoke(records));
}
@Override
public void destroy() {
// nothing to destroy
}
Comparable sanitizeValue(Object input) {
if (input instanceof CompositeValue compositeValue) {
Comparable[] components = compositeValue.getComponents();
for (int i = 0; i < components.length; ++i) {
components[i] = sanitizeScalar(components[i]);
}
return compositeValue;
} else {
return sanitizeScalar(input);
}
}
private Comparable sanitizeScalar(Object input) {
if (input == null || input instanceof Comparable) {
Comparable value = (Comparable) input;
if (value == null) {
value = NULL;
} else if (value.getClass().isEnum()) {
value = TypeConverters.ENUM_CONVERTER.convert(value);
}
return canonicalizeScalarForStorage(value);
} else {
throw new IllegalArgumentException("It is not allowed to use a type that is not Comparable: " + input.getClass());
}
}
interface CopyFunctor {
Map invoke(Map map);
}
interface IndexFunctor {
Object invoke(A param1, B param2);
}
private static class PassThroughFunctor implements CopyFunctor {
@Override
public Map invoke(Map map) {
return map;
}
}
private static class CopyInputFunctor implements CopyFunctor {
@Override
public Map invoke(Map map) {
return MapUtil.isNullOrEmpty(map) ? map : new HashMap<>(map);
}
}
}