TestDB_Close_ConcurrentCalls tests concurrent close calls Note: This test may reveal race conditions in the release() method when called concurrently. In practice, applications should not call Close() concurrently from multiple goroutines.
(t *testing.T)
| 1113 | // Note: This test may reveal race conditions in the release() method when called concurrently. |
| 1114 | // In practice, applications should not call Close() concurrently from multiple goroutines. |
| 1115 | func TestDB_Close_ConcurrentCalls(t *testing.T) { |
| 1116 | opts := DefaultOptions |
| 1117 | opts.Dir = filepath.Join(t.TempDir(), "test-close-concurrent") |
| 1118 | defer func() { _ = os.RemoveAll(opts.Dir) }() |
| 1119 | |
| 1120 | db, err := Open(opts) |
| 1121 | require.NoError(t, err) |
| 1122 | require.NotNil(t, db) |
| 1123 | |
| 1124 | bucket := "test_bucket" |
| 1125 | err = db.Update(func(tx *Tx) error { |
| 1126 | return tx.NewBucket(DataStructureBTree, bucket) |
| 1127 | }) |
| 1128 | require.NoError(t, err) |
| 1129 | |
| 1130 | // Call Close() concurrently from multiple goroutines |
| 1131 | // Note: This is testing the safety of concurrent Close() calls, |
| 1132 | // though in practice this should be avoided |
| 1133 | numGoroutines := 5 |
| 1134 | var wg sync.WaitGroup |
| 1135 | errors := make([]error, numGoroutines) |
| 1136 | |
| 1137 | wg.Add(numGoroutines) |
| 1138 | for i := 0; i < numGoroutines; i++ { |
| 1139 | go func(idx int) { |
| 1140 | defer wg.Done() |
| 1141 | // Add small delay to reduce contention |
| 1142 | time.Sleep(time.Duration(idx) * 10 * time.Millisecond) |
| 1143 | errors[idx] = db.Close() |
| 1144 | }(i) |
| 1145 | } |
| 1146 | |
| 1147 | wg.Wait() |
| 1148 | |
| 1149 | // At least one close should succeed or return ErrDBClosed |
| 1150 | hasSuccess := false |
| 1151 | hasClosedErr := false |
| 1152 | |
| 1153 | for _, err := range errors { |
| 1154 | switch err { |
| 1155 | case nil: |
| 1156 | hasSuccess = true |
| 1157 | case ErrDBClosed: |
| 1158 | hasClosedErr = true |
| 1159 | default: |
| 1160 | t.Logf("Unexpected error: %v", err) |
| 1161 | } |
| 1162 | } |
| 1163 | |
| 1164 | // Either we got a success or all got ErrDBClosed |
| 1165 | require.True(t, hasSuccess || hasClosedErr, "Should have at least one successful close or ErrDBClosed") |
| 1166 | |
| 1167 | // Database should be closed |
| 1168 | require.True(t, db.IsClose()) |
| 1169 | require.True(t, db.statusMgr.isClosed()) |
| 1170 | } |
| 1171 | |
| 1172 | // TestDB_Close_IdempotentCalls tests that multiple sequential close calls are safe |