From 315fa6f3d9c06a4cb41afa66d84e6a57c0f77ef2 Mon Sep 17 00:00:00 2001 From: Brad Fitzpatrick Date: Fri, 26 Aug 2016 09:57:18 -0700 Subject: [PATCH] search: fix describe race For a given DescribeRequest, allow only one describer in flight per blobRef. Fixes #846 Change-Id: Ief42eb568df5eb8dfa5d2e3b2710f3511f9f055e --- pkg/search/describe.go | 29 ++++++++++++++++++++--------- 1 file changed, 20 insertions(+), 9 deletions(-) diff --git a/pkg/search/describe.go b/pkg/search/describe.go index 1148d7a94..ebeea598f 100644 --- a/pkg/search/describe.go +++ b/pkg/search/describe.go @@ -128,8 +128,9 @@ type DescribeRequest struct { sh *Handler mu sync.Mutex // protects following: m MetaMap - done map[blobrefAndDepth]bool // blobref -> true - errs map[string]error // blobref -> error + started map[blobrefAndDepth]bool // blobref -> true + blobDesLock map[blob.Ref]*sync.Mutex + errs map[string]error // blobref -> error resFromRule map[*DescribeRule]map[blob.Ref]bool flatRuleCache []*DescribeRule // flattened once, by flatRules @@ -582,18 +583,28 @@ func (dr *DescribeRequest) Describe(ctx context.Context, br blob.Ref, depth int) } dr.mu.Lock() defer dr.mu.Unlock() - if dr.done == nil { - dr.done = make(map[blobrefAndDepth]bool) + if dr.blobDesLock == nil { + dr.blobDesLock = make(map[blob.Ref]*sync.Mutex) } - doneKey := blobrefAndDepth{br, depth} - if dr.done[doneKey] { + desBlobMu, ok := dr.blobDesLock[br] + if !ok { + desBlobMu = new(sync.Mutex) + dr.blobDesLock[br] = desBlobMu + } + if dr.started == nil { + dr.started = make(map[blobrefAndDepth]bool) + } + key := blobrefAndDepth{br, depth} + if dr.started[key] { return } - dr.done[doneKey] = true + dr.started[key] = true dr.wg.Add(1) go func() { defer dr.wg.Done() - dr.describeReally(ctx, br, depth) + desBlobMu.Lock() + defer desBlobMu.Unlock() + dr.doDescribe(ctx, br, depth) }() } @@ -696,7 +707,7 @@ func (dr *DescribeRequest) addError(br blob.Ref, err error) { dr.errs[br.String()] = err } -func (dr *DescribeRequest) describeReally(ctx context.Context, br blob.Ref, depth int) { +func (dr *DescribeRequest) doDescribe(ctx context.Context, br blob.Ref, depth int) { meta, err := dr.sh.index.GetBlobMeta(ctx, br) if err == os.ErrNotExist { return