diff --git a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/resource/VmwareContextFactory.java b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/resource/VmwareContextFactory.java index 5db9da3c02d..a647560c48d 100755 --- a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/resource/VmwareContextFactory.java +++ b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/resource/VmwareContextFactory.java @@ -25,22 +25,23 @@ import org.springframework.stereotype.Component; import com.cloud.hypervisor.vmware.manager.VmwareManager; import com.cloud.hypervisor.vmware.util.VmwareClient; import com.cloud.hypervisor.vmware.util.VmwareContext; +import com.cloud.hypervisor.vmware.util.VmwareContextPool; import com.cloud.utils.StringUtils; @Component public class VmwareContextFactory { - private static final Logger s_logger = Logger.getLogger(VmwareContextFactory.class); private static volatile int s_seq = 1; private static VmwareManager s_vmwareMgr; + private static VmwareContextPool s_pool; @Inject VmwareManager _vmwareMgr; static { // skip certificate check System.setProperty("axis.socketSecureFactory", "org.apache.axis.components.net.SunFakeTrustSocketFactory"); - //s_vmwareMgr = ComponentContext.inject(VmwareManagerImpl.class); + s_pool = new VmwareContextPool(); } @PostConstruct @@ -54,8 +55,6 @@ public class VmwareContextFactory { assert(vCenterPassword != null); String serviceUrl = "https://" + vCenterAddress + "/sdk/vimService"; - //String[] params = new String[] {"--url", serviceUrl, "--username", vCenterUserName, "--password", vCenterPassword }; - if(s_logger.isDebugEnabled()) s_logger.debug("initialize VmwareContext. url: " + serviceUrl + ", username: " + vCenterUserName + ", password: " + StringUtils.getMaskedPasswordForDisplay(vCenterPassword)); @@ -70,4 +69,21 @@ public class VmwareContextFactory { return context; } + + public static VmwareContext getContext(String vCenterAddress, String vCenterUserName, String vCenterPassword) throws Exception { + VmwareContext context = s_pool.getContext(vCenterAddress, vCenterUserName); + if(context == null) + context = create(vCenterAddress, vCenterUserName, vCenterPassword); + + if(context != null) { + context.setPoolInfo(s_pool, VmwareContextPool.composePoolKey(vCenterAddress, vCenterUserName)); + + context.registerStockObject(VmwareManager.CONTEXT_STOCK_NAME, s_vmwareMgr); + + context.registerStockObject("serviceconsole", s_vmwareMgr.getServiceConsolePortGroupName()); + context.registerStockObject("manageportgroup", s_vmwareMgr.getManagementPortGroupName()); + } + + return context; + } } diff --git a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/resource/VmwareResource.java b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/resource/VmwareResource.java index 70b5bf0b225..d0173d610e9 100755 --- a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/resource/VmwareResource.java +++ b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/resource/VmwareResource.java @@ -374,7 +374,7 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa protected DiskControllerType _rootDiskController = DiskControllerType.ide; protected ManagedObjectReference _morHyperHost; - protected VmwareContext _serviceContext; + protected ThreadLocal _serviceContext = new ThreadLocal(); protected String _hostName; protected HashMap _vms = new HashMap(71); @@ -602,10 +602,10 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa } } finally { + recycleServiceContext(); NDC.pop(); } - if(s_logger.isTraceEnabled()) s_logger.trace("End executeRequest(), cmd: " + cmd.getClass().getSimpleName()); @@ -3324,7 +3324,7 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa } } - protected synchronized Answer execute(final RemoteAccessVpnCfgCommand cmd) { + protected Answer execute(final RemoteAccessVpnCfgCommand cmd) { String controlIp = getRouterSshControlIp(cmd); StringBuffer argsBuf = new StringBuffer(); if (cmd.isCreate()) { @@ -3368,7 +3368,7 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa return new Answer(cmd); } - protected synchronized Answer execute(final VpnUsersCfgCommand cmd) { + protected Answer execute(final VpnUsersCfgCommand cmd) { VmwareManager mgr = getServiceContext().getStockObject(VmwareManager.CONTEXT_STOCK_NAME); String controlIp = getRouterSshControlIp(cmd); @@ -5363,7 +5363,7 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa @Override - public synchronized CreateAnswer execute(CreateCommand cmd) { + public CreateAnswer execute(CreateCommand cmd) { if (s_logger.isInfoEnabled()) { s_logger.info("Executing resource CreateCommand: " + _gson.toJson(cmd)); } @@ -5397,12 +5397,11 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa } String volumeDatastorePath = String.format("[%s] %s.vmdk", dsMo.getName(), vmdkName); - synchronized (this) { - s_logger.info("Delete file if exists in datastore to clear the way for creating the volume. file: " + volumeDatastorePath); - VmwareStorageLayoutHelper.deleteVolumeVmdkFiles(dsMo, vmdkName, dcMo); - vmMo.createDisk(volumeDatastorePath, getMBsFromBytes(dskch.getSize()), morDatastore, -1); - vmMo.detachDisk(volumeDatastorePath, false); - } + + s_logger.info("Delete file if exists in datastore to clear the way for creating the volume. file: " + volumeDatastorePath); + VmwareStorageLayoutHelper.deleteVolumeVmdkFiles(dsMo, vmdkName, dcMo); + vmMo.createDisk(volumeDatastorePath, getMBsFromBytes(dskch.getSize()), morDatastore, -1); + vmMo.detachDisk(volumeDatastorePath, false); VolumeTO vol = new VolumeTO(cmd.getVolumeId(), dskch.getType(), pool.getType(), pool.getUuid(), dskch.getName(), pool.getPath(), vmdkName, dskch.getSize(), null); return new CreateAnswer(cmd, vol); @@ -5454,13 +5453,11 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa throw new Exception("Unable to create a dummy VM for volume creation"); } - synchronized (this) { - // s_logger.info("Delete file if exists in datastore to clear the way for creating the volume. file: " + volumeDatastorePath); - VmwareStorageLayoutHelper.deleteVolumeVmdkFiles(dsMo, volumeUuid.toString(), dcMo); + // s_logger.info("Delete file if exists in datastore to clear the way for creating the volume. file: " + volumeDatastorePath); + VmwareStorageLayoutHelper.deleteVolumeVmdkFiles(dsMo, volumeUuid.toString(), dcMo); - vmMo.createDisk(volumeDatastorePath, getMBsFromBytes(dskch.getSize()), morDatastore, vmMo.getScsiDeviceControllerKey()); - vmMo.detachDisk(volumeDatastorePath, false); - } + vmMo.createDisk(volumeDatastorePath, getMBsFromBytes(dskch.getSize()), morDatastore, vmMo.getScsiDeviceControllerKey()); + vmMo.detachDisk(volumeDatastorePath, false); VolumeTO vol = new VolumeTO(cmd.getVolumeId(), dskch.getType(), pool.getType(), pool.getUuid(), dskch.getName(), pool.getPath(), volumeUuid, dskch.getSize(), null); return new CreateAnswer(cmd, vol); @@ -5627,6 +5624,8 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa s_logger.info("Host " + hyperHost.getHyperHostName() + " is not in connected state"); return null; } + + ((HostMO)hyperHost).enableVncOnHostFirewall(); AboutInfo aboutInfo = ((HostMO)hyperHost).getHostAboutInfo(); hostApiVersion = aboutInfo.getApiVersion(); @@ -6451,48 +6450,40 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa } @Override - public synchronized VmwareContext getServiceContext(Command cmd) { - if (_serviceContext == null) { - try { - _serviceContext = VmwareContextFactory.create(_vCenterAddress, _username, _password); - VmwareHypervisorHost hyperHost = getHyperHost(_serviceContext, cmd); - assert(hyperHost instanceof HostMO); - - HostFirewallSystemMO firewallMo = ((HostMO)hyperHost).getHostFirewallSystemMO(); - boolean bRefresh = false; - if(firewallMo != null) { - HostFirewallInfo firewallInfo = firewallMo.getFirewallInfo(); - if(firewallInfo != null && firewallInfo.getRuleset() != null) { - for(HostFirewallRuleset rule : firewallInfo.getRuleset()) { - if("vncServer".equalsIgnoreCase(rule.getKey())) { - bRefresh = true; - firewallMo.enableRuleset("vncServer"); - } else if("gdbserver".equalsIgnoreCase(rule.getKey())) { - bRefresh = true; - firewallMo.enableRuleset("gdbserver"); - } - } - } - - if(bRefresh) - firewallMo.refreshFirewall(); - } - } catch (Exception e) { - s_logger.error("Unable to connect to vSphere server: " + _vCenterAddress, e); - throw new CloudRuntimeException("Unable to connect to vSphere server: " + _vCenterAddress); - } + public VmwareContext getServiceContext(Command cmd) { + if(_serviceContext.get() != null) + return _serviceContext.get(); + + VmwareContext context = null; + try { + context = VmwareContextFactory.getContext(_vCenterAddress, _username, _password); + _serviceContext.set(context); + } catch (Exception e) { + s_logger.error("Unable to connect to vSphere server: " + _vCenterAddress, e); + throw new CloudRuntimeException("Unable to connect to vSphere server: " + _vCenterAddress); } - return _serviceContext; + return context; } @Override - public synchronized void invalidateServiceContext(VmwareContext context) { - if (_serviceContext != null) { - _serviceContext.close(); - } - _serviceContext = null; + public void invalidateServiceContext(VmwareContext context) { + assert(_serviceContext.get() == context); + + _serviceContext.set(null); + if(context != null) + context.close(); } + private void recycleServiceContext() { + VmwareContext context = _serviceContext.get(); + _serviceContext.set(null); + + if(context != null) { + assert(context.getPool() != null); + context.getPool().returnContext(context); + } + } + @Override public VmwareHypervisorHost getHyperHost(VmwareContext context, Command cmd) { if (_morHyperHost.getType().equalsIgnoreCase("HostSystem")) { @@ -6517,7 +6508,6 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa @Override public void setName(String name) { // TODO Auto-generated method stub - } @Override @@ -6541,7 +6531,6 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa @Override public void setRunLevel(int level) { // TODO Auto-generated method stub - } @Override @@ -6590,6 +6579,7 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa return new Answer(cmd, false, msg); } } + private boolean isVMWareToolsInstalled(VirtualMachineMO vmMo) throws Exception{ GuestInfo guestInfo = vmMo.getVmGuestInfo(); return (guestInfo != null && guestInfo.getGuestState() != null && guestInfo.getGuestState().equalsIgnoreCase("running")); diff --git a/plugins/hypervisors/vmware/src/com/cloud/storage/resource/VmwareSecondaryStorageContextFactory.java b/plugins/hypervisors/vmware/src/com/cloud/storage/resource/VmwareSecondaryStorageContextFactory.java index 646ef633fc7..5032c98f375 100644 --- a/plugins/hypervisors/vmware/src/com/cloud/storage/resource/VmwareSecondaryStorageContextFactory.java +++ b/plugins/hypervisors/vmware/src/com/cloud/storage/resource/VmwareSecondaryStorageContextFactory.java @@ -22,14 +22,16 @@ import java.util.Map; import com.cloud.hypervisor.vmware.util.VmwareClient; import com.cloud.hypervisor.vmware.util.VmwareContext; +import com.cloud.hypervisor.vmware.util.VmwareContextPool; public class VmwareSecondaryStorageContextFactory { private static volatile int s_seq = 1; - private static Map s_contextMap = new HashMap(); + private static VmwareContextPool s_pool; public static void initFactoryEnvironment() { System.setProperty("axis.socketSecureFactory", "org.apache.axis.components.net.SunFakeTrustSocketFactory"); + s_pool = new VmwareContextPool(); } public static VmwareContext create(String vCenterAddress, String vCenterUserName, String vCenterPassword) throws Exception { @@ -37,37 +39,31 @@ public class VmwareSecondaryStorageContextFactory { assert(vCenterUserName != null); assert(vCenterPassword != null); - VmwareContext context = null; - - synchronized(s_contextMap) { - context = s_contextMap.get(vCenterAddress); - if(context == null) { - String serviceUrl = "https://" + vCenterAddress + "/sdk/vimService"; - //String[] params = new String[] {"--url", serviceUrl, "--username", vCenterUserName, "--password", vCenterPassword }; - VmwareClient vimClient = new VmwareClient(vCenterAddress + "-" + s_seq++); - vimClient.connect(serviceUrl, vCenterUserName, vCenterPassword); - context = new VmwareContext(vimClient, vCenterAddress); - context.registerStockObject("username", vCenterUserName); - context.registerStockObject("password", vCenterPassword); - - s_contextMap.put(vCenterAddress, context); - } - } - + String serviceUrl = "https://" + vCenterAddress + "/sdk/vimService"; + VmwareClient vimClient = new VmwareClient(vCenterAddress + "-" + s_seq++); + vimClient.connect(serviceUrl, vCenterUserName, vCenterPassword); + VmwareContext context = new VmwareContext(vimClient, vCenterAddress); assert(context != null); return context; } - - public static void invalidate(VmwareContext context) { - synchronized(s_contextMap) { - for(Iterator> entryIter = s_contextMap.entrySet().iterator(); entryIter.hasNext();) { - Map.Entry entry = entryIter.next(); - if(entry.getValue() == context) { - entryIter.remove(); - } - } + + public static VmwareContext getContext(String vCenterAddress, String vCenterUserName, String vCenterPassword) throws Exception { + VmwareContext context = s_pool.getContext(vCenterAddress, vCenterUserName); + if(context == null) { + context = create(vCenterAddress, vCenterUserName, vCenterPassword); } - + + if(context != null) { + context.setPoolInfo(s_pool, VmwareContextPool.composePoolKey(vCenterAddress, vCenterUserName)); + + context.registerStockObject("username", vCenterUserName); + context.registerStockObject("password", vCenterPassword); + } + + return context; + } + + public static void invalidate(VmwareContext context) { context.close(); } } diff --git a/plugins/hypervisors/vmware/src/com/cloud/storage/resource/VmwareSecondaryStorageResourceHandler.java b/plugins/hypervisors/vmware/src/com/cloud/storage/resource/VmwareSecondaryStorageResourceHandler.java index 5dc70e7ce1a..edfd94acd38 100644 --- a/plugins/hypervisors/vmware/src/com/cloud/storage/resource/VmwareSecondaryStorageResourceHandler.java +++ b/plugins/hypervisors/vmware/src/com/cloud/storage/resource/VmwareSecondaryStorageResourceHandler.java @@ -45,6 +45,7 @@ import com.cloud.hypervisor.vmware.util.VmwareContext; import com.cloud.hypervisor.vmware.util.VmwareHelper; import com.cloud.serializer.GsonHelper; import com.cloud.utils.Pair; +import com.cloud.utils.StringUtils; import com.google.gson.Gson; import com.vmware.vim25.ManagedObjectReference; @@ -57,6 +58,8 @@ public class VmwareSecondaryStorageResourceHandler implements SecondaryStorageRe private final Gson _gson; private final StorageSubsystemCommandHandler storageSubsystemHandler; + + private ThreadLocal currentContext = new ThreadLocal(); /* * private Map _activeHosts = new HashMap(); @@ -73,47 +76,52 @@ public class VmwareSecondaryStorageResourceHandler implements SecondaryStorageRe vmwareStorageSubsystemCommandHandler.setStorageResource(_resource); vmwareStorageSubsystemCommandHandler.setStorageManager(_storageMgr); storageSubsystemHandler = vmwareStorageSubsystemCommandHandler; - } @Override public Answer executeRequest(Command cmd) { - Answer answer; - if (cmd instanceof PrimaryStorageDownloadCommand) { - answer = execute((PrimaryStorageDownloadCommand) cmd); - } else if (cmd instanceof BackupSnapshotCommand) { - answer = execute((BackupSnapshotCommand) cmd); - } else if (cmd instanceof CreatePrivateTemplateFromVolumeCommand) { - answer = execute((CreatePrivateTemplateFromVolumeCommand) cmd); - } else if (cmd instanceof CreatePrivateTemplateFromSnapshotCommand) { - answer = execute((CreatePrivateTemplateFromSnapshotCommand) cmd); - } else if (cmd instanceof CopyVolumeCommand) { - answer = execute((CopyVolumeCommand) cmd); - } else if (cmd instanceof CreateVolumeFromSnapshotCommand) { - answer = execute((CreateVolumeFromSnapshotCommand) cmd); - } else if (cmd instanceof StorageSubSystemCommand) { - answer = storageSubsystemHandler.handleStorageCommands((StorageSubSystemCommand) cmd); - } else if (cmd instanceof CreateEntityDownloadURLCommand) { - answer = execute((CreateEntityDownloadURLCommand)cmd); - } else { - answer = _resource.defaultAction(cmd); - } - - // special handling to pass-back context info for cleanups - if (cmd.getContextParam("execid") != null) { - answer.setContextParam("execid", cmd.getContextParam("execid")); - } - - if (cmd.getContextParam("checkpoint") != null) { - answer.setContextParam("checkpoint", cmd.getContextParam("checkpoint")); - } - - if (cmd.getContextParam("checkpoint2") != null) { - answer.setContextParam("checkpoint2", cmd.getContextParam("checkpoint2")); - } - - return answer; + + try { + Answer answer; + if (cmd instanceof PrimaryStorageDownloadCommand) { + answer = execute((PrimaryStorageDownloadCommand) cmd); + } else if (cmd instanceof BackupSnapshotCommand) { + answer = execute((BackupSnapshotCommand) cmd); + } else if (cmd instanceof CreatePrivateTemplateFromVolumeCommand) { + answer = execute((CreatePrivateTemplateFromVolumeCommand) cmd); + } else if (cmd instanceof CreatePrivateTemplateFromSnapshotCommand) { + answer = execute((CreatePrivateTemplateFromSnapshotCommand) cmd); + } else if (cmd instanceof CopyVolumeCommand) { + answer = execute((CopyVolumeCommand) cmd); + } else if (cmd instanceof CreateVolumeFromSnapshotCommand) { + answer = execute((CreateVolumeFromSnapshotCommand) cmd); + } else if (cmd instanceof StorageSubSystemCommand) { + answer = storageSubsystemHandler.handleStorageCommands((StorageSubSystemCommand) cmd); + } else if (cmd instanceof CreateEntityDownloadURLCommand) { + answer = execute((CreateEntityDownloadURLCommand)cmd); + } else { + answer = _resource.defaultAction(cmd); + } + + // special handling to pass-back context info for cleanups + if (cmd.getContextParam("execid") != null) { + answer.setContextParam("execid", cmd.getContextParam("execid")); + } + + if (cmd.getContextParam("checkpoint") != null) { + answer.setContextParam("checkpoint", cmd.getContextParam("checkpoint")); + } + + if (cmd.getContextParam("checkpoint2") != null) { + answer.setContextParam("checkpoint2", cmd.getContextParam("checkpoint2")); + } + + return answer; + } finally { + recycleServiceContext(); + } } + protected Answer execute(CreateEntityDownloadURLCommand cmd) { boolean result = _storageMgr.execute(this, cmd); return _resource.defaultAction(cmd); @@ -199,30 +207,38 @@ public class VmwareSecondaryStorageResourceHandler implements SecondaryStorageRe try { _resource.ensureOutgoingRuleForAddress(vCenterAddress); - VmwareContext context = null; - - // cached VmwareContext may be timed out in vCenter, give it a - // chance to reclaim a new context from factory - for (int i = 0; i < 2; i++) { - context = VmwareSecondaryStorageContextFactory.create(vCenterAddress, username, password); - if (!validateContext(context, cmd)) { - invalidateServiceContext(context); - } - } - + + VmwareContext context = currentContext.get(); + if(context == null) { + s_logger.info("Open new VmwareContext. vCenter: " + vCenterAddress + ", user: " + username + + ", password: " + StringUtils.getMaskedPasswordForDisplay(password)); + context = VmwareSecondaryStorageContextFactory.getContext(vCenterAddress, username, password); + } + if (context != null) { context.registerStockObject("serviceconsole", cmd.getContextParam("serviceconsole")); context.registerStockObject("manageportgroup", cmd.getContextParam("manageportgroup")); } + currentContext.set(context); return context; } catch (Exception e) { s_logger.error("Unexpected exception " + e.toString(), e); return null; } } + + public void recycleServiceContext() { + if(currentContext.get() != null) { + VmwareContext context = currentContext.get(); + currentContext.set(null); + assert(context.getPool() != null); + context.getPool().returnContext(context); + } + } @Override public void invalidateServiceContext(VmwareContext context) { + currentContext.set(null); VmwareSecondaryStorageContextFactory.invalidate(context); } diff --git a/vmware-base/src/com/cloud/hypervisor/vmware/mo/HostMO.java b/vmware-base/src/com/cloud/hypervisor/vmware/mo/HostMO.java index b5c82ce83f5..1cc0e79c2f1 100755 --- a/vmware-base/src/com/cloud/hypervisor/vmware/mo/HostMO.java +++ b/vmware-base/src/com/cloud/hypervisor/vmware/mo/HostMO.java @@ -39,6 +39,8 @@ import com.vmware.vim25.DatastoreSummary; import com.vmware.vim25.DynamicProperty; import com.vmware.vim25.HostConfigManager; import com.vmware.vim25.HostConnectInfo; +import com.vmware.vim25.HostFirewallInfo; +import com.vmware.vim25.HostFirewallRuleset; import com.vmware.vim25.HostHardwareSummary; import com.vmware.vim25.HostHyperThreadScheduleInfo; import com.vmware.vim25.HostIpRouteEntry; @@ -1030,5 +1032,26 @@ public class HostMO extends BaseMO implements VmwareHypervisorHost { return new LicenseAssignmentManagerMO(_context, licenseAssignmentManager); } + + public void enableVncOnHostFirewall() throws Exception { + HostFirewallSystemMO firewallMo = getHostFirewallSystemMO(); + boolean bRefresh = false; + if(firewallMo != null) { + HostFirewallInfo firewallInfo = firewallMo.getFirewallInfo(); + if(firewallInfo != null && firewallInfo.getRuleset() != null) { + for(HostFirewallRuleset rule : firewallInfo.getRuleset()) { + if("vncServer".equalsIgnoreCase(rule.getKey())) { + bRefresh = true; + firewallMo.enableRuleset("vncServer"); + } else if("gdbserver".equalsIgnoreCase(rule.getKey())) { + bRefresh = true; + firewallMo.enableRuleset("gdbserver"); + } + } + } + if(bRefresh) + firewallMo.refreshFirewall(); + } + } } diff --git a/vmware-base/src/com/cloud/hypervisor/vmware/util/VmwareContext.java b/vmware-base/src/com/cloud/hypervisor/vmware/util/VmwareContext.java index 265fa647d21..95553fdc9cc 100755 --- a/vmware-base/src/com/cloud/hypervisor/vmware/util/VmwareContext.java +++ b/vmware-base/src/com/cloud/hypervisor/vmware/util/VmwareContext.java @@ -37,7 +37,6 @@ import java.util.Map; import javax.net.ssl.HostnameVerifier; import javax.net.ssl.HttpsURLConnection; import javax.net.ssl.SSLSession; -import javax.xml.ws.BindingProvider; import org.apache.log4j.Logger; @@ -59,12 +58,16 @@ public class VmwareContext { private static int MAX_CONNECT_RETRY = 5; private static int CONNECT_RETRY_INTERVAL = 1000; + + private int _CHUNKSIZE = 1*1024*1024; // 1M private VmwareClient _vimClient; private String _serverAddress; private Map _stockMap = new HashMap(); - private int _CHUNKSIZE = 1*1024*1024; // 1M + + private VmwareContextPool _pool; + private String _poolKey; static { try { @@ -97,6 +100,12 @@ public class VmwareContext { _stockMap.remove(name); } } + + public void clearStockObjects() { + synchronized(_stockMap) { + _stockMap.clear(); + } + } @SuppressWarnings("unchecked") public T getStockObject(String name) { @@ -109,12 +118,6 @@ public class VmwareContext { return _serverAddress; } - /* - public ServiceConnection getServiceConnection() { - return _vimClient.getServiceConnection3(); - } - */ - public VimPortType getService() { return _vimClient.getService(); } @@ -123,12 +126,6 @@ public class VmwareContext { return _vimClient.getServiceContent(); } - /* - public ServiceUtil getServiceUtil() { - return _vimClient.getServiceUtil3(); - } - */ - public ManagedObjectReference getPropertyCollector(){ return _vimClient.getPropCol(); } @@ -140,7 +137,23 @@ public class VmwareContext { public VmwareClient getVimClient(){ return _vimClient; } - + + public void setPoolInfo(VmwareContextPool pool, String poolKey) { + _pool = pool; + _poolKey = poolKey; + } + + public VmwareContextPool getPool() { + return _pool; + } + + public String getPoolKey() { + return _poolKey; + } + + public void idleCheck() throws Exception { + getRootFolder(); + } public ManagedObjectReference getHostMorByPath(String inventoryPath) throws Exception { assert(inventoryPath != null); @@ -595,6 +608,7 @@ public class VmwareContext { } public void close() { + clearStockObjects(); try { _vimClient.disconnect(); } catch(Exception e) { diff --git a/vmware-base/src/com/cloud/hypervisor/vmware/util/VmwareContextPool.java b/vmware-base/src/com/cloud/hypervisor/vmware/util/VmwareContextPool.java new file mode 100644 index 00000000000..3bac0284353 --- /dev/null +++ b/vmware-base/src/com/cloud/hypervisor/vmware/util/VmwareContextPool.java @@ -0,0 +1,148 @@ +// 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; + +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 Map> _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>(); + + _maxIdleQueueLength = maxIdleQueueLength; + _idleCheckIntervalMs = idleCheckIntervalMs; + + _timer.scheduleAtFixedRate(getTimerTask(), _idleCheckIntervalMs, _idleCheckIntervalMs); + } + + public VmwareContext getContext(String vCenterAddress, String vCenterUserName) { + String poolKey = composePoolKey(vCenterAddress, vCenterUserName); + synchronized(_pool) { + List l = _pool.get(poolKey); + if(l == null) + return null; + + if(l.size() > 0) { + if(s_logger.isTraceEnabled()) + s_logger.trace("Return a VmwareContext from the pool."); + + VmwareContext context = l.remove(0); + context.setPoolInfo(this, poolKey); + return context; + } + + if(s_logger.isInfoEnabled()) + s_logger.info("No VmwareContext is available from the idle pool, create a new one"); + return null; + } + } + + public void returnContext(VmwareContext context) { + assert(context.getPool() == this); + assert(context.getPoolKey() != null); + synchronized(_pool) { + List l = _pool.get(context.getPoolKey()); + if(l == null) { + l = new ArrayList(); + _pool.put(context.getPoolKey(), l); + } + + if(l.size() < _maxIdleQueueLength) { + context.clearStockObjects(); + l.add(context); + } else { + if(s_logger.isInfoEnabled()) + s_logger.info("VmwareContextPool queue exceeds limits, queue size: " + l.size()); + context.close(); + } + } + } + + private void getIdleCheckContexts(List l, int batchSize) { + synchronized(_pool) { + for(List entryList : _pool.values()) { + if(entryList != null) { + int count = 0; + while(entryList.size() > 0 && count < batchSize) { + l.add(entryList.remove(0)); + count++; + } + } + } + } + } + + private TimerTask getTimerTask() { + return new TimerTask() { + @Override + public void run() { + try { + doIdleCheck(); + } catch (Throwable e) { + s_logger.error("Unexpected exception", e); + } + } + }; + } + + private void doIdleCheck() { + List l = new ArrayList(); + int batchSize = (int)(_idleCheckIntervalMs / 1000); // calculate batch size at 1 request/sec rate + getIdleCheckContexts(l, batchSize); + + for(VmwareContext context : l) { + try { + context.idleCheck(); + returnContext(context); + } 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; + } +}