@@ -6,6 +6,7 @@ package cache
6
6
7
7
import (
8
8
"context"
9
+ "fmt"
9
10
"sync"
10
11
"time"
11
12
@@ -293,15 +294,10 @@ func (e *readEntry) unrefAndTryRemoveFromMap() {
293
294
}
294
295
295
296
func (e * readEntry ) setReadValue (v * Value ) {
296
- // Add to the cache before taking another ref for readEntry, since the cache
297
- // expects ref=1 when it is called.
298
- //
299
- // TODO(sumeer): if e.refCount > 1, we should consider overriding to ensure
300
- // that it is added as etHot. The common case will be e.refCount = 1, and we
301
- // don't want to acquire e.mu twice, so one way to do this would be relax
302
- // the invariant in shard.Set that requires Value.refs() == 1. Then we can
303
- // do the work under e.mu before calling shard.Set.
304
- e .readShard .shard .set (e .key , v )
297
+ if n := v .refs (); n != 1 {
298
+ panic (fmt .Sprintf ("pebble: Value has already been added to the cache: refs=%d" , n ))
299
+ }
300
+ concurrentRequesters := false
305
301
e .mu .Lock ()
306
302
// Acquire a ref for readEntry, since we are going to remember it in e.mu.v.
307
303
v .acquire ()
@@ -318,8 +314,12 @@ func (e *readEntry) setReadValue(v *Value) {
318
314
// readEntry.waitForReadPermissionOrHandle, and those will also use
319
315
// e.mu.v.
320
316
close (e .mu .ch )
317
+ // e.mu.ch is non-nil only when there were concurrent requesters. NB: we
318
+ // can't read e.refCount here since it is protected by e.readShard.mu.
319
+ concurrentRequesters = true
321
320
}
322
321
e .mu .Unlock ()
322
+ e .readShard .shard .set (e .key , v , concurrentRequesters )
323
323
e .unrefAndTryRemoveFromMap ()
324
324
}
325
325
@@ -368,6 +368,8 @@ func (rh ReadHandle) Valid() bool {
368
368
//
369
369
// The cache takes a reference on the Value and holds it until it is evicted and
370
370
// no longer needed by other readers.
371
+ //
372
+ // REQUIRES: v.refs() == 1
371
373
func (rh ReadHandle ) SetReadValue (v * Value ) {
372
374
rh .entry .setReadValue (v )
373
375
}
0 commit comments