blob: c97c01f32c33cdfac75a07382f61206874ce447c [file] [log] [blame]
// 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 com.cloud.hypervisor.vmware.util;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Timer;
import java.util.TimerTask;
import org.apache.log4j.Logger;
import org.apache.cloudstack.managed.context.ManagedContextTimerTask;
public class VmwareContextPool {
private static final Logger s_logger = Logger.getLogger(VmwareContextPool.class);
private static final long DEFAULT_CHECK_INTERVAL = 10000;
private static final int DEFAULT_IDLE_QUEUE_LENGTH = 128;
private List<VmwareContext> _outstandingRegistry = new ArrayList<VmwareContext>();
private Map<String, List<VmwareContext>> _pool;
private int _maxIdleQueueLength = DEFAULT_IDLE_QUEUE_LENGTH;
private long _idleCheckIntervalMs = DEFAULT_CHECK_INTERVAL;
private Timer _timer = new Timer();
public VmwareContextPool() {
this(DEFAULT_IDLE_QUEUE_LENGTH, DEFAULT_CHECK_INTERVAL);
}
public VmwareContextPool(int maxIdleQueueLength) {
this(maxIdleQueueLength, DEFAULT_CHECK_INTERVAL);
}
public VmwareContextPool(int maxIdleQueueLength, long idleCheckIntervalMs) {
_pool = new HashMap<String, List<VmwareContext>>();
_maxIdleQueueLength = maxIdleQueueLength;
_idleCheckIntervalMs = idleCheckIntervalMs;
_timer.scheduleAtFixedRate(getTimerTask(), _idleCheckIntervalMs, _idleCheckIntervalMs);
}
public void registerOutstandingContext(VmwareContext context) {
assert (context != null);
synchronized (this) {
_outstandingRegistry.add(context);
}
}
public void unregisterOutstandingContext(VmwareContext context) {
assert (context != null);
synchronized (this) {
_outstandingRegistry.remove(context);
}
}
public VmwareContext getContext(String vCenterAddress, String vCenterUserName) {
String poolKey = composePoolKey(vCenterAddress, vCenterUserName);
synchronized (this) {
List<VmwareContext> l = _pool.get(poolKey);
if (l == null)
return null;
if (l.size() > 0) {
VmwareContext context = l.remove(0);
context.setPoolInfo(this, poolKey);
if (s_logger.isTraceEnabled())
s_logger.trace("Return a VmwareContext from the idle pool: " + poolKey + ". current pool size: " + l.size() + ", outstanding count: " +
VmwareContext.getOutstandingContextCount());
return context;
}
// TODO, we need to control the maximum number of outstanding VmwareContext object in the future
return null;
}
}
public void returnContext(VmwareContext context) {
assert (context.getPool() == this);
assert (context.getPoolKey() != null);
synchronized (this) {
List<VmwareContext> l = _pool.get(context.getPoolKey());
if (l == null) {
l = new ArrayList<VmwareContext>();
_pool.put(context.getPoolKey(), l);
}
if (l.size() < _maxIdleQueueLength) {
context.clearStockObjects();
l.add(context);
if (s_logger.isTraceEnabled())
s_logger.trace("Recycle VmwareContext into idle pool: " + context.getPoolKey() + ", current idle pool size: " + l.size() + ", outstanding count: " +
VmwareContext.getOutstandingContextCount());
} else {
if (s_logger.isTraceEnabled())
s_logger.trace("VmwareContextPool queue exceeds limits, queue size: " + l.size());
context.close();
}
}
}
private TimerTask getTimerTask() {
return new ManagedContextTimerTask() {
@Override
protected void runInContext() {
try {
// doIdleCheck();
doKeepAlive();
} catch (Throwable e) {
s_logger.error("Unexpected exception", e);
}
}
};
}
private void getKeepAliveCheckContexts(List<VmwareContext> l, int batchSize) {
synchronized (this) {
int size = Math.min(_outstandingRegistry.size(), batchSize);
while (size > 0) {
VmwareContext context = _outstandingRegistry.remove(0);
l.add(context);
_outstandingRegistry.add(context);
size--;
}
}
}
private void doKeepAlive() {
List<VmwareContext> l = new ArrayList<VmwareContext>();
int batchSize = (int)(_idleCheckIntervalMs / 1000); // calculate batch size at 1 request/sec rate
getKeepAliveCheckContexts(l, batchSize);
for (VmwareContext context : l) {
try {
context.idleCheck();
} catch (Throwable e) {
s_logger.warn("Exception caught during VmwareContext idle check, close and discard the context", e);
context.close();
}
}
}
public static String composePoolKey(String vCenterAddress, String vCenterUserName) {
assert (vCenterUserName != null);
assert (vCenterAddress != null);
return vCenterUserName + "@" + vCenterAddress;
}
}