Skip to content

[BUG]: cachedFetcher.update() blocks token reads during cache refresh #1547

@NETIZEN-11

Description

@NETIZEN-11

👾 Description

The cachedFetcher.update() function in token/services/selector/sherdlock/fetcher.go holds a write lock (f.mu.Lock()) for the
entire duration of the database query when refreshing the token cache. This causes all concurrent token read operations to block
during the refresh, creating a performance bottleneck.

Severity: Medium

Type: Concurrency / Performance Bug

🛠️ Steps to reproduce

  1. Set up a Fabric Token SDK environment with sherdlock selector
  2. Configure a slow database or add artificial delay to SpendableTokensIteratorBy
  3. Trigger a cache refresh (wait for freshnessInterval to expire or set maxQueriesBeforeRefresh to low value)
  4. While cache is refreshing, attempt token read operations via UnspentTokensIteratorBy
  5. Observe that read operations block until the DB query completes

📋 Logs and Screenshots

No response

🌐 Network Environment

Other

📦 Fabric Token SDK Version

v0.10.x or latest main

🐹 Go Version

1.24

💻 Operating System

Windows (WSL2)

➕ Additional context

Root Cause Location: token/services/selector/sherdlock/fetcher.go - update() function

Affected Code Pattern:

func (f *cachedFetcher) update(ctx context.Context) {
    f.mu.Lock()
    defer f.mu.Unlock()  // Lock held during slow DB call
    // ...
    it, err := f.tokenDB.SpendableTokensIteratorBy(ctx, "", "")  // Blocks all readers
}

Proposed Fix: Release lock before DB call, re-acquire and re-check staleness after, then update cache atomically.

Related PR: #1535

Impact: Performance degradation onlyno correctness issue. Token operations eventually complete, but latency spikes during cache
refresh.

Labels: bug, performance, concurrency, sherdlock

Metadata

Metadata

Assignees

Labels

bugSomething isn't working

Type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions