2929
3030import com .google .common .util .concurrent .ListenableFuture ;
3131import com .google .common .util .concurrent .SettableFuture ;
32- import org .apache .tsfile .external .commons .lang3 .Validate ;
3332import org .apache .tsfile .read .common .block .TsBlock ;
3433import org .junit .Assert ;
3534import org .junit .Test ;
3635import org .mockito .Mockito ;
3736
37+ import java .util .concurrent .CompletionService ;
38+ import java .util .concurrent .ExecutorCompletionService ;
3839import java .util .concurrent .ExecutorService ;
3940import java .util .concurrent .Executors ;
40- import java .util .concurrent .atomic .AtomicReference ;
41+ import java .util .concurrent .Future ;
42+ import java .util .concurrent .TimeUnit ;
4143
4244import static com .google .common .util .concurrent .MoreExecutors .newDirectExecutorService ;
4345
@@ -119,8 +121,8 @@ public void testAsyncListenerAfterAbortDoesNotAddTsBlock() {
119121 Assert .assertTrue (addFuture .isDone ());
120122 }
121123
122- @ Test ( timeout = 15000L )
123- public void concurrencyTest () {
124+ @ Test
125+ public void concurrencyTest () throws Exception {
124126 final String queryId = "q0" ;
125127 final long mockTsBlockSize = 1024L * 1024L ;
126128
@@ -140,120 +142,57 @@ public void concurrencyTest() {
140142 queue .getCanAddTsBlock ().set (null );
141143 queue .setMaxBytesCanReserve (Long .MAX_VALUE );
142144
145+ // Reuse an immutable block so mock generation is outside the concurrency deadline.
146+ TsBlock block = Utils .createMockTsBlock (mockTsBlockSize );
147+ int blockCount = 1000 ;
143148 ExecutorService executor = Executors .newFixedThreadPool (2 );
144- AtomicReference <Integer > numOfTimesSenderBlocked = new AtomicReference <>(0 );
145- AtomicReference <Integer > numOfTimesReceiverBlocked = new AtomicReference <>(0 );
146- AtomicReference <Integer > numOfTsBlocksToSend = new AtomicReference <>(1000 );
147- AtomicReference <Integer > numOfTsBlocksToReceive = new AtomicReference <>(1000 );
148- executor .submit (
149- new SendTask (
150- queue , mockTsBlockSize , numOfTsBlocksToSend , numOfTimesSenderBlocked , executor ));
151- executor .submit (
152- new ReceiveTask (queue , numOfTsBlocksToReceive , numOfTimesReceiverBlocked , executor ));
153-
154- while (numOfTsBlocksToSend .get () != 0 && numOfTsBlocksToReceive .get () != 0 ) {
155- String message =
156- String .format (
157- "Sender %d: %d, Receiver %d: %d" ,
158- numOfTimesSenderBlocked .get (),
159- numOfTsBlocksToSend .get (),
160- numOfTimesReceiverBlocked .get (),
161- numOfTsBlocksToReceive .get ());
162- System .out .println (message );
163- try {
164- Thread .sleep (10L );
165- } catch (InterruptedException e ) {
166- Assert .fail (e .getMessage ());
167- }
168- }
169- }
170-
171- private static class SendTask implements Runnable {
172-
173- private final SharedTsBlockQueue queue ;
174- private final long mockTsBlockSize ;
175- private final AtomicReference <Integer > numOfTsBlocksToSend ;
176- private final AtomicReference <Integer > numOfTimesBlocked ;
177- private final ExecutorService executor ;
178-
179- public SendTask (
180- SharedTsBlockQueue queue ,
181- long mockTsBlockSize ,
182- AtomicReference <Integer > numOfTsBlocksToSend ,
183- AtomicReference <Integer > numOfTimesBlocked ,
184- ExecutorService executor ) {
185- this .queue = Validate .notNull (queue );
186- Validate .isTrue (mockTsBlockSize > 0L );
187- this .mockTsBlockSize = mockTsBlockSize ;
188- this .numOfTsBlocksToSend = Validate .notNull (numOfTsBlocksToSend );
189- this .numOfTimesBlocked = Validate .notNull (numOfTimesBlocked );
190- this .executor = Validate .notNull (executor );
191- }
192-
193- @ Override
194- public void run () {
195- ListenableFuture <Void > blockedOnMemory = null ;
196- while (numOfTsBlocksToSend .get () > 0 ) {
197- synchronized (queue ) {
198- blockedOnMemory = queue .add (Utils .createMockTsBlock (mockTsBlockSize ));
199- }
200- numOfTsBlocksToSend .updateAndGet (v -> v - 1 );
201- if (!blockedOnMemory .isDone ()) {
202- break ;
203- }
204- }
205-
206- if (blockedOnMemory != null ) {
207- numOfTimesBlocked .updateAndGet (v -> v + 1 );
208- blockedOnMemory .addListener (
209- new SendTask (queue , mockTsBlockSize , numOfTsBlocksToSend , numOfTimesBlocked , executor ),
210- executor );
211- } else {
212- synchronized (queue ) {
213- queue .setNoMoreTsBlocks (true );
214- }
149+ CompletionService <Void > completedTasks = new ExecutorCompletionService <>(executor );
150+ try {
151+ completedTasks .submit (
152+ () -> {
153+ for (int i = 0 ; i < blockCount ; i ++) {
154+ ListenableFuture <Void > blocked ;
155+ synchronized (queue ) {
156+ blocked = queue .add (block );
157+ }
158+ blocked .get (10 , TimeUnit .SECONDS );
159+ }
160+ synchronized (queue ) {
161+ queue .setNoMoreTsBlocks (true );
162+ }
163+ return null ;
164+ });
165+ completedTasks .submit (
166+ () -> {
167+ for (int i = 0 ; i < blockCount ; i ++) {
168+ ListenableFuture <Void > blocked ;
169+ synchronized (queue ) {
170+ blocked = queue .isBlocked ();
171+ }
172+ blocked .get (10 , TimeUnit .SECONDS );
173+ synchronized (queue ) {
174+ Assert .assertSame (block , queue .remove ());
175+ }
176+ }
177+ return null ;
178+ });
179+ for (int i = 0 ; i < 2 ; i ++) {
180+ Future <Void > completed = completedTasks .poll (10 , TimeUnit .SECONDS );
181+ Assert .assertNotNull (completed );
182+ completed .get ();
215183 }
216- }
217- }
218-
219- private static class ReceiveTask implements Runnable {
220-
221- private final SharedTsBlockQueue queue ;
222- private final AtomicReference <Integer > numOfTsBlocksToReceive ;
223- private final AtomicReference <Integer > numOfTimesBlocked ;
224- private final ExecutorService executor ;
225-
226- public ReceiveTask (
227- SharedTsBlockQueue queue ,
228- AtomicReference <Integer > numOfTsBlocksToReceive ,
229- AtomicReference <Integer > numOfTimesBlocked ,
230- ExecutorService executor ) {
231- this .queue = Validate .notNull (queue );
232- this .numOfTsBlocksToReceive = Validate .notNull (numOfTsBlocksToReceive );
233- this .numOfTimesBlocked = Validate .notNull (numOfTimesBlocked );
234- this .executor = Validate .notNull (executor );
235- }
236-
237- @ Override
238- public void run () {
239- ListenableFuture <Void > blocked = null ;
240- while (numOfTsBlocksToReceive .get () > 0 ) {
184+ Assert .assertTrue (queue .hasNoMoreTsBlocks ());
185+ Assert .assertTrue (queue .isEmpty ());
186+ Assert .assertEquals (0 , spyMemoryPool .getReservedBytes ());
187+ } finally {
188+ executor .shutdownNow ();
189+ try {
190+ Assert .assertTrue (executor .awaitTermination (10 , TimeUnit .SECONDS ));
191+ } finally {
241192 synchronized (queue ) {
242- blocked = queue .isBlocked ();
243- if (blocked .isDone ()) {
244- queue .remove ();
245- numOfTsBlocksToReceive .updateAndGet (v -> v - 1 );
246- } else {
247- break ;
248- }
193+ queue .close ();
249194 }
250195 }
251-
252- if (blocked != null ) {
253- numOfTimesBlocked .updateAndGet (v -> v + 1 );
254- blocked .addListener (
255- new ReceiveTask (queue , numOfTsBlocksToReceive , numOfTimesBlocked , executor ), executor );
256- }
257196 }
258197 }
259198
0 commit comments