fix: improve threaded world compatibility and chunk reads in 1.1.15
Add regression tests and per-dimension progress diagnostics. Document the unresolved C2ME random-initialization redirect conflict.
This commit is contained in:
1 parent
74cae0b581
commit
32b11aee87
42 files changed
+1506
-381
No files matched your search
@@ -0,0 +1,83 @@
|
||||
import dev.modzuozhi.core.compat.ManagedFutureAwait;
|
||||
import java.util.concurrent.*;
|
||||
|
||||
/** Standalone regression: dimension work needs a callback on the waiting server thread. */
|
||||
public final class ManagedFutureAwaitRegression {
|
||||
public static void main(String[] args) throws Exception {
|
||||
Thread serverThread = Thread.currentThread();
|
||||
BlockingQueue<Runnable> serverTasks = new LinkedBlockingQueue<>();
|
||||
CompletableFuture<Integer> chunk = new CompletableFuture<>();
|
||||
Thread worker = new Thread(() -> {
|
||||
try {
|
||||
CompletableFuture<Void> physics = new CompletableFuture<>();
|
||||
serverTasks.add(() -> {
|
||||
if (Thread.currentThread() != serverThread) {
|
||||
physics.completeExceptionally(new AssertionError("wrong callback thread"));
|
||||
} else {
|
||||
physics.complete(null);
|
||||
}
|
||||
});
|
||||
physics.get(3, TimeUnit.SECONDS);
|
||||
chunk.complete(42);
|
||||
} catch (Throwable failure) {
|
||||
chunk.completeExceptionally(failure);
|
||||
}
|
||||
}, "test-dimension-worker");
|
||||
worker.start();
|
||||
int value = ManagedFutureAwait.join(chunk, done -> {
|
||||
long deadline = System.nanoTime() + TimeUnit.SECONDS.toNanos(5);
|
||||
while (!done.getAsBoolean()) {
|
||||
if (System.nanoTime() > deadline) throw new AssertionError("circular wait");
|
||||
try {
|
||||
Runnable task = serverTasks.poll(10, TimeUnit.MILLISECONDS);
|
||||
if (task != null) task.run();
|
||||
} catch (InterruptedException failure) {
|
||||
throw new AssertionError(failure);
|
||||
}
|
||||
}
|
||||
});
|
||||
worker.join(1000);
|
||||
if (value != 42 || worker.isAlive()) throw new AssertionError("request did not finish");
|
||||
if (ManagedFutureAwait.join(CompletableFuture.completedFuture(7), done -> {
|
||||
throw new AssertionError("completed future pumped callbacks");
|
||||
}) != 7) throw new AssertionError("wrong result");
|
||||
RuntimeException failure = new RuntimeException("expected");
|
||||
try {
|
||||
ManagedFutureAwait.join(CompletableFuture.failedFuture(failure), done -> {});
|
||||
throw new AssertionError("exception swallowed");
|
||||
} catch (CompletionException expected) {
|
||||
if (expected.getCause() != failure) throw new AssertionError("exception changed");
|
||||
}
|
||||
CompletableFuture<Object> cancelled = new CompletableFuture<>();
|
||||
cancelled.cancel(false);
|
||||
try {
|
||||
ManagedFutureAwait.join(cancelled, done -> {});
|
||||
throw new AssertionError("cancellation swallowed");
|
||||
} catch (CancellationException expected) {}
|
||||
// An apparently server-owned cache can switch owner after the entry check.
|
||||
// The request must remain queued regardless; an inline-capable execute() is unsafe.
|
||||
BlockingQueue<Runnable> chunkTasks = new LinkedBlockingQueue<>();
|
||||
java.util.concurrent.atomic.AtomicReference<Thread> owner =
|
||||
new java.util.concurrent.atomic.AtomicReference<>(serverThread);
|
||||
java.util.concurrent.atomic.AtomicBoolean executed = new java.util.concurrent.atomic.AtomicBoolean();
|
||||
int queued = ManagedFutureAwait.callQueued(() -> {
|
||||
if (owner.get() != Thread.currentThread()) throw new AssertionError("wrong chunk owner");
|
||||
executed.set(true);
|
||||
return 19;
|
||||
}, task -> {
|
||||
chunkTasks.add(task);
|
||||
if (executed.get()) throw new AssertionError("request executed inline");
|
||||
}, done -> {
|
||||
Thread dimension = new Thread(() -> {
|
||||
owner.set(Thread.currentThread());
|
||||
chunkTasks.remove().run();
|
||||
});
|
||||
dimension.start();
|
||||
try { dimension.join(2000); } catch (InterruptedException e) { throw new AssertionError(e); }
|
||||
if (!done.getAsBoolean()) throw new AssertionError("queued request stuck");
|
||||
});
|
||||
if (queued != 19 || !executed.get()) throw new AssertionError("lost queued result");
|
||||
System.out.println("PASS: callback handoff, completion, failure and cancellation");
|
||||
System.out.println("PASS: unconditional enqueue survives owner switch after entry");
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user