fixed locking transient bug

This commit is contained in:
David Ribeiro Alves 2012-03-22 17:49:04 +00:00
parent 28bd62edfc
commit 1f31e96a9f
7 changed files with 39 additions and 29 deletions

View File

@ -158,7 +158,7 @@ public class VirtualBoxComputeServiceContextModule extends
bind(new TypeLiteral<Function<IMachine, SshClient>>() { bind(new TypeLiteral<Function<IMachine, SshClient>>() {
}).to(IMachineToSshClient.class); }).to(IMachineToSshClient.class);
bind(ExecutionType.class).toInstance(ExecutionType.GUI); bind(ExecutionType.class).toInstance(ExecutionType.HEADLESS);
bind(LockType.class).toInstance(LockType.Write); bind(LockType.class).toInstance(LockType.Write);
} }

View File

@ -147,7 +147,7 @@ public class CreateAndInstallVm implements Function<MasterSpec, IMachine> {
.split(installationKeySequence), new StringToKeyCode()); .split(installationKeySequence), new StringToKeyCode());
for (List<Integer> scancodes : scancodelist) { for (List<Integer> scancodes : scancodelist) {
machineUtils.readLockMachineAndApplyToSession(vmName,new SendScancodes(scancodes)); machineUtils.sharedLockMachineAndApplyToSession(vmName,new SendScancodes(scancodes));
} }
} }

View File

@ -46,6 +46,7 @@ import org.jclouds.virtualbox.domain.NodeSpec;
import org.jclouds.virtualbox.domain.VmSpec; import org.jclouds.virtualbox.domain.VmSpec;
import org.jclouds.virtualbox.statements.DeleteGShadowLock; import org.jclouds.virtualbox.statements.DeleteGShadowLock;
import org.jclouds.virtualbox.statements.SetIpAddress; import org.jclouds.virtualbox.statements.SetIpAddress;
import org.jclouds.virtualbox.util.MachineController;
import org.jclouds.virtualbox.util.MachineUtils; import org.jclouds.virtualbox.util.MachineUtils;
import org.virtualbox_4_1.CleanupMode; import org.virtualbox_4_1.CleanupMode;
import org.virtualbox_4_1.IMachine; import org.virtualbox_4_1.IMachine;
@ -83,23 +84,22 @@ public class NodeCreator implements Function<NodeSpec, NodeAndInitialCredentials
// TODO parameterize // TODO parameterize
public static final boolean USE_LINKED = true; public static final boolean USE_LINKED = true;
// TODO parameterize
public static final ExecutionType EXECUTION_TYPE = ExecutionType.HEADLESS;
private final Supplier<VirtualBoxManager> manager; private final Supplier<VirtualBoxManager> manager;
private final Function<CloneSpec, IMachine> cloner; private final Function<CloneSpec, IMachine> cloner;
private final AtomicInteger nodePorts; private final AtomicInteger nodePorts;
private final AtomicInteger nodeIps; private final AtomicInteger nodeIps;
private MachineUtils machineUtils; private final MachineUtils machineUtils;
private final MachineController machineController;
@Inject @Inject
public NodeCreator(Supplier<VirtualBoxManager> manager, Function<CloneSpec, IMachine> cloner, public NodeCreator(Supplier<VirtualBoxManager> manager, Function<CloneSpec, IMachine> cloner,
MachineUtils machineUtils, RunScriptOnNode.Factory scriptRunnerFactory) { MachineUtils machineUtils, RunScriptOnNode.Factory scriptRunnerFactory, MachineController machineController) {
this.manager = manager; this.manager = manager;
this.cloner = cloner; this.cloner = cloner;
this.nodePorts = new AtomicInteger(NODE_PORT_INIT); this.nodePorts = new AtomicInteger(NODE_PORT_INIT);
this.nodeIps = new AtomicInteger(2); this.nodeIps = new AtomicInteger(2);
this.machineUtils = machineUtils; this.machineUtils = machineUtils;
this.machineController = machineController;
} }
@Override @Override
@ -147,7 +147,7 @@ public class NodeCreator implements Function<NodeSpec, NodeAndInitialCredentials
IMachine cloned = cloner.apply(cloneSpec); IMachine cloned = cloner.apply(cloneSpec);
new LaunchMachineIfNotAlreadyRunning(manager.get(), EXECUTION_TYPE, "").apply(cloned); machineController.ensureMachineIsLaunched(cloneVmSpec.getVmName());
// IMachineToNodeMetadata produces the final ip's but these need to be set before so we build a // IMachineToNodeMetadata produces the final ip's but these need to be set before so we build a
// NodeMetadata just for the sake of running the gshadow and setip scripts // NodeMetadata just for the sake of running the gshadow and setip scripts

View File

@ -67,7 +67,7 @@ public class MachineController {
public void ensureMachineHasPowerDown(String vmName) { public void ensureMachineHasPowerDown(String vmName) {
while (!manager.get().getVBox().findMachine(vmName).getState().equals(MachineState.POWERED_OFF)) { while (!manager.get().getVBox().findMachine(vmName).getState().equals(MachineState.POWERED_OFF)) {
try { try {
machineUtils.writeLockMachineAndApplyToSession(vmName, new Function<ISession, Void>() { machineUtils.sharedLockMachineAndApplyToSession(vmName, new Function<ISession, Void>() {
@Override @Override
public Void apply(ISession session) { public Void apply(ISession session) {
IProgress powerDownProgress = session.getConsole().powerDown(); IProgress powerDownProgress = session.getConsole().powerDown();

View File

@ -57,15 +57,12 @@ public class MachineUtils {
private final Supplier<VirtualBoxManager> manager; private final Supplier<VirtualBoxManager> manager;
private final Factory scriptRunner; private final Factory scriptRunner;
private final Supplier<NodeMetadata> host;
@Inject @Inject
public MachineUtils(Supplier<VirtualBoxManager> manager, RunScriptOnNode.Factory scriptRunner, public MachineUtils(Supplier<VirtualBoxManager> manager, RunScriptOnNode.Factory scriptRunner) {
Supplier<NodeMetadata> host) {
super(); super();
this.manager = manager; this.manager = manager;
this.scriptRunner = scriptRunner; this.scriptRunner = scriptRunner;
this.host = host;
} }
public ListenableFuture<ExecResponse> runScriptOnNode(NodeMetadata metadata, Statement statement, public ListenableFuture<ExecResponse> runScriptOnNode(NodeMetadata metadata, Statement statement,
@ -100,10 +97,11 @@ public class MachineUtils {
}); });
} }
/** /**
* Locks the machine and executes the given function using the machine matching the given id. * Locks the machine and executes the given function using the machine matching the given id. The
* The machine is write locked and modifications to the session that reflect on the machine can be done safely. * machine is write locked and modifications to the session that reflect on the machine can be
* done safely.
* <p/> * <p/>
* Unlocks the machine before returning. * Unlocks the machine before returning.
* *
@ -116,10 +114,11 @@ public class MachineUtils {
public <T> T writeLockMachineAndApplyToSession(final String machineId, final Function<ISession, T> function) { public <T> T writeLockMachineAndApplyToSession(final String machineId, final Function<ISession, T> function) {
return lockSessionOnMachineAndApply(machineId, LockType.Write, function); return lockSessionOnMachineAndApply(machineId, LockType.Write, function);
} }
/** /**
* Locks the machine and executes the given function using the machine matching the given id. * Locks the machine and executes the given function using the machine matching the given id. The
* The machine is read locked, which means that settings can be read safely (but not changed) by function. * machine is read locked, which means that settings can be read safely (but not changed) by
* function.
* <p/> * <p/>
* Unlocks the machine before returning. * Unlocks the machine before returning.
* *
@ -129,7 +128,7 @@ public class MachineUtils {
* the function to execute * the function to execute
* @return the result from applying the function to the machine. * @return the result from applying the function to the machine.
*/ */
public <T> T readLockMachineAndApply(final String machineId, final Function<IMachine, T> function) { public <T> T sharedLockMachineAndApply(final String machineId, final Function<IMachine, T> function) {
return lockSessionOnMachineAndApply(machineId, LockType.Shared, new Function<ISession, T>() { return lockSessionOnMachineAndApply(machineId, LockType.Shared, new Function<ISession, T>() {
@Override @Override
@ -144,10 +143,11 @@ public class MachineUtils {
}); });
} }
/** /**
* Locks the machine and executes the given function to the session using the machine matching the given id. * Locks the machine and executes the given function to the session using the machine matching
* The machine is read locked, which means that settings can be read safely (but not changed) by function. * the given id. The machine is read locked, which means that settings can be read safely (but
* not changed) by function.
* <p/> * <p/>
* Unlocks the machine before returning. * Unlocks the machine before returning.
* *
@ -157,10 +157,9 @@ public class MachineUtils {
* the function to execute * the function to execute
* @return the result from applying the function to the machine. * @return the result from applying the function to the machine.
*/ */
public <T> T readLockMachineAndApplyToSession(final String machineId, final Function<ISession, T> function) { public <T> T sharedLockMachineAndApplyToSession(final String machineId, final Function<ISession, T> function) {
return lockSessionOnMachineAndApply(machineId, LockType.Shared, function); return lockSessionOnMachineAndApply(machineId, LockType.Shared, function);
} }
/** /**
* Locks the machine and executes the given function using the current session. Since the machine * Locks the machine and executes the given function using the current session. Since the machine
@ -183,11 +182,14 @@ public class MachineUtils {
int retries = 5; int retries = 5;
int count = 0; int count = 0;
ISession session; ISession session;
long time = System.currentTimeMillis();
while (true) { while (true) {
try { try {
session = manager.get().getSessionObject();
IMachine immutableMachine = manager.get().getVBox().findMachine(machineId); IMachine immutableMachine = manager.get().getVBox().findMachine(machineId);
session = manager.get().getSessionObject();
immutableMachine.lockMachine(session, type); immutableMachine.lockMachine(session, type);
System.err.println("ACQUIRED LOCK ["+time+"]");
print();
break; break;
} catch (VBoxException e) { } catch (VBoxException e) {
VBoxException vbex = Throwables2.getFirstThrowableOfType(e, VBoxException.class); VBoxException vbex = Throwables2.getFirstThrowableOfType(e, VBoxException.class);
@ -195,7 +197,7 @@ public class MachineUtils {
return null; return null;
} }
count++; count++;
logger.warn("Could not lock machine (try %i of %i). Error: %s", retries, count, e.getMessage()); logger.warn(e, "Could not lock machine (try %d of %d). Error: %s", count, retries, e.getMessage());
if (count == retries) { if (count == retries) {
throw new RuntimeException(String.format("error locking %s with %s lock: %s", machineId, type, throw new RuntimeException(String.format("error locking %s with %s lock: %s", machineId, type,
e.getMessage()), e); e.getMessage()), e);
@ -213,6 +215,14 @@ public class MachineUtils {
type, e.getMessage()), e); type, e.getMessage()), e);
} finally { } finally {
session.unlockMachine(); session.unlockMachine();
System.err.println("RELEASED LOCK ["+time+"]");
print();
}
}
void print() {
for (StackTraceElement element : Thread.currentThread().getStackTrace()){
System.err.println(element.toString());
} }
} }

View File

@ -142,7 +142,7 @@ public class CreateAndInstallVmLiveTest extends BaseVirtualBoxClientLiveTest {
String vboxVersion = Iterables.get( String vboxVersion = Iterables.get(
Splitter.on('r').split(context.getProviderSpecificContext().getBuildVersion()), 0); Splitter.on('r').split(context.getProviderSpecificContext().getBuildVersion()), 0);
assertEquals(vboxVersion, machineUtils.readLockMachineAndApplyToSession(machine.getName(), assertEquals(vboxVersion, machineUtils.sharedLockMachineAndApplyToSession(machine.getName(),
new Function<ISession, String>() { new Function<ISession, String>() {
@Override @Override
public String apply(ISession session) { public String apply(ISession session) {

View File

@ -110,7 +110,7 @@ public class GuestAdditionsInstallerLiveTest extends
machineUtils.applyForMachine(machine.getName(), machineUtils.applyForMachine(machine.getName(),
new LaunchMachineIfNotAlreadyRunning(manager.get(), new LaunchMachineIfNotAlreadyRunning(manager.get(),
ExecutionType.GUI, "")); ExecutionType.GUI, ""));
assertTrue(machineUtils.readLockMachineAndApplyToSession( assertTrue(machineUtils.sharedLockMachineAndApplyToSession(
machine.getName(), machine.getName(),
new Function<ISession, Boolean>() { new Function<ISession, Boolean>() {
@Override @Override