@@ -4,7 +4,7 @@ import path from 'path';
44import fs from 'fs' ;
55import Logger , { LogLevel , StreamHandler } from '@matrixai/logger' ;
66import { withF } from '@matrixai/resources' ;
7- import { errors as locksErrors } from '@matrixai/async-locks' ;
7+ import { Barrier , errors as locksErrors } from '@matrixai/async-locks' ;
88import DB from '@/DB' ;
99import DBTransaction from '@/DBTransaction' ;
1010import * as errors from '@/errors' ;
@@ -260,6 +260,8 @@ describe(DBTransaction.name, () => {
260260 expect ( await db . get ( 'hello' ) ) . toBeUndefined ( ) ;
261261 } ) ;
262262 test ( 'getForUpdate addresses write-skew by promoting gets into same-value puts' , async ( ) => {
263+ // Ensure deterministic concurrency
264+ const barrier = await Barrier . createBarrier ( 2 ) ;
263265 // Snapshot isolation allows write skew anomalies to occur
264266 // A write skew means that 2 transactions concurrently read from overlapping keys
265267 // then make disjoint updates to the keys, that breaks a consistency constraint on those keys
@@ -272,13 +274,15 @@ describe(DBTransaction.name, () => {
272274 const t1 = withF ( [ db . transaction ( ) ] , async ( [ tran ] ) => {
273275 let balance1 = parseInt ( ( await tran . getForUpdate ( 'balance1' ) ) ! ) ;
274276 const balance2 = parseInt ( ( await tran . getForUpdate ( 'balance2' ) ) ! ) ;
277+ await barrier . wait ( ) ;
275278 balance1 -= 100 ;
276279 expect ( balance1 + balance2 ) . toBeGreaterThanOrEqual ( 0 ) ;
277280 await tran . put ( 'balance1' , balance1 . toString ( ) ) ;
278281 } ) ;
279282 const t2 = withF ( [ db . transaction ( ) ] , async ( [ tran ] ) => {
280283 const balance1 = parseInt ( ( await tran . getForUpdate ( 'balance1' ) ) ! ) ;
281284 let balance2 = parseInt ( ( await tran . getForUpdate ( 'balance2' ) ) ! ) ;
285+ await barrier . wait ( ) ;
282286 balance2 -= 100 ;
283287 expect ( balance1 + balance2 ) . toBeGreaterThanOrEqual ( 0 ) ;
284288 await tran . put ( 'balance2' , balance2 . toString ( ) ) ;
@@ -298,16 +302,20 @@ describe(DBTransaction.name, () => {
298302 ) . toBe ( true ) ;
299303 } ) ;
300304 test ( 'locking to prevent thrashing for racing counters' , async ( ) => {
305+ // Ensure deterministic concurrency
306+ const barrier = await Barrier . createBarrier ( 2 ) ;
301307 await db . put ( 'counter' , '0' ) ;
302308 let t1 = withF ( [ db . transaction ( ) ] , async ( [ tran ] ) => {
303309 // Can also use `getForUpdate`, but a conflict exists even for `get`
304310 let counter = parseInt ( ( await tran . get ( 'counter' ) ) ! ) ;
311+ await barrier . wait ( ) ;
305312 counter ++ ;
306313 await tran . put ( 'counter' , counter . toString ( ) ) ;
307314 } ) ;
308315 let t2 = withF ( [ db . transaction ( ) ] , async ( [ tran ] ) => {
309316 // Can also use `getForUpdate`, but a conflict exists even for `get`
310317 let counter = parseInt ( ( await tran . get ( 'counter' ) ) ! ) ;
318+ await barrier . wait ( ) ;
311319 counter ++ ;
312320 await tran . put ( 'counter' , counter . toString ( ) ) ;
313321 } ) ;
0 commit comments