Bug 10197:

implement pool-wise VM sync,
    For XenServer, VM fullSync is pool-wise now, VM deltaSync is still per host
This commit is contained in:
anthony 2011-08-02 16:47:04 -07:00
parent 5f9884d97a
commit dc7ff2b5ad
9 changed files with 290 additions and 74 deletions

View File

@ -69,6 +69,7 @@ import com.cloud.agent.api.StartAnswer;
import com.cloud.agent.api.StartCommand;
import com.cloud.agent.api.StartupCommand;
import com.cloud.agent.api.StartupRoutingCommand;
import com.cloud.agent.api.StartupRoutingCommand.VmState;
import com.cloud.agent.api.StartupStorageCommand;
import com.cloud.agent.api.StopAnswer;
import com.cloud.agent.api.StopCommand;
@ -127,7 +128,7 @@ public class FakeComputingResource extends ServerResourceBase implements ServerR
@Override
public StartupCommand[] initialize() {
Map<String, State> changes = null;
Map<String, VmState> changes = null;
final List<Object> info = getHostInfo();

View File

@ -2505,8 +2505,9 @@ public class LibvirtComputingResource extends ServerResourceBase implements Serv
}
final List<Object> info = getHostInfo();
final StartupRoutingCommand cmd = new StartupRoutingCommand((Integer)info.get(0), (Long)info.get(1), (Long)info.get(2), (Long)info.get(4), (String)info.get(3), HypervisorType.KVM, RouterPrivateIpStrategy.HostLocal, changes);
final StartupRoutingCommand cmd = new StartupRoutingCommand((Integer)info.get(0), (Long)info.get(1), (Long)info.get(2), (Long)info.get(4), (String)info.get(3), HypervisorType.KVM, RouterPrivateIpStrategy.HostLocal);
cmd.setStateChanges(changes);
fillNetworkInformation(cmd);
cmd.getHostDetails().putAll(getVersionStrings());
cmd.setPool(_pool);

View File

@ -26,11 +26,26 @@ import com.cloud.network.Networks.RouterPrivateIpStrategy;
import com.cloud.vm.VirtualMachine.State;
public class StartupRoutingCommand extends StartupCommand {
public class VmState {
State state;
String host;
public VmState(State state, String host) {
this.state = state;
this.host = host;
}
public State getState() {
return state;
}
public String getHost() {
return host;
}
}
int cpus;
long speed;
long memory;
long dom0MinMemory;
Map<String, State> vms;
boolean poolSync;
Map<String, VmState> vms;
String caps;
String pool;
HypervisorType hypervisorType;
@ -50,20 +65,30 @@ public class StartupRoutingCommand extends StartupCommand {
String caps,
HypervisorType hypervisorType,
RouterPrivateIpStrategy privIpStrategy,
Map<String, State> vms) {
Map<String, VmState> vms) {
this(cpus, speed, memory, dom0MinMemory, caps, hypervisorType, vms);
getHostDetails().put(RouterPrivateIpStrategy.class.getCanonicalName(), privIpStrategy.toString());
}
public StartupRoutingCommand(int cpus,
long speed,
long memory,
long dom0MinMemory,
String caps,
HypervisorType hypervisorType,
RouterPrivateIpStrategy privIpStrategy) {
this(cpus, speed, memory, dom0MinMemory, caps, hypervisorType, new HashMap<String,String>(), new HashMap<String, VmState>());
getHostDetails().put(RouterPrivateIpStrategy.class.getCanonicalName(), privIpStrategy.toString());
}
public StartupRoutingCommand(int cpus,
long speed,
long memory,
long dom0MinMemory,
final String caps,
final HypervisorType hypervisorType,
final HypervisorType hypervisorType,
final Map<String, String> hostDetails,
Map<String, State> vms) {
Map<String, VmState> vms) {
super(Host.Type.Routing);
this.cpus = cpus;
this.speed = speed;
@ -73,17 +98,27 @@ public class StartupRoutingCommand extends StartupCommand {
this.hypervisorType = hypervisorType;
this.hostDetails = hostDetails;
this.caps = caps;
this.poolSync = false;
}
public StartupRoutingCommand(int cpus2, long speed2, long memory2,
long dom0MinMemory2, String caps2, HypervisorType hypervisorType2,
Map<String, State> vms2) {
Map<String, VmState> vms2) {
this(cpus2, speed2, memory2, dom0MinMemory2, caps2, hypervisorType2, new HashMap<String,String>(), vms2);
}
public void setChanges(Map<String, State> vms) {
public void setChanges(Map<String, VmState> vms) {
this.vms = vms;
}
public void setStateChanges(Map<String, State> vms) {
for( String vm_name : vms.keySet() ) {
if( this.vms == null ) {
this.vms = new HashMap<String, VmState>();
}
this.vms.put(vm_name, new VmState(vms.get(vm_name), null));
}
}
public int getCpus() {
return cpus;
@ -105,7 +140,7 @@ public class StartupRoutingCommand extends StartupCommand {
return dom0MinMemory;
}
public Map<String, State> getVmStates() {
public Map<String, VmState> getVmStates() {
return vms;
}
@ -137,7 +172,15 @@ public class StartupRoutingCommand extends StartupCommand {
this.pool = pool;
}
public HypervisorType getHypervisorType() {
public boolean isPoolSync() {
return poolSync;
}
public void setPoolSync(boolean poolSync) {
this.poolSync = poolSync;
}
public HypervisorType getHypervisorType() {
return hypervisorType;
}

View File

@ -28,6 +28,7 @@ import com.cloud.agent.api.Command;
import com.cloud.agent.api.PingCommand;
import com.cloud.agent.api.StartupCommand;
import com.cloud.agent.api.StartupRoutingCommand;
import com.cloud.agent.api.StartupRoutingCommand.VmState;
import com.cloud.host.Host.Type;
import com.cloud.hypervisor.Hypervisor;
import com.cloud.resource.ServerResource;
@ -48,7 +49,7 @@ public class KvmDummyResourceBase extends ServerResourceBase implements ServerRe
@Override
public StartupCommand[] initialize() {
StartupRoutingCommand cmd = new StartupRoutingCommand(0, 0, 0, 0, null, Hypervisor.HypervisorType.KVM, new HashMap<String, String>(), new HashMap<String, State>());
StartupRoutingCommand cmd = new StartupRoutingCommand(0, 0, 0, 0, null, Hypervisor.HypervisorType.KVM, new HashMap<String, String>(), new HashMap<String, VmState>());
cmd.setDataCenter(_zoneId);
cmd.setPod(_podId);
cmd.setCluster(_clusterId);

View File

@ -120,6 +120,7 @@ import com.cloud.agent.api.StartAnswer;
import com.cloud.agent.api.StartCommand;
import com.cloud.agent.api.StartupCommand;
import com.cloud.agent.api.StartupRoutingCommand;
import com.cloud.agent.api.StartupRoutingCommand.VmState;
import com.cloud.agent.api.StartupStorageCommand;
import com.cloud.agent.api.StopAnswer;
import com.cloud.agent.api.StopCommand;
@ -2411,7 +2412,7 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe
throw new CloudRuntimeException("Com'on no control domain? What the crap?!#@!##$@");
}
protected HashMap<String, State> sync(Connection conn) {
protected HashMap<String, State> deltaSync(Connection conn) {
HashMap<String, State> newStates;
HashMap<String, State> oldStates = null;
@ -2505,6 +2506,46 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe
return changes;
}
protected void fullSync(StartupRoutingCommand cmd, Connection conn) {
synchronized (_vms) {
_vms.clear();
}
try {
final HashMap<String, VmState> vmStates = new HashMap<String, VmState>();
Map<VM, VM.Record> vmRs = VM.getAllRecords(conn);
for (VM.Record record : vmRs.values()) {
if (record.isControlDomain || record.isASnapshot || record.isATemplate) {
continue; // Skip DOM0
}
String vm_name = record.nameLabel;
VmPowerState ps = record.powerState;
final State state = convertToState(ps);
Host host = record.residentOn;
String host_uuid = null;
if( host != null ) {
host_uuid = host.getUuid(conn);
if( host_uuid.equals(_host.uuid)) {
synchronized (_vms) {
_vms.put(vm_name, state);
}
}
}
if (s_logger.isTraceEnabled()) {
s_logger.trace("VM " + vm_name + ": powerstate = " + ps + "; vm state=" + state.toString());
}
VmState vm_state = cmd.new VmState(state, host_uuid);
vmStates.put(vm_name, vm_state);
}
cmd.setChanges(vmStates);
} catch (final Throwable e) {
String msg = "Unable to get vms through host " + _host.uuid + " due to to " + e.toString();
s_logger.warn(msg, e);
throw new CloudRuntimeException(msg);
}
}
protected ReadyAnswer execute(ReadyCommand cmd) {
Connection conn = getConnection();
Long dcId = cmd.getDataCenterId();
@ -3625,7 +3666,7 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe
return null;
}
}
HashMap<String, State> newStates = sync(conn);
HashMap<String, State> newStates = deltaSync(conn);
if (newStates == null) {
s_logger.warn("Unable to get current status from sync");
return null;
@ -3862,25 +3903,18 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe
s_logger.warn("Unable to get host information for " + _host.ip);
return null;
}
StartupRoutingCommand cmd = new StartupRoutingCommand();
fillHostInfo(conn, cmd);
Map<String, State> changes = null;
synchronized (_vms) {
_vms.clear();
changes = sync(conn);
}
fullSync(cmd, conn);
cmd.setHypervisorType(HypervisorType.XenServer);
cmd.setChanges(changes);
cmd.setCluster(_cluster);
cmd.setPoolSync(true);
StartupStorageCommand sscmd = initializeLocalSR(conn);
if (sscmd != null) {
return new StartupCommand[] { cmd, sscmd };
}
return new StartupCommand[] { cmd };
}

View File

@ -54,6 +54,7 @@ import com.cloud.agent.api.StartAnswer;
import com.cloud.agent.api.StartCommand;
import com.cloud.agent.api.StartupCommand;
import com.cloud.agent.api.StartupRoutingCommand;
import com.cloud.agent.api.StartupRoutingCommand.VmState;
import com.cloud.agent.api.StopAnswer;
import com.cloud.agent.api.StopCommand;
import com.cloud.agent.api.to.VirtualMachineTO;
@ -1439,7 +1440,7 @@ public class VirtualMachineManagerImpl implements VirtualMachineManager, Listene
}
public Commands deltaSync(long hostId, Map<String, State> newStates) {
Map<Long, AgentVmInfo> states = convertToInfos(newStates);
Map<Long, AgentVmInfo> states = convertDeltaToInfos(newStates);
Commands commands = new Commands(OnError.Continue);
for (Map.Entry<Long, AgentVmInfo> entry : states.entrySet()) {
@ -1466,7 +1467,8 @@ public class VirtualMachineManagerImpl implements VirtualMachineManager, Listene
return commands;
}
protected Map<Long, AgentVmInfo> convertToInfos(final Map<String, State> states) {
protected Map<Long, AgentVmInfo> convertDeltaToInfos(final Map<String, State> states) {
final HashMap<Long, AgentVmInfo> map = new HashMap<Long, AgentVmInfo>();
if (states == null) {
@ -1488,7 +1490,38 @@ public class VirtualMachineManagerImpl implements VirtualMachineManager, Listene
Long id = vmGuru.convertToId(name);
if (id != null) {
map.put(id, new AgentVmInfo(entry.getKey(), vmGuru, null, entry.getValue()));
map.put(id, new AgentVmInfo(entry.getKey(), vmGuru, null,entry.getValue()));
break;
}
}
}
return map;
}
protected Map<Long, AgentVmInfo> convertToInfos(final Map<String, VmState> states) {
final HashMap<Long, AgentVmInfo> map = new HashMap<Long, AgentVmInfo>();
if (states == null) {
return map;
}
Collection<VirtualMachineGuru<? extends VMInstanceVO>> vmGurus = _vmGurus.values();
for (Map.Entry<String, VmState> entry : states.entrySet()) {
for (VirtualMachineGuru<? extends VMInstanceVO> vmGuru : vmGurus) {
String name = entry.getKey();
VMInstanceVO vm = vmGuru.findByName(name);
if (vm != null) {
map.put(vm.getId(), new AgentVmInfo(entry.getKey(), vmGuru, vm, entry.getValue().getState(), entry.getValue().getHost() ));
break;
}
Long id = vmGuru.convertToId(name);
if (id != null) {
map.put(id, new AgentVmInfo(entry.getKey(), vmGuru, null,entry.getValue().getState(), entry.getValue().getHost() ));
break;
}
}
@ -1667,57 +1700,92 @@ public class VirtualMachineManagerImpl implements VirtualMachineManager, Listene
}
}
public Commands fullSync(final long hostId, final Map<String, State> newStates) {
public Commands fullSync(final long hostId, StartupRoutingCommand startup) {
Commands commands = new Commands(OnError.Continue);
final List<? extends VMInstanceVO> vms = _vmDao.listByHostId(hostId);
s_logger.debug("Found " + vms.size() + " VMs for host " + hostId);
Map<Long, AgentVmInfo> infos = convertToInfos(newStates);
for (VMInstanceVO vm : vms) {
AgentVmInfo info = infos.remove(vm.getId());
VMInstanceVO castedVm = null;
if (info == null) {
info = new AgentVmInfo(vm.getInstanceName(), getVmGuru(vm), vm, State.Stopped);
castedVm = info.guru.findById(vm.getId());
} else {
castedVm = info.vm;
}
HypervisorGuru hvGuru = _hvGuruMgr.getGuru(castedVm.getHypervisorType());
Command command = compareState(hostId, castedVm, info, true, hvGuru.trackVmHostChange());
if (command != null) {
commands.addCommand(command);
}
}
for (final AgentVmInfo left : infos.values()) {
boolean found = false;
for (VirtualMachineGuru<? extends VMInstanceVO> vmGuru : _vmGurus.values()) {
VMInstanceVO vm = vmGuru.findByName(left.name);
if (vm != null) {
found = true;
HypervisorGuru hvGuru = _hvGuruMgr.getGuru(vm.getHypervisorType());
if(hvGuru.trackVmHostChange()) {
Command command = compareState(hostId, vm, left, true, true);
if (command != null) {
commands.addCommand(command);
}
} else {
s_logger.warn("Stopping a VM, VM " + left.name + " migrate from Host " + vm.getHostId() + " to Host " + hostId );
commands.addCommand(cleanup(left.name));
Map<Long, AgentVmInfo> infos = convertToInfos(startup.getVmStates());
if( startup.isPoolSync()) {
long hId = 0;
Host host = _hostDao.findById(hostId);
long clusterId= host.getClusterId();
final List<? extends VMInstanceVO> vms = _vmDao.listByClusterId(clusterId);
s_logger.debug("Found " + vms.size() + " VMs for cluster " + clusterId);
for (VMInstanceVO vm : vms) {
AgentVmInfo info = infos.remove(vm.getId());
VMInstanceVO castedVm = null;
if (info == null) {
info = new AgentVmInfo(vm.getInstanceName(), getVmGuru(vm), vm, State.Stopped);
hId = 0;
castedVm = info.guru.findById(vm.getId());
} else {
castedVm = info.vm;
String host_guid = info.getHost();
host = _hostDao.findByGuid(host_guid);
if ( host == null ) {
infos.put(vm.getId(), info);
continue;
}
break;
hId = host.getId();
}
HypervisorGuru hvGuru = _hvGuruMgr.getGuru(castedVm.getHypervisorType());
Command command = compareState(hId, castedVm, info, true, hvGuru.trackVmHostChange());
if (command != null) {
commands.addCommand(command);
}
}
if ( ! found ) {
for (final AgentVmInfo left : infos.values()) {
s_logger.warn("Stopping a VM that we have no record of: " + left.name);
commands.addCommand(cleanup(left.name));
}
} else {
final List<? extends VMInstanceVO> vms = _vmDao.listByHostId(hostId);
s_logger.debug("Found " + vms.size() + " VMs for host " + hostId);
for (VMInstanceVO vm : vms) {
AgentVmInfo info = infos.remove(vm.getId());
VMInstanceVO castedVm = null;
if (info == null) {
info = new AgentVmInfo(vm.getInstanceName(), getVmGuru(vm), vm, State.Stopped);
castedVm = info.guru.findById(vm.getId());
} else {
castedVm = info.vm;
}
HypervisorGuru hvGuru = _hvGuruMgr.getGuru(castedVm.getHypervisorType());
Command command = compareState(hostId, castedVm, info, true, hvGuru.trackVmHostChange());
if (command != null) {
commands.addCommand(command);
}
}
for (final AgentVmInfo left : infos.values()) {
boolean found = false;
for (VirtualMachineGuru<? extends VMInstanceVO> vmGuru : _vmGurus.values()) {
VMInstanceVO vm = vmGuru.findByName(left.name);
if (vm != null) {
found = true;
HypervisorGuru hvGuru = _hvGuruMgr.getGuru(vm.getHypervisorType());
if(hvGuru.trackVmHostChange()) {
Command command = compareState(hostId, vm, left, true, true);
if (command != null) {
commands.addCommand(command);
}
} else {
s_logger.warn("Stopping a VM, VM " + left.name + " migrate from Host " + vm.getHostId() + " to Host " + hostId );
commands.addCommand(cleanup(left.name));
}
break;
}
}
if ( ! found ) {
s_logger.warn("Stopping a VM that we have no record of: " + left.name);
commands.addCommand(cleanup(left.name));
}
}
}
return commands;
}
@ -1797,7 +1865,7 @@ public class VirtualMachineManagerImpl implements VirtualMachineManager, Listene
StartupRoutingCommand startup = (StartupRoutingCommand) cmd;
Commands commands = fullSync(agentId, startup.getVmStates());
Commands commands = fullSync(agentId, startup);
if (commands.size() > 0) {
s_logger.debug("Sending clean commands to the agent");
@ -1860,15 +1928,25 @@ public class VirtualMachineManagerImpl implements VirtualMachineManager, Listene
protected class AgentVmInfo {
public String name;
public State state;
public String host;
public VMInstanceVO vm;
public VirtualMachineGuru<VMInstanceVO> guru;
@SuppressWarnings("unchecked")
public AgentVmInfo(String name, VirtualMachineGuru<? extends VMInstanceVO> guru, VMInstanceVO vm, State state) {
public AgentVmInfo(String name, VirtualMachineGuru<? extends VMInstanceVO> guru, VMInstanceVO vm, State state, String host) {
this.name = name;
this.state = state;
this.vm = vm;
this.guru = (VirtualMachineGuru<VMInstanceVO>) guru;
this.host = host;
}
public AgentVmInfo(String name, VirtualMachineGuru<? extends VMInstanceVO> guru, VMInstanceVO vm, State state) {
this(name, guru, vm, state, null);
}
public String getHost() {
return host;
}
}

View File

@ -79,5 +79,7 @@ public interface VMInstanceDao extends GenericDao<VMInstanceVO, Long>, StateDao<
List<VMInstanceVO> listByTypeAndState(State state, VirtualMachine.Type type);
List<VMInstanceVO> listByAccountId(long accountId);
public Long countAllocatedVirtualRoutersForAccount(long accountId);
public Long countAllocatedVirtualRoutersForAccount(long accountId);
List<VMInstanceVO> listByClusterId(long clusterId);
}

View File

@ -26,11 +26,18 @@ import javax.ejb.Local;
import org.apache.log4j.Logger;
import com.cloud.cluster.agentlb.HostTransferMapVO;
import com.cloud.cluster.agentlb.dao.HostTransferMapDaoImpl;
import com.cloud.host.HostVO;
import com.cloud.host.dao.HostDaoImpl;
import com.cloud.org.Managed;
import com.cloud.utils.component.ComponentLocator;
import com.cloud.utils.db.Attribute;
import com.cloud.utils.db.GenericDaoBase;
import com.cloud.utils.db.GenericSearchBuilder;
import com.cloud.utils.db.SearchBuilder;
import com.cloud.utils.db.SearchCriteria;
import com.cloud.utils.db.JoinBuilder.JoinType;
import com.cloud.utils.db.SearchCriteria.Func;
import com.cloud.utils.db.SearchCriteria.Op;
import com.cloud.utils.db.UpdateBuilder;
@ -45,6 +52,7 @@ public class VMInstanceDaoImpl extends GenericDaoBase<VMInstanceVO, Long> implem
public static final Logger s_logger = Logger.getLogger(VMInstanceDaoImpl.class);
protected final SearchBuilder<VMInstanceVO> VMClusterSearch;
protected final SearchBuilder<VMInstanceVO> IdStatesSearch;
protected final SearchBuilder<VMInstanceVO> AllFieldsSearch;
protected final SearchBuilder<VMInstanceVO> ZoneTemplateNonExpungedSearch;
@ -60,11 +68,18 @@ public class VMInstanceDaoImpl extends GenericDaoBase<VMInstanceVO, Long> implem
protected final Attribute _updateTimeAttr;
protected final HostDaoImpl _hostDao = ComponentLocator.inject(HostDaoImpl.class);
protected VMInstanceDaoImpl() {
IdStatesSearch = createSearchBuilder();
IdStatesSearch.and("id", IdStatesSearch.entity().getId(), Op.EQ);
IdStatesSearch.and("states", IdStatesSearch.entity().getState(), Op.IN);
IdStatesSearch.done();
VMClusterSearch = createSearchBuilder();
SearchBuilder<HostVO> hostSearch = _hostDao.createSearchBuilder();
VMClusterSearch.join("hostSearch", hostSearch, hostSearch.entity().getId(), VMClusterSearch.entity().getHostId(), JoinType.INNER);
hostSearch.and("clusterId", hostSearch.entity().getClusterId(), SearchCriteria.Op.EQ);
VMClusterSearch.done();
AllFieldsSearch = createSearchBuilder();
AllFieldsSearch.and("host", AllFieldsSearch.entity().getHostId(), Op.EQ);
@ -162,6 +177,14 @@ public class VMInstanceDaoImpl extends GenericDaoBase<VMInstanceVO, Long> implem
return listBy(sc);
}
@Override
public List<VMInstanceVO> listByClusterId(long clusterId) {
SearchCriteria<VMInstanceVO> sc = VMClusterSearch.create();
sc.setJoinParameters("hostSearch", "clusterId", clusterId);
return listBy(sc);
}
@Override
public List<VMInstanceVO> listByZoneIdAndType(long zoneId, VirtualMachine.Type type) {

View File

@ -0,0 +1,33 @@
/**
* Copyright (C) 2010 Cloud.com, Inc. All rights reserved.
*
* This software is licensed under the GNU General Public License v3 or later.
*
* It is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
package com.cloud.utils.exception;
import com.cloud.utils.SerialVersionUID;
public class HypervisorVersionChangedException extends RuntimeException {
private static final long serialVersionUID = SerialVersionUID.CloudRuntimeException;
public HypervisorVersionChangedException(String message) {
super(message);
}
protected HypervisorVersionChangedException() {
super();
}
}