Skip to content

Commit d9496d9

Browse files
authored
[26.02] Allows inconsistent reads in concurrent cache during shutdown
1 parent 077f30e commit d9496d9

2 files changed

Lines changed: 33 additions & 10 deletions

File tree

core/concurrent_cache/concurrent_cache.go

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -218,8 +218,10 @@ func Lock(ctx context.Context, queries ...[]Subquery) (results []Result, unlocke
218218

219219
roots := make([][]int, len(queries))
220220
cachesPresent := make(map[resource]struct{}, resourceCount)
221+
// if there are no consistent locks, we don't add the root lock
222+
hasConsistentLocks := false
221223
// phase 1, requires no locks, check errors, dedupe, and build trees
222-
if err = assembleQueries(queries, roots, cachesPresent); err != nil {
224+
if hasConsistentLocks, err = assembleQueries(queries, roots, cachesPresent); err != nil {
223225
return nil, func() {}, err
224226
}
225227

@@ -229,30 +231,34 @@ func Lock(ctx context.Context, queries ...[]Subquery) (results []Result, unlocke
229231
}
230232

231233
// phase 3, takes per-resource locks
232-
merged := mergeQueries(queries)
234+
merged := mergeQueries(queries, hasConsistentLocks)
233235
results, unlocker, err = lockQuery(merged, len(queries))
234236
if err == nil && ctx.Err() != nil {
235237
err = ctx.Err()
236238
}
237239
return results, unlocker, err
238240
}
239241

240-
func assembleQueries(queries [][]Subquery, roots [][]int, cachesPresent map[resource]struct{}) error {
242+
func assembleQueries(queries [][]Subquery, roots [][]int, cachesPresent map[resource]struct{}) (bool, error) {
243+
hasConsistentLocks := false
241244
for i, q := range queries {
242245
if err := checkError(q); err != nil {
243-
return err
246+
return false, err
244247
}
245248
ri, err := dedupe(q)
246249
if err != nil {
247-
return err
250+
return false, err
248251
}
249252
for _, sq := range q {
250253
cachesPresent[sq.res] = struct{}{}
254+
if sq.op != list && sq.op != inconsistentRead {
255+
hasConsistentLocks = true
256+
}
251257
}
252258
queries[i], roots[i] = buildTrees(ri, q)
253259
}
254260

255-
return nil
261+
return hasConsistentLocks, nil
256262
}
257263

258264
func lockCachesAndFillInIDs(queries [][]Subquery, roots [][]int, cachesPresent map[resource]struct{}) error {
@@ -486,14 +492,16 @@ func fillInIDs(root int, query []Subquery) error {
486492
return nil
487493
}
488494

489-
func mergeQueries(queries [][]Subquery) []Subquery {
495+
func mergeQueries(queries [][]Subquery, hasConsistentLocks bool) []Subquery {
490496
length := 1
491497
for _, q := range queries {
492498
length += len(q)
493499
}
494500
merged := make([]Subquery, 0, length)
495-
// always add implied read root, if write root is present it will take precedence
496-
merged = append(merged, Subquery{res: root, op: read, id: "."})
501+
// if there are consistent locks, we need to add the root lock to block during shutdown. Inconsistent reads are still allowed.
502+
if hasConsistentLocks {
503+
merged = append(merged, Subquery{res: root, op: read, id: "."})
504+
}
497505
for i, q := range queries {
498506
for j := range q {
499507
q[j].result = i

core/concurrent_cache/concurrent_cache_test.go

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -226,7 +226,7 @@ func TestMergeQueries(t *testing.T) {
226226
queries = append(queries, q)
227227
}
228228

229-
merged := mergeQueries(queries)
229+
merged := mergeQueries(queries, true)
230230
assert.Len(t, merged, 14)
231231
})
232232
}
@@ -1041,3 +1041,18 @@ func TestCheckDependency(t *testing.T) {
10411041
})
10421042
}
10431043
}
1044+
1045+
// TestAllowInconsistentReadWithRootLock tests that inconsistent reads and lists can occur while the root lock is held.
1046+
func TestAllowInconsistentReadWithRootLock(t *testing.T) {
1047+
initCaches()
1048+
1049+
_, unlocker, err := Lock(context.Background(), Query(LockCache()))
1050+
defer unlocker()
1051+
1052+
assert.NoError(t, err)
1053+
results, unlocker2, err := Lock(context.Background(), Query(InconsistentReadBackend("backend1"), ListVolumes()))
1054+
defer unlocker2()
1055+
assert.NoError(t, err)
1056+
assert.NotNil(t, results[0].Backend.Read)
1057+
assert.NotEmpty(t, results[0].Volumes)
1058+
}

0 commit comments

Comments
 (0)