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

com.hazelcast.map.impl.PartitionContainerImpl 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.map.impl;

import com.hazelcast.config.MapConfig;
import com.hazelcast.internal.eviction.ExpirationManager;
import com.hazelcast.internal.locksupport.LockSupportService;
import com.hazelcast.internal.partition.IPartitionService;
import com.hazelcast.internal.partition.impl.NameSpaceUtil;
import com.hazelcast.internal.services.ObjectNamespace;
import com.hazelcast.internal.services.ServiceNamespace;
import com.hazelcast.internal.util.ConcurrencyUtil;
import com.hazelcast.internal.util.ConstructorFunction;
import com.hazelcast.internal.util.ContextMutexFactory;
import com.hazelcast.internal.util.MapUtil;
import com.hazelcast.map.impl.operation.MapClearExpiredOperation;
import com.hazelcast.map.impl.recordstore.RecordStore;
import com.hazelcast.spi.impl.NodeEngine;
import com.hazelcast.spi.impl.executionservice.ExecutionService;
import com.hazelcast.spi.impl.operationservice.OperationService;
import com.hazelcast.spi.properties.ClusterProperty;

import javax.annotation.Nullable;
import java.util.Collection;
import java.util.Collections;
import java.util.concurrent.ConcurrentMap;
import java.util.function.Predicate;

import static com.hazelcast.map.impl.MapKeyLoaderUtil.getMaxSizePerNode;
import static com.hazelcast.map.impl.MapMigrationAwareService.lesserBackupMapsThenWithContainer;

public class PartitionContainerImpl implements PartitionContainer {

    private final int partitionId;
    private final MapService mapService;
    private final ContextMutexFactory contextMutexFactory = new ContextMutexFactory();
    private final ConcurrentMap maps;
    private final ConstructorFunction recordStoreConstructor
            = name -> {
        RecordStore recordStore = createRecordStore(name);
        recordStore.startLoading();
        return recordStore;
    };
    private final ConstructorFunction recordStoreConstructorSkipLoading
            = this::createRecordStore;

    private final ConstructorFunction recordStoreConstructorForHotRestart
            = this::createRecordStore;
    /**
     * Flag to check if there is a {@link MapClearExpiredOperation}
     * running on this partition at this moment or not.
     */
    private volatile boolean hasRunningCleanup;
    private volatile long lastCleanupTime;

    /**
     * Used when sorting partition containers in {@link ExpirationManager}
     * A non-volatile copy of lastCleanupTime is used with two reasons.
     * 

* 1. We need an un-modified field during sorting. * 2. Decrease number of volatile reads. */ private long lastCleanupTimeCopy; public PartitionContainerImpl(final MapService mapService, final int partitionId) { this.mapService = mapService; this.partitionId = partitionId; int approxMapCount = mapService.mapServiceContext.getNodeEngine() .getConfig().getMapConfigs().size(); this.maps = MapUtil.createConcurrentHashMap(approxMapCount); } private RecordStore createRecordStore(String name) { MapServiceContext mapServiceContext = mapService.getMapServiceContext(); MapContainer mapContainer = mapServiceContext.getMapContainer(name); MapKeyLoader keyLoader = mapContainer.getMapStoreContext().isMapLoader() ? createMapKeyLoader(mapServiceContext, mapContainer) : null; int partitionId = getPartitionId(); if (!mapContainer.shouldUseGlobalIndex()) { mapContainer.createIndexRegistry(false, partitionId); } RecordStore recordStore = mapServiceContext.createRecordStore(mapContainer, partitionId, keyLoader); recordStore.init(); return recordStore; } private MapKeyLoader createMapKeyLoader(MapServiceContext mapServiceContext, MapContainer mapContainer) { MapConfig mapConfig = mapContainer.getMapConfig(); String mapName = mapContainer.getName(); NodeEngine nodeEngine = mapServiceContext.getNodeEngine(); IPartitionService partitionService = nodeEngine.getPartitionService(); ExecutionService executionService = nodeEngine.getExecutionService(); OperationService opService = nodeEngine.getOperationService(); MapKeyLoader keyLoader = new MapKeyLoader(mapName, opService, partitionService, nodeEngine.getClusterService(), executionService, mapContainer.toData(), mapServiceContext.getNodeWideLoadedKeyLimiter()); keyLoader.setMaxBatch(nodeEngine.getProperties().getInteger(ClusterProperty.MAP_LOAD_CHUNK_SIZE)); keyLoader.setMaxSize(getMaxSizePerNode(mapConfig.getEvictionConfig())); keyLoader.setHasBackup(mapConfig.getTotalBackupCount() > 0); keyLoader.setMapOperationProvider(mapServiceContext.getMapOperationProvider(mapName)); return keyLoader; } @Override public ConcurrentMap getMaps() { return maps; } @Override public Collection getAllRecordStores() { return maps.isEmpty() ? Collections.emptyList() : maps.values(); } @Override public Collection getAllNamespaces(int replicaIndex) { return getNamespaces(ignored -> true, replicaIndex); } @Override public Collection getNamespaces(Predicate predicate, int replicaIndex) { return NameSpaceUtil.getAllNamespaces(maps, recordStore -> { MapContainer mapContainer = recordStore.getMapContainer(); MapConfig mapConfig = mapContainer.getMapConfig(); return mapConfig.getTotalBackupCount() >= replicaIndex && predicate.test(mapConfig); }, recordStore -> recordStore.getMapContainer().getObjectNamespace()); } @Override public int getPartitionId() { return partitionId; } @Override public MapService getMapService() { return mapService; } @Override public RecordStore getRecordStore(String name) { return ConcurrencyUtil.getOrPutSynchronized(maps, name, contextMutexFactory, recordStoreConstructor); } @Override public RecordStore getRecordStore(String name, boolean skipLoadingOnCreate) { return ConcurrencyUtil.getOrPutSynchronized(maps, name, this, skipLoadingOnCreate ? recordStoreConstructorSkipLoading : recordStoreConstructor); } @Override public RecordStore getRecordStoreForHotRestart(String name) { return ConcurrencyUtil.getOrPutSynchronized(maps, name, contextMutexFactory, recordStoreConstructorForHotRestart); } @Override @Nullable public RecordStore getExistingRecordStore(String mapName) { return maps.get(mapName); } @Override public final void destroyMap(MapContainer mapContainer) { // Mark map container destroyed before the underlying // data structures are destroyed. We need this to // ensure that every reader that observed non-destroyed // state may use previously read data. E.g. if the // reader returned only Key1 it is guaranteed that it // hadn't missed Key2 because it was destroyed earlier. mapContainer.onBeforeDestroy(); String name = mapContainer.getName(); RecordStore recordStore = maps.remove(name); if (recordStore != null) { // this call also clears and disposes Indexes for that partition recordStore.destroy(); } else { // It can be that, map is used only for locking, // because of that RecordStore is not created. // We will try to remove/clear LockStore belonging to // this IMap partition. clearLockStore(name); } MapServiceContext mapServiceContext = mapService.mapServiceContext; mapServiceContext.removeMapContainer(mapContainer); mapServiceContext.removePartitioningStrategyFromCache(mapContainer.getName()); } private void clearLockStore(String name) { final NodeEngine nodeEngine = mapService.getMapServiceContext().getNodeEngine(); final LockSupportService lockService = nodeEngine.getServiceOrNull(LockSupportService.SERVICE_NAME); if (lockService != null) { final ObjectNamespace namespace = MapService.getObjectNamespace(name); lockService.clearLockStore(partitionId, namespace); } } @Override public boolean hasRunningCleanup() { return hasRunningCleanup; } @Override public void setHasRunningCleanup(boolean hasRunningCleanup) { this.hasRunningCleanup = hasRunningCleanup; } @Override public long getLastCleanupTime() { return lastCleanupTime; } @Override public void setLastCleanupTime(long lastCleanupTime) { this.lastCleanupTime = lastCleanupTime; } @Override public long getLastCleanupTimeCopy() { return lastCleanupTimeCopy; } @Override public void setLastCleanupTimeCopy(long lastCleanupTimeCopy) { this.lastCleanupTimeCopy = lastCleanupTimeCopy; } /** * Cleans up the container's state if the enclosing partition is migrated * off this member. Whether cleanup is needed is decided based on the * provided {@code replicaIndex}. * * @param replicaIndex The replica index to use for deciding per map whether * cleanup is necessary or not */ @Override public final void cleanUpOnMigration(int replicaIndex) { mapService.getMapServiceContext().getMapContainers().entrySet() .stream() .filter(entry -> replicaIndex == -1 || lesserBackupMapsThenWithContainer(replicaIndex).test(entry.getValue())) .forEach(entry -> cleanUpMap(entry.getKey(), entry.getValue())); } protected void cleanUpMap(String mapName, MapContainer mapContainer) { // overridden in enterprise } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy