88 "errors"
99 "io"
1010 "io/fs"
11+ "runtime"
1112 "sync/atomic"
1213 "testing"
1314 "time"
@@ -61,14 +62,67 @@ func testDB_BasicOperation(t *testing.T, cfg Config) {
6162 assert .Error (t , err )
6263 assert .That (t , errors .Is (err , fs .ErrNotExist ))
6364
64- // create and read should fail after close.
65+ // create, read and compact should fail after close.
6566 db .Close ()
6667
6768 _ , err = db .Read (ctx , newKey ())
6869 assert .Error (t , err )
6970
7071 _ , err = db .Create (ctx , newKey (), time.Time {})
7172 assert .Error (t , err )
73+
74+ err = db .Compact (ctx )
75+ assert .Error (t , err )
76+ }
77+
78+ func TestDB_ConcurrentOperation (t * testing.T ) {
79+ forAllTables (t , testDB_ConcurrentOperation )
80+ }
81+ func testDB_ConcurrentOperation (t * testing.T , cfg Config ) {
82+ cfg .Compaction .MaxLogSize = 1 << 10 // 1KiB
83+
84+ db := newTestDB (t , cfg , nil , nil )
85+ defer db .Close ()
86+
87+ procs := runtime .GOMAXPROCS (- 1 )
88+ keysCh := make (chan []Key , procs )
89+ for range procs {
90+ go func () {
91+ var keys []Key
92+ for i := 0 ; ; i ++ {
93+ // stop when we have ~100 log files and, if not short, compaction has happened
94+ stats , _ , _ := db .Stats ()
95+ if stats .NumLogs >= 100 && (testing .Short () || stats .Compactions > 0 ) {
96+ break
97+ }
98+
99+ keys = append (keys , db .AssertCreate ())
100+
101+ // add about 10% concurrent reads
102+ if mwc .Intn (10 ) == 0 {
103+ db .AssertRead (keys [mwc .Intn (len (keys ))])
104+ }
105+ }
106+ keysCh <- keys
107+ }()
108+ }
109+
110+ // collect all the keys created by the goroutines.
111+ var allKeys []Key
112+ for range procs {
113+ allKeys = append (allKeys , <- keysCh ... )
114+ }
115+
116+ // ensure we can read all the keys back.
117+ for _ , key := range allKeys {
118+ db .AssertRead (key )
119+ }
120+
121+ // ensure we can still read all the keys back after reopen.
122+ db .AssertReopen ()
123+ for _ , key := range allKeys {
124+ db .AssertRead (key )
125+ }
72126}
73127
74128func TestDB_TrashStats (t * testing.T ) {
@@ -420,7 +474,7 @@ func benchmarkDB(b *testing.B, cfg Config) {
420474
421475 db , err := New (ctx , cfg , b .TempDir (), "" , nil , nil , nil )
422476 assert .NoError (b , err )
423- defer db . Close ( )
477+ defer assertClose ( b , db )
424478
425479 b .SetBytes (int64 (size ))
426480 b .ReportAllocs ()
@@ -446,7 +500,7 @@ func benchmarkDB(b *testing.B, cfg Config) {
446500
447501 db , err := New (ctx , cfg , b .TempDir (), "" , nil , nil , nil )
448502 assert .NoError (b , err )
449- defer db . Close ( )
503+ defer assertClose ( b , db )
450504
451505 // write at most ~100MB of keys or 1000 keys, whichever is smaller. this keeps the benchmark
452506 // time reasonable.
0 commit comments