Skip to content

Commit f06c01d

Browse files
committed
bboltcachestorage: delete links outside of cursor
The `emptyBranchWithParents` method could accidentally leave link entries that shouldn't exist. When finding these links, deleting during the iteration can sometimes cause the cursor to jump entries that should be deleted. This changes the code path to delete the links outside of the iteration to avoid this. This is caused by a long-standing bug in bolt that can't be fixed easily. See etcd-io/bbolt#611 for details. Signed-off-by: Jonathan A. Sternberg <[email protected]>
1 parent 449856f commit f06c01d

File tree

1 file changed

+10
-1
lines changed

1 file changed

+10
-1
lines changed

solver/bboltcachestorage/storage.go

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -267,19 +267,28 @@ func (s *Store) emptyBranchWithParents(tx *bolt.Tx, id []byte) error {
267267
if backlinks := tx.Bucket([]byte(backlinksBucket)).Bucket(id); backlinks != nil {
268268
if err := backlinks.ForEach(func(k, v []byte) error {
269269
if subLinks := tx.Bucket([]byte(linksBucket)).Bucket(k); subLinks != nil {
270+
// Perform deletion outside of the iteration.
271+
// https://github.com/etcd-io/bbolt/pull/611
272+
var toDelete []string
270273
if err := subLinks.ForEach(func(k, v []byte) error {
271274
parts := bytes.Split(k, []byte("@"))
272275
if len(parts) != 2 {
273276
return errors.Errorf("invalid key %s", k)
274277
}
275278
if bytes.Equal(id, parts[1]) {
276-
return subLinks.Delete(k)
279+
toDelete = append(toDelete, string(k))
277280
}
278281
return nil
279282
}); err != nil {
280283
return err
281284
}
282285

286+
for _, k := range toDelete {
287+
if err := subLinks.Delete([]byte(k)); err != nil {
288+
return err
289+
}
290+
}
291+
283292
if isEmptyBucket(subLinks) {
284293
if subResult := tx.Bucket([]byte(resultBucket)).Bucket(k); isEmptyBucket(subResult) {
285294
if err := tx.Bucket([]byte(linksBucket)).DeleteBucket(k); err != nil {

0 commit comments

Comments
 (0)