blob: b4733ecc2b1bfc2ab63e68adb6b17d352d34fe11 [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 org.apache.commons.lang3.StringUtils;
import org.apache.cloudstack.managed.context.ManagedContextTimerTask;
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.LogManager;
import org.joda.time.Duration;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Queue;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.ConcurrentMap;
public class VmwareContextPool {
protected Logger logger = LogManager.getLogger(getClass());
private static final Duration DEFAULT_CHECK_INTERVAL = Duration.millis(10000L);
private static final int DEFAULT_IDLE_QUEUE_LENGTH = 128;
private final ConcurrentMap<String, Queue<VmwareContext>> _pool;
private int _maxIdleQueueLength = DEFAULT_IDLE_QUEUE_LENGTH;
private Duration _idleCheckInterval = DEFAULT_CHECK_INTERVAL;
private Timer _timer = new Timer();
public VmwareContextPool() {
this(DEFAULT_IDLE_QUEUE_LENGTH, DEFAULT_CHECK_INTERVAL);
}
public VmwareContextPool(int maxIdleQueueLength, Duration idleCheckInterval) {
_pool = new ConcurrentHashMap<String, Queue<VmwareContext>>();
_maxIdleQueueLength = maxIdleQueueLength;
_idleCheckInterval = idleCheckInterval;
_timer.scheduleAtFixedRate(getTimerTask(), _idleCheckInterval.getMillis(), _idleCheckInterval.getMillis());
}
public VmwareContext getContext(final String vCenterAddress, final String vCenterUserName) {
final String poolKey = composePoolKey(vCenterAddress, vCenterUserName).intern();
if (StringUtils.isEmpty(poolKey)) {
return null;
}
synchronized (poolKey) {
final Queue<VmwareContext> ctxList = _pool.get(poolKey);
if (ctxList != null && !ctxList.isEmpty()) {
final VmwareContext context = ctxList.remove();
if (context != null) {
context.setPoolInfo(this, poolKey);
}
if (logger.isTraceEnabled()) {
logger.trace("Return a VmwareContext from the idle pool: " + poolKey + ". current pool size: " + ctxList.size() + ", outstanding count: " +
VmwareContext.getOutstandingContextCount());
}
return context;
}
return null;
}
}
public void registerContext(final VmwareContext context) {
assert (context.getPool() == this);
assert (context.getPoolKey() != null);
final String poolKey = context.getPoolKey().intern();
synchronized (poolKey) {
Queue<VmwareContext> ctxQueue = _pool.get(poolKey);
if (ctxQueue == null) {
ctxQueue = new ConcurrentLinkedQueue<>();
_pool.put(poolKey, ctxQueue);
}
if (ctxQueue.size() >= _maxIdleQueueLength) {
final VmwareContext oldestContext = ctxQueue.remove();
if (oldestContext != null) {
try {
oldestContext.close();
} catch (Throwable t) {
logger.error("Unexpected exception caught while trying to purge oldest VmwareContext", t);
}
}
}
context.clearStockObjects();
ctxQueue.add(context);
if (logger.isTraceEnabled()) {
logger.trace("Recycle VmwareContext into idle pool: " + context.getPoolKey() + ", current idle pool size: " + ctxQueue.size() + ", outstanding count: "
+ VmwareContext.getOutstandingContextCount());
}
}
}
public void unregisterContext(final VmwareContext context) {
assert (context != null);
final String poolKey = context.getPoolKey().intern();
final Queue<VmwareContext> ctxList = _pool.get(poolKey);
synchronized (poolKey) {
if (StringUtils.isNotEmpty(poolKey) && ctxList != null && ctxList.contains(context)) {
ctxList.remove(context);
}
}
}
private TimerTask getTimerTask() {
return new ManagedContextTimerTask() {
@Override
protected void runInContext() {
try {
doKeepAlive();
} catch (Throwable e) {
logger.error("Unexpected exception", e);
}
}
};
}
private void doKeepAlive() {
final List<VmwareContext> closableCtxList = new ArrayList<>();
for (final Queue<VmwareContext> ctxQueue : _pool.values()) {
for (Iterator<VmwareContext> iterator = ctxQueue.iterator(); iterator.hasNext();) {
final VmwareContext context = iterator.next();
if (context == null) {
iterator.remove();
continue;
}
try {
context.idleCheck();
} catch (Throwable e) {
logger.warn("Exception caught during VmwareContext idle check, close and discard the context", e);
closableCtxList.add(context);
iterator.remove();
}
}
}
for (final VmwareContext context : closableCtxList) {
context.close();
}
}
public static String composePoolKey(final String vCenterAddress, final String vCenterUserName) {
assert (vCenterUserName != null);
assert (vCenterAddress != null);
return vCenterUserName + "@" + vCenterAddress;
}
}