Skip to content

Commit 26dc1bc

Browse files
authored
Merge pull request #20483 from apullo777/store-demux-watcher
cache: make store a normal demux watcher to reduce lock contention
2 parents d006be4 + 352fd4e commit 26dc1bc

File tree

1 file changed

+58
-18
lines changed

1 file changed

+58
-18
lines changed

cache/cache.go

Lines changed: 58 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ func New(client *clientv3.Client, prefix string, opts ...Option) (*Cache, error)
7777
cache.waitGroup.Add(1)
7878
go func() {
7979
defer cache.waitGroup.Done()
80-
cache.getWatchLoop(internalCtx)
80+
cache.getWatchLoop()
8181
}()
8282

8383
return cache, nil
@@ -202,14 +202,15 @@ func (c *Cache) Close() {
202202
c.waitGroup.Wait()
203203
}
204204

205-
func (c *Cache) getWatchLoop(ctx context.Context) {
205+
func (c *Cache) getWatchLoop() {
206206
cfg := defaultConfig()
207+
ctx := c.internalCtx
207208
backoff := cfg.InitialBackoff
208209
for {
209210
if err := ctx.Err(); err != nil {
210211
return
211212
}
212-
if err := c.getWatch(ctx); err != nil {
213+
if err := c.getWatch(); err != nil {
213214
fmt.Printf("getWatch failed, will retry after %v: %v\n", backoff, err)
214215
}
215216
select {
@@ -220,12 +221,12 @@ func (c *Cache) getWatchLoop(ctx context.Context) {
220221
}
221222
}
222223

223-
func (c *Cache) getWatch(ctx context.Context) error {
224-
getResp, err := c.get(ctx)
224+
func (c *Cache) getWatch() error {
225+
getResp, err := c.get(c.internalCtx)
225226
if err != nil {
226227
return err
227228
}
228-
return c.watch(ctx, getResp.Header.Revision+1)
229+
return c.watch(getResp.Header.Revision + 1)
229230
}
230231

231232
func (c *Cache) get(ctx context.Context) (*clientv3.GetResponse, error) {
@@ -237,36 +238,75 @@ func (c *Cache) get(ctx context.Context) (*clientv3.GetResponse, error) {
237238
return resp, nil
238239
}
239240

240-
func (c *Cache) watch(ctx context.Context, rev int64) error {
241+
func (c *Cache) watch(rev int64) error {
241242
readyOnce := sync.Once{}
242243
for {
244+
storeW := newWatcher(c.cfg.PerWatcherBufferSize, nil)
245+
c.demux.Register(storeW, rev)
246+
applyErr := make(chan error, 1)
247+
c.waitGroup.Add(1)
248+
go func() {
249+
defer c.waitGroup.Done()
250+
if err := c.applyStorage(storeW); err != nil {
251+
applyErr <- err
252+
}
253+
close(applyErr)
254+
}()
255+
243256
watchCh := c.watcher.Watch(
244-
ctx,
257+
c.internalCtx,
245258
c.prefix,
246259
clientv3.WithPrefix(),
247260
clientv3.WithRev(rev),
248261
clientv3.WithProgressNotify(),
249262
clientv3.WithCreatedNotify(),
250263
)
251264

252-
for resp := range watchCh {
253-
readyOnce.Do(func() { c.ready.Set() })
254-
if err := resp.Err(); err != nil {
255-
c.ready.Reset()
256-
c.demux.Purge()
265+
err := c.watchEvents(watchCh, applyErr, &readyOnce)
266+
c.demux.Unregister(storeW)
267+
268+
if err != nil {
269+
return err
270+
}
271+
}
272+
}
273+
274+
func (c *Cache) applyStorage(storeW *watcher) error {
275+
for {
276+
select {
277+
case <-c.internalCtx.Done():
278+
return nil
279+
case events, ok := <-storeW.eventQueue:
280+
if !ok {
281+
return nil
282+
}
283+
if err := c.store.Apply(events); err != nil {
257284
return err
258285
}
286+
}
287+
}
288+
}
259289

260-
if err := c.store.Apply(resp.Events); err != nil {
290+
func (c *Cache) watchEvents(watchCh clientv3.WatchChan, applyErr <-chan error, readyOnce *sync.Once) error {
291+
for {
292+
select {
293+
case <-c.internalCtx.Done():
294+
return c.internalCtx.Err()
295+
case resp, ok := <-watchCh:
296+
if !ok {
297+
return nil
298+
}
299+
readyOnce.Do(func() { c.ready.Set() })
300+
if err := resp.Err(); err != nil {
261301
c.ready.Reset()
262302
c.demux.Purge()
263303
return err
264304
}
265305
c.demux.Broadcast(resp.Events)
266-
}
267-
268-
if ctx.Err() != nil {
269-
return ctx.Err()
306+
case err := <-applyErr:
307+
c.ready.Reset()
308+
c.demux.Purge()
309+
return err
270310
}
271311
}
272312
}

0 commit comments

Comments
 (0)