org.apache.iotdb.db.rescon.SystemInfo Maven / Gradle / Ivy
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 org.apache.iotdb.db.rescon;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.PriorityQueue;
import org.apache.iotdb.db.conf.IoTDBConfig;
import org.apache.iotdb.db.conf.IoTDBDescriptor;
import org.apache.iotdb.db.engine.flush.FlushManager;
import org.apache.iotdb.db.engine.storagegroup.StorageGroupInfo;
import org.apache.iotdb.db.engine.storagegroup.TsFileProcessor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class SystemInfo {
private static final IoTDBConfig config = IoTDBDescriptor.getInstance().getConfig();
private static final Logger logger = LoggerFactory.getLogger(SystemInfo.class);
private long totalSgMemCost = 0L;
private volatile boolean rejected = false;
private Map reportedSgMemCostMap = new HashMap<>();
private static final double FLUSH_THERSHOLD =
config.getAllocateMemoryForWrite() * config.getFlushProportion();
private static final double REJECT_THERSHOLD =
config.getAllocateMemoryForWrite() * config.getRejectProportion();
/**
* Report current mem cost of storage group to system. Called when the memory of
* storage group newly accumulates to IoTDBConfig.getStorageGroupSizeReportThreshold()
*
* @param storageGroupInfo storage group
*/
public synchronized void reportStorageGroupStatus(StorageGroupInfo storageGroupInfo) {
long delta = storageGroupInfo.getMemCost() -
reportedSgMemCostMap.getOrDefault(storageGroupInfo, 0L);
totalSgMemCost += delta;
if (logger.isDebugEnabled()) {
logger.debug("Report Storage Group Status to the system. "
+ "After adding {}, current sg mem cost is {}.", delta, totalSgMemCost);
}
reportedSgMemCostMap.put(storageGroupInfo, storageGroupInfo.getMemCost());
storageGroupInfo.setLastReportedSize(storageGroupInfo.getMemCost());
if (totalSgMemCost >= FLUSH_THERSHOLD) {
logger.debug("The total storage group mem costs are too large, call for flushing. "
+ "Current sg cost is {}", totalSgMemCost);
chooseTSPToMarkFlush();
}
if (totalSgMemCost >= REJECT_THERSHOLD) {
logger.info("Change system to reject status...");
rejected = true;
}
}
/**
* Report resetting the mem cost of sg to system.
* It will be called after flushing, closing and failed to insert
*
* @param storageGroupInfo storage group
*/
public synchronized void resetStorageGroupStatus(StorageGroupInfo storageGroupInfo,
boolean shouldInvokeFlush) {
if (reportedSgMemCostMap.containsKey(storageGroupInfo)) {
this.totalSgMemCost -= (reportedSgMemCostMap.get(storageGroupInfo) -
storageGroupInfo.getMemCost());
storageGroupInfo.setLastReportedSize(storageGroupInfo.getMemCost());
reportedSgMemCostMap.put(storageGroupInfo, storageGroupInfo.getMemCost());
if (shouldInvokeFlush) {
checkSystemToInvokeFlush();
}
}
}
private void checkSystemToInvokeFlush() {
if (totalSgMemCost >= FLUSH_THERSHOLD && totalSgMemCost < REJECT_THERSHOLD) {
logger.debug("Some sg memory released but still exceeding flush proportion, call flush.");
if (rejected) {
logger.info("Some sg memory released, set system to normal status.");
}
logCurrentTotalSGMemory();
rejected = false;
forceAsyncFlush();
}
else if (totalSgMemCost >= REJECT_THERSHOLD) {
logger.warn("Some sg memory released, but system is still in reject status.");
logCurrentTotalSGMemory();
rejected = true;
forceAsyncFlush();
}
else {
logger.debug("Some sg memory released, system is in normal status.");
logCurrentTotalSGMemory();
rejected = false;
}
}
private void logCurrentTotalSGMemory() {
logger.debug("Current Sg cost is {}", totalSgMemCost);
}
/**
* Order all tsfileProcessors in system by memory cost of actual data points in memtable.
* Mark the top K TSPs as to be flushed,
* so that after flushing the K TSPs, the memory cost should be less than FLUSH_THRESHOLD
*/
private void chooseTSPToMarkFlush() {
if (FlushManager.getInstance().getNumberOfWorkingTasks() > 0) {
return;
}
// If invoke flush by replaying logs, do not flush now!
if (reportedSgMemCostMap.size() == 0) {
return;
}
// get the tsFile processors which has the max work MemTable size
List processors = getTsFileProcessorsToFlush();
for (TsFileProcessor processor : processors) {
if (processor != null) {
processor.setFlush();
}
}
}
/**
* Be Careful!! This method can only be called by flush thread!
*/
private void forceAsyncFlush() {
if (FlushManager.getInstance().getNumberOfWorkingTasks() > 0) {
return;
}
List processors = getTsFileProcessorsToFlush();
if (logger.isDebugEnabled()) {
logger.debug("[mem control] get {} tsp to flush", processors.size());
}
for (TsFileProcessor processor : processors) {
if (processor != null) {
processor.startAsyncFlush();
}
}
}
private List getTsFileProcessorsToFlush() {
PriorityQueue tsps = new PriorityQueue<>(
(o1, o2) -> Long.compare(o2.getWorkMemTableRamCost(), o1.getWorkMemTableRamCost()));
for (StorageGroupInfo sgInfo : reportedSgMemCostMap.keySet()) {
tsps.addAll(sgInfo.getAllReportedTsp());
}
List processors = new ArrayList<>();
long memCost = 0;
while (totalSgMemCost - memCost > FLUSH_THERSHOLD / 2) {
if (tsps.isEmpty() || tsps.peek().getWorkMemTableRamCost() == 0) {
return processors;
}
processors.add(tsps.peek());
memCost += tsps.peek().getWorkMemTableRamCost();
tsps.poll();
}
return processors;
}
public boolean isRejected() {
return rejected;
}
public void close() {
reportedSgMemCostMap.clear();
totalSgMemCost = 0;
rejected = false;
}
public static SystemInfo getInstance() {
return InstanceHolder.instance;
}
private static class InstanceHolder {
private InstanceHolder() {
}
private static SystemInfo instance = new SystemInfo();
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy