|
6 | 6 | import org.junit.Before;
|
7 | 7 | import org.junit.Test;
|
8 | 8 |
|
| 9 | +import java.util.concurrent.Callable; |
| 10 | +import java.util.concurrent.CountDownLatch; |
| 11 | +import java.util.concurrent.atomic.AtomicBoolean; |
| 12 | +import java.util.concurrent.atomic.AtomicLong; |
| 13 | + |
9 | 14 | import static java.util.Objects.requireNonNull;
|
10 | 15 | import static org.junit.Assert.*;
|
11 | 16 |
|
@@ -202,4 +207,60 @@ public void putValueForExistingLeaf_Int() {
|
202 | 207 | });
|
203 | 208 | }
|
204 | 209 |
|
| 210 | + @Test |
| 211 | + public void concurrentTxs() throws InterruptedException { |
| 212 | + final CountDownLatch latch = new CountDownLatch(3); |
| 213 | + final AtomicBoolean readThreadOK = new AtomicBoolean(false); |
| 214 | + final AtomicLong bookBranchId = new AtomicLong(0); |
| 215 | + Thread readThread = new Thread(() -> { |
| 216 | + tree.runInReadTx(() -> { |
| 217 | + System.out.println("Thread " + Thread.currentThread().getId() + " entered tree TX"); |
| 218 | + latch.countDown(); |
| 219 | + try { |
| 220 | + latch.await(); |
| 221 | + } catch (InterruptedException e) { |
| 222 | + e.printStackTrace(); |
| 223 | + } |
| 224 | + assertNull(tree.root().branch("Book")); |
| 225 | + readThreadOK.set(true); |
| 226 | + }); |
| 227 | + }); |
| 228 | + readThread.start(); |
| 229 | + |
| 230 | + Thread writeThread = new Thread(() -> { |
| 231 | + tree.runInTx(() -> { |
| 232 | + System.out.println("Thread " + Thread.currentThread().getId() + " entered tree TX (write)"); |
| 233 | + latch.countDown(); |
| 234 | + try { |
| 235 | + latch.await(); |
| 236 | + } catch (InterruptedException e) { |
| 237 | + e.printStackTrace(); |
| 238 | + } |
| 239 | + long id = tree.putBranch(tree.root().getId(), metaBranchIds[1]); |
| 240 | + bookBranchId.set(id); |
| 241 | + }); |
| 242 | + }); |
| 243 | + writeThread.start(); |
| 244 | + |
| 245 | + Callable<Branch> branchCallable = () -> { |
| 246 | + System.out.println("Thread " + Thread.currentThread().getId() + " entered tree TX"); |
| 247 | + latch.countDown(); |
| 248 | + latch.await(); |
| 249 | + return tree.root().branch("Book"); |
| 250 | + }; |
| 251 | + Branch branch = tree.callInReadTx(branchCallable); |
| 252 | + assertNull(branch); |
| 253 | + |
| 254 | + // And once more to see that read TXs can still be started |
| 255 | + tree.callInReadTx(branchCallable); |
| 256 | + |
| 257 | + readThread.join(); |
| 258 | + assertTrue(readThreadOK.get()); |
| 259 | + writeThread.join(); |
| 260 | + assertNotEquals(0, bookBranchId.get()); |
| 261 | + |
| 262 | + branch = tree.callInReadTx(branchCallable); |
| 263 | + assertNotNull(branch); |
| 264 | + assertEquals(bookBranchId.get(), branch.getId()); |
| 265 | + } |
205 | 266 | }
|
0 commit comments