From 2e284e1f75718e5d839ebc664bfe3e0a63eadab2 Mon Sep 17 00:00:00 2001 From: Kelven Yang Date: Mon, 28 Mar 2011 18:41:17 -0700 Subject: [PATCH] Add system VM load scaner --- .../com/cloud/vm/SystemVmLoadScanHandler.java | 18 ++++ .../src/com/cloud/vm/SystemVmLoadScanner.java | 100 ++++++++++++++++++ 2 files changed, 118 insertions(+) create mode 100644 server/src/com/cloud/vm/SystemVmLoadScanHandler.java create mode 100644 server/src/com/cloud/vm/SystemVmLoadScanner.java diff --git a/server/src/com/cloud/vm/SystemVmLoadScanHandler.java b/server/src/com/cloud/vm/SystemVmLoadScanHandler.java new file mode 100644 index 00000000000..ced7e9e6ddb --- /dev/null +++ b/server/src/com/cloud/vm/SystemVmLoadScanHandler.java @@ -0,0 +1,18 @@ +package com.cloud.vm; + +import com.cloud.vm.SystemVmLoadScanner.AfterScanAction; + +public interface SystemVmLoadScanHandler { + boolean canScan(); + + void onScanStart(); + + T[] getScannablePools(); + boolean isPoolReadyForScan(T pool); + AfterScanAction scanPool(T pool); + void expandPool(T pool); + void shrinkPool(T pool); + + void onScanEnd(); +} + diff --git a/server/src/com/cloud/vm/SystemVmLoadScanner.java b/server/src/com/cloud/vm/SystemVmLoadScanner.java new file mode 100644 index 00000000000..7649897699b --- /dev/null +++ b/server/src/com/cloud/vm/SystemVmLoadScanner.java @@ -0,0 +1,100 @@ +package com.cloud.vm; + +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; + +import org.apache.log4j.Logger; + +import com.cloud.maid.StackMaid; +import com.cloud.utils.concurrency.NamedThreadFactory; +import com.cloud.utils.db.GlobalLock; +import com.cloud.utils.db.Transaction; + +// +// TODO: simple load scanner, to minimize code changes required in console proxy manager and SSVM, we still leave most of work at handler +// +public class SystemVmLoadScanner { + public enum AfterScanAction { nop, expand, shrink } + + private static final Logger s_logger = Logger.getLogger(SystemVmLoadScanner.class); + + private static final int ACQUIRE_GLOBAL_LOCK_TIMEOUT_FOR_COOPERATION = 3; // 3 seconds + + private final SystemVmLoadScanHandler _scanHandler; + private final ScheduledExecutorService _capacityScanScheduler; + private final GlobalLock _capacityScanLock; + + public SystemVmLoadScanner(SystemVmLoadScanHandler scanHandler) { + _scanHandler = scanHandler; + _capacityScanScheduler = Executors.newScheduledThreadPool(1, new NamedThreadFactory(scanHandler.getClass().getSimpleName())); + _capacityScanLock = GlobalLock.getInternLock(scanHandler.getClass().getSimpleName() + ".scan.lock"); + } + + public void initScan(long startupDelayMs, long scanIntervalMs) { + _capacityScanScheduler.scheduleAtFixedRate(getCapacityScanTask(), startupDelayMs, scanIntervalMs, TimeUnit.MILLISECONDS); + } + + private Runnable getCapacityScanTask() { + return new Runnable() { + + @Override + public void run() { + Transaction txn = Transaction.open(Transaction.CLOUD_DB); + try { + reallyRun(); + } catch (Throwable e) { + s_logger.warn("Unexpected exception " + e.getMessage(), e); + } finally { + StackMaid.current().exitCleanup(); + txn.close(); + } + } + + private void reallyRun() { + loadScan(); + } + }; + } + + private void loadScan() { + if(!_scanHandler.canScan()) { + return; + } + + if (!_capacityScanLock.lock(ACQUIRE_GLOBAL_LOCK_TIMEOUT_FOR_COOPERATION)) { + if (s_logger.isTraceEnabled()) { + s_logger.trace("Capacity scan lock is used by others, skip and wait for my turn"); + } + return; + } + + try { + _scanHandler.onScanStart(); + + T[] pools = _scanHandler.getScannablePools(); + for(T p : pools) { + if(_scanHandler.isPoolReadyForScan(p)) { + switch(_scanHandler.scanPool(p)) { + case nop: + break; + + case expand: + _scanHandler.expandPool(p); + break; + + case shrink: + _scanHandler.shrinkPool(p); + break; + } + } + } + + _scanHandler.onScanEnd(); + + } finally { + _capacityScanLock.unlock(); + } + } +} +