1919import com .mongodb .internal .async .function .LoopState ;
2020import com .mongodb .internal .time .StartTime ;
2121import com .mongodb .lang .Nullable ;
22+ import org .junit .jupiter .api .AfterAll ;
23+ import org .junit .jupiter .api .BeforeAll ;
2224import org .junit .jupiter .params .ParameterizedTest ;
2325import org .junit .jupiter .params .provider .CsvSource ;
2426
2830import java .time .Duration ;
2931import java .util .Objects ;
3032import java .util .concurrent .CompletableFuture ;
31- import java .util .concurrent .ForkJoinPool ;
33+ import java .util .concurrent .Executors ;
34+ import java .util .concurrent .ScheduledExecutorService ;
3235import java .util .concurrent .TimeUnit ;
3336
3437import static com .mongodb .internal .async .AsyncRunnable .beginAsync ;
3538
3639class VakoTest {
40+ private static ScheduledExecutorService executor ;
41+
42+ @ BeforeAll
43+ static void beforeAll () {
44+ executor = Executors .newScheduledThreadPool (2 );
45+ }
46+
47+ @ AfterAll
48+ static void afterAll () throws InterruptedException {
49+ executor .shutdownNow ();
50+ com .mongodb .assertions .Assertions .assertTrue (executor .awaitTermination (1 , TimeUnit .MINUTES ));
51+ }
52+
3753 @ ParameterizedTest
3854 @ CsvSource ({
3955 "10"
4056 })
4157 void asyncCallbackLoop (final int iterations ) throws Exception {
42- System .err .printf ("baselineStackDepth=%d%n" , Thread .currentThread ().getStackTrace ().length );
58+ System .err .printf ("baselineStackDepth=%d%n%n " , Thread .currentThread ().getStackTrace ().length );
4359 CompletableFuture <Void > join = new CompletableFuture <>();
4460 LoopState loopState = new LoopState ();
4561 new AsyncCallbackLoop (loopState , c -> {
@@ -51,78 +67,92 @@ void asyncCallbackLoop(final int iterations) throws Exception {
5167 }).run ((r , t ) -> {
5268 System .err .printf ("test callback completed callStackDepth=%d, r=%s, t=%s%n" ,
5369 Thread .currentThread ().getStackTrace ().length , r , exceptionToString (t ));
54- if (t != null ) {
55- join .completeExceptionally (t );
56- } else {
57- join .complete (r );
58- }
70+ complete (join , r , t );
5971 });
6072 join .get ();
6173 System .err .printf ("%n%nDONE%n%n" );
6274 }
6375
76+ private enum IterationExecutionType {
77+ SYNC_SAME_THREAD ,
78+ SYNC_DIFFERENT_THREAD ,
79+ ASYNC ,
80+ }
81+
6482 @ ParameterizedTest ()
6583 @ CsvSource ({
66- "0, false, 0, 10" ,
67- "0, true, 4, 10" ,
68- "4, true, 0, 10"
84+ "10, 0, SYNC_SAME_THREAD, 0" ,
85+ // "10, 0, SYNC_DIFFERENT_THREAD, 0",
86+ "10, 0, ASYNC, 4" ,
87+ "10, 4, ASYNC, 0"
6988 })
7089 void testThenRunDoWhileLoop (
71- final int blockInAsyncMethodTotalSeconds ,
72- final boolean asyncExecution ,
73- final int delayAsyncExecutionTotalSeconds ,
74- final int counterInitialValue ) throws Exception {
75- Duration blockInAsyncMethodTotalDuration = Duration .ofSeconds (blockInAsyncMethodTotalSeconds );
76- com .mongodb .assertions .Assertions .assertTrue (asyncExecution || delayAsyncExecutionTotalSeconds == 0 );
90+ final int counterInitialValue ,
91+ final int blockSyncPartOfIterationTotalSeconds ,
92+ final IterationExecutionType executionType ,
93+ final int delayAsyncExecutionTotalSeconds ) throws Exception {
94+ System .err .printf ("baselineStackDepth=%d%n%n" , Thread .currentThread ().getStackTrace ().length );
95+ Duration blockSyncPartOfIterationTotalDuration = Duration .ofSeconds (blockSyncPartOfIterationTotalSeconds );
96+ com .mongodb .assertions .Assertions .assertTrue (
97+ executionType .equals (IterationExecutionType .ASYNC ) || delayAsyncExecutionTotalSeconds == 0 );
7798 Duration delayAsyncExecutionTotalDuration = Duration .ofSeconds (delayAsyncExecutionTotalSeconds );
7899 StartTime start = StartTime .now ();
79- System .err .printf ("baselineStackDepth=%d%n" , Thread .currentThread ().getStackTrace ().length );
80100 CompletableFuture <Void > join = new CompletableFuture <>();
81- asyncMethod1 ( blockInAsyncMethodTotalDuration , asyncExecution , delayAsyncExecutionTotalDuration , new Counter (counterInitialValue ),
101+ asyncLoop ( new Counter (counterInitialValue ), blockSyncPartOfIterationTotalDuration , executionType , delayAsyncExecutionTotalDuration ,
82102 (r , t ) -> {
83- System .err .printf ("TEST callback completed callStackDepth=%s, r=%s, t=%s%n" ,
103+ System .err .printf ("test callback completed callStackDepth=%s, r=%s, t=%s%n" ,
84104 Thread .currentThread ().getStackTrace ().length , r , exceptionToString (t ));
85- if (t != null ) {
86- join .completeExceptionally (t );
87- } else {
88- join .complete (r );
89- }
105+ complete (join , r , t );
90106 });
91- System .err .printf ("asyncMethod1 returned in %s%n" , start .elapsed ());
107+ System .err .printf ("\t asyncLoop returned in %s%n" , start .elapsed ());
92108 join .get ();
93109 System .err .printf ("%n%nDONE%n%n" );
94110 }
95111
96- private static void asyncMethod1 (
97- final Duration blockInAsyncMethodTotalDuration ,
98- final boolean asyncExecution ,
99- final Duration delayAsyncExecutionTotalDuration ,
112+ private static void asyncLoop (
100113 final Counter counter ,
114+ final Duration blockSyncPartOfIterationTotalDuration ,
115+ final IterationExecutionType executionType ,
116+ final Duration delayAsyncExecutionTotalDuration ,
101117 final SingleResultCallback <Void > callback ) {
102118 beginAsync ().thenRunDoWhileLoop (c -> {
103- sleep (blockInAsyncMethodTotalDuration .dividedBy (counter .initial ()));
119+ sleep (blockSyncPartOfIterationTotalDuration .dividedBy (counter .initial ()));
104120 StartTime start = StartTime .now ();
105- asyncMethod2 ( asyncExecution , delayAsyncExecutionTotalDuration , counter , c );
106- System .err .printf ("asyncMethod2 returned in %s%n" , start .elapsed ());
121+ asyncPartOfIteration ( counter , executionType , delayAsyncExecutionTotalDuration , c );
122+ System .err .printf ("\t asyncPartOfIteration returned in %s%n" , start .elapsed ());
107123 }, () -> !counter .done ()).finish (callback );
108124 }
109125
110- private static void asyncMethod2 (
111- final boolean asyncExecution ,
112- final Duration delayAsyncExecutionTotalDuration ,
126+ private static void asyncPartOfIteration (
113127 final Counter counter ,
128+ final IterationExecutionType executionType ,
129+ final Duration delayAsyncExecutionTotalDuration ,
114130 final SingleResultCallback <Void > callback ) {
115- Runnable action = () -> {
116- sleep (delayAsyncExecutionTotalDuration .dividedBy (counter .initial ()));
131+ Runnable asyncPartOfIteration = () -> {
117132 counter .countDown ();
118133 StartTime start = StartTime .now ();
119134 callback .complete (callback );
120- System .err .printf ("asyncMethod2 callback.complete returned in %s%n" , start .elapsed ());
135+ System .err .printf ("\t asyncPartOfIteration callback.complete returned in %s%n" , start .elapsed ());
121136 };
122- if (asyncExecution ) {
123- ForkJoinPool .commonPool ().execute (action );
124- } else {
125- action .run ();
137+ switch (executionType ) {
138+ case SYNC_SAME_THREAD : {
139+ asyncPartOfIteration .run ();
140+ break ;
141+ }
142+ case SYNC_DIFFERENT_THREAD : {
143+ Thread guaranteedDifferentThread = new Thread (asyncPartOfIteration );
144+ guaranteedDifferentThread .start ();
145+ join (guaranteedDifferentThread );
146+ break ;
147+ }
148+ case ASYNC : {
149+ executor .schedule (asyncPartOfIteration ,
150+ delayAsyncExecutionTotalDuration .dividedBy (counter .initial ()).toNanos (), TimeUnit .NANOSECONDS );
151+ break ;
152+ }
153+ default : {
154+ com .mongodb .assertions .Assertions .fail (executionType .toString ());
155+ }
126156 }
127157 }
128158
@@ -170,6 +200,23 @@ private static String exceptionToString(@Nullable final Throwable t) {
170200 }
171201 }
172202
203+ private static <T > void complete (final CompletableFuture <T > future , @ Nullable final T result , @ Nullable final Throwable t ) {
204+ if (t != null ) {
205+ future .completeExceptionally (t );
206+ } else {
207+ future .complete (result );
208+ }
209+ }
210+
211+ private static void join (final Thread thread ) {
212+ try {
213+ thread .join ();
214+ } catch (InterruptedException e ) {
215+ Thread .currentThread ().interrupt ();
216+ throw new RuntimeException (e );
217+ }
218+ }
219+
173220 private static void sleep (final Duration duration ) {
174221 if (duration .isZero ()) {
175222 return ;
@@ -179,7 +226,6 @@ private static void sleep(final Duration duration) {
179226 long durationMsPartFromNsPart = TimeUnit .MILLISECONDS .convert (duration .getNano (), TimeUnit .NANOSECONDS );
180227 long sleepMs = TimeUnit .MILLISECONDS .convert (duration .getSeconds (), TimeUnit .SECONDS ) + durationMsPartFromNsPart ;
181228 int sleepNs = Math .toIntExact (durationNsPart - TimeUnit .NANOSECONDS .convert (durationMsPartFromNsPart , TimeUnit .MILLISECONDS ));
182- System .err .printf ("sleeping for %d ms %d ns%n" , sleepMs , sleepNs );
183229 Thread .sleep (sleepMs , sleepNs );
184230 } catch (InterruptedException e ) {
185231 Thread .currentThread ().interrupt ();
0 commit comments