Skip to content

Commit

Permalink
fix: async warmup will be blocked by state lock (#33687)
Browse files Browse the repository at this point in the history
issue: #33685
pr: #33686

Signed-off-by: chyezh <chyezh@outlook.com>
  • Loading branch information
chyezh committed Jun 7, 2024
1 parent 26db471 commit 93348af
Show file tree
Hide file tree
Showing 3 changed files with 32 additions and 0 deletions.
4 changes: 4 additions & 0 deletions internal/querynodev2/segments/segment.go
Original file line number Diff line number Diff line change
Expand Up @@ -1379,6 +1379,10 @@ func (s *LocalSegment) WarmupChunkCache(ctx context.Context, fieldID int64) {
}).Await()
case "async":
GetWarmupPool().Submit(func() (any, error) {
// bad implemtation, warmup is async at another goroutine and hold the rlock.
// the state transition of segment in segment loader will blocked.
// add a waiter to avoid it.
s.ptrLock.BlockUntilDataLoadedOrReleased()
if !s.ptrLock.RLockIf(state.IsNotReleased) {
return nil, nil
}
Expand Down
10 changes: 10 additions & 0 deletions internal/querynodev2/segments/state/load_state_lock.go
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,16 @@ func (ls *LoadStateLock) StartReleaseAll() (g LoadStateLockGuard) {
}
}

// blockUntilDataLoadedOrReleased blocks until the segment is loaded or released.
func (ls *LoadStateLock) BlockUntilDataLoadedOrReleased() {
ls.cv.L.Lock()
defer ls.cv.L.Unlock()

for ls.state != LoadStateDataLoaded && ls.state != LoadStateReleased {
ls.cv.Wait()
}
}

// waitUntilCanReleaseData waits until segment is release data able.
func (ls *LoadStateLock) waitUntilCanReleaseData() {
state := ls.state
Expand Down
18 changes: 18 additions & 0 deletions internal/querynodev2/segments/state/load_state_lock_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,24 @@ func TestStartReleaseData(t *testing.T) {
assert.Equal(t, LoadStateOnlyMeta, l.state)
}

func TestBlockUntilDataLoadedOrReleased(t *testing.T) {
l := NewLoadStateLock(LoadStateOnlyMeta)
ch := make(chan struct{})
go func() {
l.BlockUntilDataLoadedOrReleased()
close(ch)
}()
select {
case <-ch:
t.Errorf("should be blocked")
case <-time.After(10 * time.Millisecond):
}

g, _ := l.StartLoadData()
g.Done(nil)
<-ch
}

func TestStartReleaseAll(t *testing.T) {
l := NewLoadStateLock(LoadStateOnlyMeta)
// Test Release All, nothing to do on only meta.
Expand Down

0 comments on commit 93348af

Please sign in to comment.