From c8590629a15fede9e881e7f080c34a38ec3a7acc Mon Sep 17 00:00:00 2001 From: Jozufozu Date: Thu, 4 Jan 2024 12:35:58 -0800 Subject: [PATCH] We do a little thieving - Reimplement stealInstance. --- .../flywheel/api/instance/Instancer.java | 13 ++++++ .../backend/engine/AbstractInstancer.java | 44 +++++++++++++++++-- .../backend/engine/InstanceHandleImpl.java | 2 +- 3 files changed, 55 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/jozufozu/flywheel/api/instance/Instancer.java b/src/main/java/com/jozufozu/flywheel/api/instance/Instancer.java index 17f17fa80..52e10f425 100644 --- a/src/main/java/com/jozufozu/flywheel/api/instance/Instancer.java +++ b/src/main/java/com/jozufozu/flywheel/api/instance/Instancer.java @@ -24,6 +24,19 @@ public interface Instancer { */ I createInstance(); + /** + * Steal an instance from another instancer. + *
+ * This has the effect of swapping the instance's model in-place. + *

+ * If the given instance is already owned by this instancer, this method does nothing. + *
+ * 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. * diff --git a/src/main/java/com/jozufozu/flywheel/backend/engine/AbstractInstancer.java b/src/main/java/com/jozufozu/flywheel/backend/engine/AbstractInstancer.java index e4dc0ce91..c4d7b3e66 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/engine/AbstractInstancer.java +++ b/src/main/java/com/jozufozu/flywheel/backend/engine/AbstractInstancer.java @@ -29,13 +29,51 @@ public abstract class AbstractInstancer implements Instancer var handle = new InstanceHandleImpl(this, i); I instance = type.create(handle); - instances.add(instance); - handles.add(handle); - changed.set(i); + addLocked(instance, handle); 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() { return instances.size(); } diff --git a/src/main/java/com/jozufozu/flywheel/backend/engine/InstanceHandleImpl.java b/src/main/java/com/jozufozu/flywheel/backend/engine/InstanceHandleImpl.java index 820ef2c4a..17148ac6c 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/engine/InstanceHandleImpl.java +++ b/src/main/java/com/jozufozu/flywheel/backend/engine/InstanceHandleImpl.java @@ -3,7 +3,7 @@ package com.jozufozu.flywheel.backend.engine; import com.jozufozu.flywheel.api.instance.InstanceHandle; public class InstanceHandleImpl implements InstanceHandle { - public final AbstractInstancer instancer; + public AbstractInstancer instancer; public int index; public InstanceHandleImpl(AbstractInstancer instancer, int index) {