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

com.hazelcast.replicatedmap.impl.ReplicatedMapSplitBrainHandlerService Maven / Gradle / Ivy

There is a newer version: 5.5.0
Show newest version
/*
 * Copyright (c) 2008-2016, 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.replicatedmap.impl;

import com.hazelcast.config.ReplicatedMapConfig;
import com.hazelcast.core.ExecutionCallback;
import com.hazelcast.core.ICompletableFuture;
import com.hazelcast.internal.serialization.SerializationService;
import com.hazelcast.logging.ILogger;
import com.hazelcast.nio.Address;
import com.hazelcast.replicatedmap.impl.operation.MergeOperation;
import com.hazelcast.replicatedmap.impl.record.ReplicatedMapEntryView;
import com.hazelcast.replicatedmap.impl.record.ReplicatedRecord;
import com.hazelcast.replicatedmap.impl.record.ReplicatedRecordStore;
import com.hazelcast.replicatedmap.merge.MergePolicyProvider;
import com.hazelcast.replicatedmap.merge.ReplicatedMapMergePolicy;
import com.hazelcast.spi.NodeEngine;
import com.hazelcast.spi.SplitBrainHandlerService;
import com.hazelcast.util.ExceptionUtil;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;

import static com.hazelcast.replicatedmap.impl.ReplicatedMapService.SERVICE_NAME;

/**
 * Contains split-brain handling logic for {@link com.hazelcast.core.ReplicatedMap}
 */
public class ReplicatedMapSplitBrainHandlerService implements SplitBrainHandlerService {
    private final ReplicatedMapService service;
    private final MergePolicyProvider mergePolicyProvider;
    private final NodeEngine nodeEngine;
    private final SerializationService serializationService;

    public ReplicatedMapSplitBrainHandlerService(ReplicatedMapService service,
                                                 MergePolicyProvider mergePolicyProvider) {
        this.service = service;
        this.mergePolicyProvider = mergePolicyProvider;
        this.nodeEngine = service.getNodeEngine();
        this.serializationService = nodeEngine.getSerializationService();
    }

    @Override
    public Runnable prepareMergeRunnable() {
        HashMap> recordMap = new HashMap>();
        Address thisAddress = service.getNodeEngine().getThisAddress();
        List partitions = nodeEngine.getPartitionService().getMemberPartitions(thisAddress);
        for (Integer partition : partitions) {
            PartitionContainer partitionContainer = service.getPartitionContainer(partition);
            ConcurrentMap stores = partitionContainer.getStores();
            for (ReplicatedRecordStore store : stores.values()) {
                String name = store.getName();
                Collection records = recordMap.get(name);
                if (records == null) {
                    records = new ArrayList();
                }
                Iterator iterator = store.recordIterator();
                while (iterator.hasNext()) {
                    ReplicatedRecord record = iterator.next();
                    records.add(record);
                }
                recordMap.put(name, records);
                store.reset();
            }
        }

        return new Merger(recordMap);
    }


    private class Merger implements Runnable {

        private static final int TIMEOUT_FACTOR = 500;

        Map> recordMap;

        public Merger(Map> recordMap) {
            this.recordMap = recordMap;
        }

        @Override
        public void run() {
            final Semaphore semaphore = new Semaphore(0);
            int recordCount = 0;
            final ILogger logger = nodeEngine.getLogger(ReplicatedMapService.class);

            ExecutionCallback mergeCallback = new ExecutionCallback() {
                @Override
                public void onResponse(Object response) {
                    semaphore.release(1);
                }

                @Override
                public void onFailure(Throwable t) {
                    logger.warning("Error while running replicated map merge operation: " + t.getMessage());
                    semaphore.release(1);
                }
            };

            for (Map.Entry> entry : recordMap.entrySet()) {
                recordCount++;
                String name = entry.getKey();
                Collection records = entry.getValue();
                ReplicatedMapConfig replicatedMapConfig = service.getReplicatedMapConfig(name);
                String mergePolicy = replicatedMapConfig.getMergePolicy();
                ReplicatedMapMergePolicy policy = mergePolicyProvider.getMergePolicy(mergePolicy);
                for (ReplicatedRecord record : records) {
                    ReplicatedMapEntryView entryView = createEntryView(record);
                    MergeOperation mergeOperation = new MergeOperation(name, record.getKeyInternal(), entryView, policy);
                    try {
                        int partitionId = nodeEngine.getPartitionService().getPartitionId(record.getKeyInternal());
                        ICompletableFuture f = nodeEngine.getOperationService()
                                .invokeOnPartition(SERVICE_NAME, mergeOperation, partitionId);
                        f.andThen(mergeCallback);
                    } catch (Throwable t) {
                        throw ExceptionUtil.rethrow(t);
                    }
                }
            }
            try {
                semaphore.tryAcquire(recordCount, recordCount * TIMEOUT_FACTOR, TimeUnit.MILLISECONDS);
            } catch (InterruptedException e) {
                logger.finest("Interrupted while waiting replicated map merge operation...");
            }

        }

        private ReplicatedMapEntryView createEntryView(ReplicatedRecord record) {
            Object key = serializationService.toObject(record.getKeyInternal());
            Object value = serializationService.toObject(record.getValueInternal());
            ReplicatedMapEntryView entryView = new ReplicatedMapEntryView(key, value);
            entryView.setHits(record.getHits());
            entryView.setTtl(record.getTtlMillis());
            entryView.setLastAccessTime(record.getLastAccessTime());
            entryView.setCreationTime(record.getCreationTime());
            entryView.setLastUpdateTime(record.getUpdateTime());
            return entryView;
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy