mirror of https://github.com/apache/cloudstack.git
167 lines
6.4 KiB
Java
167 lines
6.4 KiB
Java
// 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 com.google.common.base.Strings;
|
|
import org.apache.cloudstack.managed.context.ManagedContextTimerTask;
|
|
import org.apache.log4j.Logger;
|
|
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 {
|
|
private static final Logger s_logger = Logger.getLogger(VmwareContextPool.class);
|
|
|
|
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 (Strings.isNullOrEmpty(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 (s_logger.isTraceEnabled()) {
|
|
s_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) {
|
|
s_logger.error("Unexpected exception caught while trying to purge oldest VmwareContext", t);
|
|
}
|
|
}
|
|
}
|
|
context.clearStockObjects();
|
|
ctxQueue.add(context);
|
|
|
|
if (s_logger.isTraceEnabled()) {
|
|
s_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 (!Strings.isNullOrEmpty(poolKey) && ctxList != null && ctxList.contains(context)) {
|
|
ctxList.remove(context);
|
|
}
|
|
}
|
|
}
|
|
|
|
private TimerTask getTimerTask() {
|
|
return new ManagedContextTimerTask() {
|
|
@Override
|
|
protected void runInContext() {
|
|
try {
|
|
doKeepAlive();
|
|
} catch (Throwable e) {
|
|
s_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) {
|
|
s_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;
|
|
}
|
|
}
|