We do a little thieving

- Reimplement stealInstance.
This commit is contained in:
Jozufozu 2024-01-04 12:35:58 -08:00
parent 8221616eff
commit c8590629a1
3 changed files with 55 additions and 4 deletions

View file

@ -24,6 +24,19 @@ public interface Instancer<I extends Instance> {
*/ */
I createInstance(); I createInstance();
/**
* Steal an instance from another instancer.
* <br>
* This has the effect of swapping the instance's model in-place.
* <br><br>
* If the given instance is already owned by this instancer, this method does nothing.
* <br>
* If the given instance was created by a different backend, the behavior of this method is undefined.
*
* @param instance The instance to steal.
*/
void stealInstance(I instance);
/** /**
* Populate arr with new instances of this model. * Populate arr with new instances of this model.
* *

View file

@ -29,13 +29,51 @@ public abstract class AbstractInstancer<I extends Instance> implements Instancer
var handle = new InstanceHandleImpl(this, i); var handle = new InstanceHandleImpl(this, i);
I instance = type.create(handle); I instance = type.create(handle);
instances.add(instance); addLocked(instance, handle);
handles.add(handle);
changed.set(i);
return instance; return instance;
} }
} }
@Override
public void stealInstance(I instance) {
var instanceHandle = instance.handle();
if (!(instanceHandle instanceof InstanceHandleImpl handle)) {
// UB: do nothing
return;
}
if (handle.instancer == this) {
return;
}
// FIXME: in theory there could be a race condition here if the instance
// is somehow being stolen by 2 different instancers between threads.
// That seems kinda impossible so I'm fine leaving it as is for now.
// Remove the instance from its old instancer.
// This won't have any unwanted effect when the old instancer
// is filtering deleted instances later, so is safe.
handle.setDeleted();
// Only lock now that we'll be mutating our state.
synchronized (lock) {
// Add the instance to this instancer.
handle.instancer = this;
handle.index = instances.size();
addLocked(instance, handle);
}
}
/**
* Calls must be synchronized on {@link #lock}.
*/
private void addLocked(I instance, InstanceHandleImpl handle) {
instances.add(instance);
handles.add(handle);
changed.set(handle.index);
}
public int getInstanceCount() { public int getInstanceCount() {
return instances.size(); return instances.size();
} }

View file

@ -3,7 +3,7 @@ package com.jozufozu.flywheel.backend.engine;
import com.jozufozu.flywheel.api.instance.InstanceHandle; import com.jozufozu.flywheel.api.instance.InstanceHandle;
public class InstanceHandleImpl implements InstanceHandle { public class InstanceHandleImpl implements InstanceHandle {
public final AbstractInstancer<?> instancer; public AbstractInstancer<?> instancer;
public int index; public int index;
public InstanceHandleImpl(AbstractInstancer<?> instancer, int index) { public InstanceHandleImpl(AbstractInstancer<?> instancer, int index) {