Skip to content

Commit 32cf045

Browse files
committed
Preserve panics in create
In 24e43a4 we fixed deadlocks when the passed create func panics, but we also converted any panic into a returned err. Preserving the panic is in many situations useful.
1 parent 24e43a4 commit 32cf045

File tree

2 files changed

+33
-15
lines changed

2 files changed

+33
-15
lines changed

‎lazycache.go‎

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
package lazycache
22

33
import (
4-
"fmt"
54
"sync"
65

76
"github.com/hashicorp/golang-lru/v2/simplelru"
@@ -122,23 +121,24 @@ func (c *Cache[K, V]) GetOrCreate(key K, create func(key K) (V, error)) (V, bool
122121
c.lru.Add(key, w)
123122
c.mu.Unlock()
124123

124+
isPanic := true
125+
125126
v, err := func() (v V, err error) {
126127
defer func() {
127-
if r := recover(); r != nil {
128-
err = fmt.Errorf("panic: %v", r)
129-
}
130128
w.err = err
131129
w.value = v
132-
w.found = err == nil
130+
w.found = err == nil && !isPanic
133131
close(w.ready)
134132

135-
if err != nil {
133+
if err != nil || isPanic {
136134
v = c.zerov
137135
c.Delete(key)
138136
}
139137
}()
138+
140139
// Create the value with the lock released.
141140
v, err = create(key)
141+
isPanic = false
142142

143143
return
144144
}()

‎lazycache_test.go‎

Lines changed: 27 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -61,17 +61,29 @@ func TestPanic(t *testing.T) {
6161
c := qt.New(t)
6262

6363
cache := New(Options[int, any]{MaxEntries: 1000})
64+
ep := &errorProducer{}
65+
66+
willPanic := func(i int) func() {
67+
return func() {
68+
cache.GetOrCreate(i, func(key int) (any, error) {
69+
ep.Panic(i)
70+
return nil, nil
71+
})
72+
}
73+
}
74+
6475
for i := 0; i < 2; i++ {
65-
_, _, err := cache.GetOrCreate(42, func(key int) (any, error) {
66-
panic("failed1")
67-
})
68-
c.Assert(err, qt.IsNotNil)
69-
c.Assert(err, qt.ErrorMatches, "panic: failed1")
70-
_, _, err = cache.GetOrCreate(i, func(key int) (any, error) {
71-
panic("failed2")
76+
for j := 0; j < 2; j++ {
77+
c.Assert(willPanic(i), qt.PanicMatches, fmt.Sprintf("failed-%d", i))
78+
}
79+
}
80+
81+
for i := 0; i < 2; i++ {
82+
v, _, err := cache.GetOrCreate(i, func(key int) (any, error) {
83+
return key + 2, nil
7284
})
73-
c.Assert(err, qt.IsNotNil)
74-
c.Assert(err, qt.ErrorMatches, "panic: failed2")
85+
c.Assert(err, qt.IsNil)
86+
c.Assert(v, qt.Equals, i+2)
7587
}
7688
}
7789

@@ -461,3 +473,9 @@ func BenchmarkCacheParallel(b *testing.B) {
461473
})
462474
})
463475
}
476+
477+
type errorProducer struct{}
478+
479+
func (e *errorProducer) Panic(i int) {
480+
panic(fmt.Sprintf("failed-%d", i))
481+
}

0 commit comments

Comments
 (0)