Skip to content

Commit 0d61467

Browse files
committed
start using ThreadLocal
1 parent 2de9acd commit 0d61467

1 file changed

Lines changed: 43 additions & 23 deletions

File tree

driver-core/src/main/com/mongodb/internal/async/function/AsyncCallbackLoop.java

Lines changed: 43 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -53,47 +53,67 @@ public AsyncCallbackLoop(final LoopState state, final AsyncCallbackRunnable body
5353

5454
@Override
5555
public void run(final SingleResultCallback<Void> callback) {
56-
body.loop(new ReusableLoopCallback(callback));
56+
body.initiateIteration(false, new ReusableLoopCallback(callback));
5757
}
5858

5959
private static final class Body {
6060
private final AsyncCallbackRunnable wrapped;
6161
private final LoopState state;
62-
private boolean reenteredLoopMethod;
62+
private final ThreadLocal<Boolean> iterationIsExecutingSynchronously;
63+
private final ThreadLocal<Status> status;
64+
65+
private enum Status {
66+
ITERATION_INITIATED,
67+
LAST_ITERATION_COMPLETED,
68+
ANOTHER_ITERATION_NEEDED
69+
}
6370

6471
private Body(final LoopState state, final AsyncCallbackRunnable body) {
6572
this.wrapped = body;
6673
this.state = state;
67-
reenteredLoopMethod = false;
74+
iterationIsExecutingSynchronously = ThreadLocal.withInitial(() -> false);
75+
status = ThreadLocal.withInitial(() -> Status.ITERATION_INITIATED);
6876
}
6977

7078
/**
71-
* @return {@code true} to indicate that the looping completed;
72-
* {@code false} to indicate that the looping is still executing, potentially asynchronously.
79+
* Invoking this method initiates a new iteration of the loop. An iteration may be executed either
80+
* synchronously or asynchronously with the execution of this method:
81+
*
82+
* <ul>
83+
* <li>synchronous execution: iteration completes before (in the happens-before order) the method completes;</li>
84+
* <li>asynchronous execution: the aforementioned relation does not exist.</li>
85+
* </ul>
86+
*
87+
* @return {@code true} iff it is known that another iteration must be initiated.
88+
* Such information is available to this method only if the iteration it initiated has completed synchronously.
7389
*/
74-
boolean loop(final ReusableLoopCallback callback) {
75-
boolean[] done = {true};
90+
Status initiateIteration(final boolean trampolining, final ReusableLoopCallback callback) {
91+
iterationIsExecutingSynchronously.set(true);
7692
wrapped.run((r, t) -> {
77-
boolean localDone = callback.onResult(state, r, t);
78-
if (localDone) {
79-
done[0] = localDone;
93+
boolean localIterationIsExecutingSynchronously = iterationIsExecutingSynchronously.get();
94+
if (callback.onResult(state, r, t)) {
95+
status.set(Status.LAST_ITERATION_COMPLETED);
8096
return;
8197
}
82-
if (!reenteredLoopMethod) {
83-
reenteredLoopMethod = true;
84-
try {
85-
do {
86-
localDone = loop(callback);
87-
} while (!localDone);
88-
done[0] = assertTrue(localDone);
89-
} finally {
90-
reenteredLoopMethod = false;
91-
}
92-
} else {
93-
done[0] = localDone;
98+
if (trampolining && localIterationIsExecutingSynchronously) {
99+
// bounce
100+
status.set(Status.ANOTHER_ITERATION_NEEDED);
101+
return;
94102
}
103+
Status localStatus;
104+
do {
105+
localStatus = initiateIteration(true, callback);
106+
} while (localStatus.equals(Status.ANOTHER_ITERATION_NEEDED));
107+
status.set(localStatus);
108+
109+
// VAKOTODO remove thread-locals if executed asynchronously
95110
});
96-
return done[0];
111+
try {
112+
return status.get();
113+
} finally {
114+
status.remove();
115+
iterationIsExecutingSynchronously.remove();
116+
}
97117
}
98118
}
99119

0 commit comments

Comments
 (0)