All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.hazelcast.query.impl.BaseSingleValueIndexStore Maven / Gradle / Ivy

The newest version!
/*
 * 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.json.NonTerminalJsonValue;
import com.hazelcast.internal.monitor.impl.IndexOperationStats;
import com.hazelcast.internal.serialization.Data;
import com.hazelcast.query.impl.getters.MultiResult;

import java.util.List;

/**
 * The base store for indexes that are unable to work with multi-value
 * attributes natively. For such indexes {@link MultiResult}s are split into
 * individual values and each value is inserted/removed separately.
 * 

* All operations on the off-heap index store like insert/remove/getRecords are * not guarded by a global lock. The subclasses must either implement thread-safe * access operations or the index should be used as single-threaded by design. */ public abstract class BaseSingleValueIndexStore extends BaseIndexStore { /** * The flag is set to {@code true} when a collection is inserted into the index * and deduplication is needed. *

* Since there is no global lock guarding update/getRecords() operations * some queries still can return duplicates. */ private volatile boolean multiResultHasToDetectDuplicates; BaseSingleValueIndexStore(IndexCopyBehavior copyOn, boolean enableGlobalLock) { super(copyOn, enableGlobalLock); } /** * Associates the given value in this index store with the given record. *

* Despite the name the given value acts as a key into this index store. In * other words, it's a value of an attribute this index store is built for. * * @param value the value of an attribute this index store is built for. * @param record the record to associate with the given value. * @return the record that was associated with the given value before the * operation, if there was any, {@code null} otherwise. */ abstract Object insertInternal(Comparable value, QueryableEntry record); /** * Removes the association between the given value and a record identified * by the given record key. *

* Despite the name the given value acts as a key into this index store. In * other words, it's a value of an attribute this index store is built for. * * @param value the value of an attribute this index store is built for. * @param recordKey the key of a record to dissociate from the given value. * @return the record that was associated with the given value before the * operation, if there was any, {@code null} otherwise. */ abstract Object removeInternal(Comparable value, Data recordKey); final MultiResultSet createMultiResultSet() { return multiResultHasToDetectDuplicates ? new DuplicateDetectingMultiResult() : new FastMultiResultSet(); } @Override public final void insert(Object value, CachedQueryEntry entry, QueryableEntry entryToStore, IndexOperationStats operationStats) { takeWriteLock(); try { unwrapAndInsertToIndex(value, entryToStore, operationStats); } finally { releaseWriteLock(); } } @Override public final void update(Object oldValue, Object newValue, CachedQueryEntry entry, QueryableEntry entryToStore, IndexOperationStats operationStats) { takeWriteLock(); try { Data indexKey = entry.getKeyData(); unwrapAndRemoveFromIndex(oldValue, indexKey, operationStats); unwrapAndInsertToIndex(newValue, entryToStore, operationStats); } finally { releaseWriteLock(); } } @Override public final void remove(Object value, CachedQueryEntry entry, IndexOperationStats operationStats) { takeWriteLock(); try { unwrapAndRemoveFromIndex(value, entry.getKeyData(), operationStats); } finally { releaseWriteLock(); } } private void unwrapAndInsertToIndex(Object newValue, QueryableEntry queryableEntry, IndexOperationStats operationStats) { if (newValue == NonTerminalJsonValue.INSTANCE) { return; } if (newValue instanceof MultiResult result) { multiResultHasToDetectDuplicates = true; List results = result.getResults(); for (Object o : results) { Comparable sanitizedValue = sanitizeValue(o); Object oldValue = insertInternal(sanitizedValue, queryableEntry); if (oldValue == null) { operationStats.onEntryAdded(newValue); } } } else { Comparable sanitizedValue = sanitizeValue(newValue); Object oldValue = insertInternal(sanitizedValue, queryableEntry); if (oldValue == null) { operationStats.onEntryAdded(newValue); } } } private void unwrapAndRemoveFromIndex(Object oldValue, Data recordKey, IndexOperationStats operationStats) { if (oldValue == NonTerminalJsonValue.INSTANCE) { return; } if (oldValue instanceof MultiResult result) { List results = result.getResults(); for (Object o : results) { Comparable sanitizedValue = sanitizeValue(o); Object removedValue = removeInternal(sanitizedValue, recordKey); if (removedValue != null) { operationStats.onEntryRemoved(oldValue); } } } else { Comparable sanitizedValue = sanitizeValue(oldValue); Object removedValue = removeInternal(sanitizedValue, recordKey); if (removedValue != null) { operationStats.onEntryRemoved(oldValue); } } } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy