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

com.hazelcast.internal.networking.nio.iobalancer.LoadTracker 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.internal.networking.nio.iobalancer;

import com.hazelcast.internal.networking.nio.MigratablePipeline;
import com.hazelcast.internal.networking.nio.NioThread;
import com.hazelcast.logging.ILogger;
import com.hazelcast.internal.util.ItemCounter;

import java.util.HashSet;
import java.util.Map;
import java.util.Set;

import static com.hazelcast.internal.util.MapUtil.createHashMap;

/**
 * Tracks the load of of NioThread(s) and creates a mapping between NioThread -> NioPipeline.
 * 

* This class is not thread-safe with the exception of * {@link #addPipeline(MigratablePipeline)} and * {@link #removePipeline(MigratablePipeline)} */ class LoadTracker { private final ILogger logger; //all known IO ioThreads. we assume no. of ioThreads is constant during a lifespan of a member private final NioThread[] ioThreads; private final Map> ownerToPipelines; //load per pipeline since an instance started private final ItemCounter lastLoadCounter = new ItemCounter<>(); //load per NioThread since last calculation private final ItemCounter ownerLoad = new ItemCounter<>(); //load per pipeline since last calculation private final ItemCounter pipelineLoadCount = new ItemCounter<>(); //contains all known pipelines private final Set pipelines = new HashSet<>(); private final LoadImbalance imbalance; LoadTracker(NioThread[] ioThreads, ILogger logger) { this.logger = logger; this.ioThreads = new NioThread[ioThreads.length]; System.arraycopy(ioThreads, 0, this.ioThreads, 0, ioThreads.length); this.ownerToPipelines = createHashMap(ioThreads.length); for (NioThread selector : ioThreads) { ownerToPipelines.put(selector, new HashSet<>()); } this.imbalance = new LoadImbalance(ownerToPipelines, pipelineLoadCount); } /** * Recalculates a new LoadStatus. Returned instance of {@link LoadImbalance} are recycled * between invocations therefore they are valid for the last invocation only. * * @return recalculated imbalance */ LoadImbalance updateImbalance() { clearWorkingImbalance(); updateNewWorkingImbalance(); updateNewFinalImbalance(); printDebugTable(); return imbalance; } // just for testing Set getPipelines() { return pipelines; } // just for testing ItemCounter getLastLoadCounter() { return lastLoadCounter; } // just for testing ItemCounter getPipelineLoadCount() { return pipelineLoadCount; } private void updateNewFinalImbalance() { imbalance.minimumLoad = Long.MAX_VALUE; imbalance.maximumLoad = Long.MIN_VALUE; imbalance.srcOwner = null; imbalance.dstOwner = null; for (NioThread owner : ioThreads) { long load = ownerLoad.get(owner); int pipelineCount = ownerToPipelines.get(owner).size(); if (load > imbalance.maximumLoad && pipelineCount > 1) { // if a nioThread has only 1 handle, there is no point in making it a source nioThread since // there is no pipeline that can be migrated anyway. In that case it is better to move on to // the next nioThread. imbalance.maximumLoad = load; imbalance.srcOwner = owner; } if (load < imbalance.minimumLoad) { imbalance.minimumLoad = load; imbalance.dstOwner = owner; } } } private void updateNewWorkingImbalance() { for (MigratablePipeline pipeline : pipelines) { updatePipelineState(pipeline); } } private void updatePipelineState(MigratablePipeline pipeline) { long pipelineLoad = getLoadSinceLastCheck(pipeline); pipelineLoadCount.set(pipeline, pipelineLoad); NioThread owner = pipeline.owner(); if (owner == null) { // the pipeline is currently being migrated - owner is null return; } ownerLoad.add(owner, pipelineLoad); ownerToPipelines.get(owner).add(pipeline); } private long getLoadSinceLastCheck(MigratablePipeline pipeline) { long load = pipeline.load(); long lastLoad = lastLoadCounter.getAndSet(pipeline, load); return load - lastLoad; } private void clearWorkingImbalance() { pipelineLoadCount.reset(); ownerLoad.reset(); for (Set pipelines : ownerToPipelines.values()) { pipelines.clear(); } } void addPipeline(MigratablePipeline pipeline) { pipelines.add(pipeline); } void removePipeline(MigratablePipeline pipeline) { pipelines.remove(pipeline); pipelineLoadCount.remove(pipeline); lastLoadCounter.remove(pipeline); } private void printDebugTable() { if (!logger.isFinestEnabled()) { return; } NioThread minThread = imbalance.dstOwner; NioThread maxThread = imbalance.srcOwner; if (minThread == null || maxThread == null) { return; } StringBuilder sb = new StringBuilder(System.lineSeparator()) .append("------------") .append(System.lineSeparator()); Long loadPerOwner = ownerLoad.get(minThread); sb.append("Min NioThread ") .append(minThread) .append(" receive-load ") .append(loadPerOwner) .append(" load. "); sb.append("It contains following pipelines: "). append(System.lineSeparator()); appendSelectorInfo(minThread, ownerToPipelines, sb); loadPerOwner = ownerLoad.get(maxThread); sb.append("Max NioThread ") .append(maxThread) .append(" receive-load ") .append(loadPerOwner); sb.append("It contains following pipelines: ") .append(System.lineSeparator()); appendSelectorInfo(maxThread, ownerToPipelines, sb); sb.append("Other NioThread: ") .append(System.lineSeparator()); for (NioThread thread : ioThreads) { if (!thread.equals(minThread) && !thread.equals(maxThread)) { loadPerOwner = ownerLoad.get(thread); sb.append("NioThread ") .append(thread) .append(" contains ") .append(loadPerOwner) .append(" and has these pipelines: ") .append(System.lineSeparator()); appendSelectorInfo(thread, ownerToPipelines, sb); } } sb.append("------------") .append(System.lineSeparator()); logger.finest(sb.toString()); } private void appendSelectorInfo( NioThread minThread, Map> pipelinesPerOwner, StringBuilder sb) { Set pipelines = pipelinesPerOwner.get(minThread); for (MigratablePipeline pipeline : pipelines) { Long loadPerPipeline = pipelineLoadCount.get(pipeline); sb.append(pipeline) .append(": ") .append(loadPerPipeline) .append(System.lineSeparator()); } sb.append(System.lineSeparator()); } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy