Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add concurrency to tag Lookup #3589

Closed
wants to merge 1 commit into from
Closed

Conversation

bainsy88
Copy link
Contributor

This was to address performance issues when deleting images in repos with a large number of tagstore

#3525

Signed-off-by: jack-baines jack.baines@uk.ibm.com

This was to address performance issues when deleting images in repos with a large number of tagstore

distribution#3525

Signed-off-by: jack-baines <jack.baines@uk.ibm.com>
@codecov-commenter
Copy link

codecov-commenter commented Feb 17, 2022

Codecov Report

Merging #3589 (76c29bf) into main (b609265) will increase coverage by 0.22%.
The diff coverage is n/a.

Impacted file tree graph

@@            Coverage Diff             @@
##             main    #3589      +/-   ##
==========================================
+ Coverage   56.33%   56.56%   +0.22%     
==========================================
  Files         101      101              
  Lines        7313     7354      +41     
==========================================
+ Hits         4120     4160      +40     
- Misses       2536     2537       +1     
  Partials      657      657              
Impacted Files Coverage Δ
...ribution/distribution/registry/storage/tagstore.go 81.63% <0.00%> (+6.16%) ⬆️

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update a4d9db5...76c29bf. Read the comment docs.

@bainsy88
Copy link
Contributor Author

bainsy88 commented Feb 17, 2022

This PR fixes 1 of the 2 things described in the issue which is that we have to look up every tag in the repo to detect whether it matches the digest being deleted and needs to be untagged and previously this was done one tag at a time.

The 2nd bit has much lower impact from manual testing and is that once we have identified which tags match the digest we untag them sequentially. My view was this second change can be done standalone at a later date.

@bainsy88
Copy link
Contributor Author

My testing on a a relatively small repo showed a 3x improvement so deleting an image in a repo with 500 tags took ~6s down from ~18s.

@bainsy88
Copy link
Contributor Author

Final thing to point out is that I have hardcoded the concurrency limit to 10 obviously may be some advantages to that being configurable but wasn't entirely sure on how that could be achieved, so if that is deemed required would appreciate a pointer of a similar code that gets config into something like the tag store.

Copy link
Member

@milosgajdos milosgajdos left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, this looks good. I have a few nits if you don't mind :)

go func() {
wg.Wait()
close(tagChan)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can we remove this empty line?

Comment on lines +212 to +225
read:
for {
select {
case err, workRemaining := <-errChan:
if !workRemaining {
break read
}
cancel()
return nil, err
case tag, workRemaining := <-tagChan:
if !workRemaining {
close(errChan)
break read
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can we move this code into a goroutine (maybe allocate a chan and wait for it to finish?); it would be great to get rid of the break label 🤔

Copy link
Collaborator

@wy65701436 wy65701436 Mar 21, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1 for use gorountine,

done := make(chan bool, 1)
go func() {
		defer func() {
			done <- true
		}()
                for {
		                select {
		                case err, workRemaining := <-errChan:
			                if !workRemaining {
				                break read
			                }
			                cancel()
			                return nil, err
		                case tag, workRemaining := <-tagChan:
			                if !workRemaining {
				                close(errChan)
				                break read
			                }
			                tags = append(tags, tag)
		                }
                
	                }
}
<-done

@@ -149,26 +150,82 @@ func (ts *tagStore) Lookup(ctx context.Context, desc distribution.Descriptor) ([
return nil, err
}

limiter := make(chan struct{}, 10)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can we make 10 a constant?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

and why chooses 10 or make it configurable just by env is enough?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah I'm all for making this configurable, but we could also have a fallthrough default value which should be a constant

@milosgajdos
Copy link
Member

Just wondering since we are addressing these slow deletes...this code in S3 delete driver could use a bit of TLC, too. If the repo contains a lot of data, we end up growing s3Objects slice into huge size; the actual deletes are batched, though that is of little help since we must first go through all contents of the repo.

name: ts.repository.Named().Name(),
tag: tag,
}
limiter <- struct{}{}
Copy link
Collaborator

@wy65701436 wy65701436 Mar 21, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd like we can have a struct to wrap chan to provide public methods, that could be easy to understand.

My suggestion:

func NewWorkerPool(size int32) *WorkerPool {
	wp := &WorkerPool{}
	wp.queue = make(chan struct{}, size)
	return wp
}

type WorkerPool struct {
	queue chan struct{}
}

func (w *WorkerPool) GetWorker() {
	w.queue <- struct{}{}
}

func (w *WorkerPool) ReleaseWorker() {
	<-w.queue
}

@tiny1990
Copy link

LGTM...

800TB files in ceph ,its' hard to delete.
patch it by this pr

delete file with 3TB / min

@Antiarchitect
Copy link

Is there any news on this?

Antiarchitect added a commit to Enapter/distribution that referenced this pull request Jan 25, 2023
Antiarchitect added a commit to Enapter/distribution that referenced this pull request Jan 25, 2023
Based on distribution#3589

Signed-off-by: Andrey Voronkov <voronkovaa@gmail.com>
Antiarchitect added a commit to Enapter/distribution that referenced this pull request Jan 29, 2023
Based on distribution#3589

Signed-off-by: Andrey Voronkov <voronkovaa@gmail.com>
@milosgajdos
Copy link
Member

Ping @bainsy88

Antiarchitect added a commit to Enapter/distribution that referenced this pull request Feb 13, 2023
Based on distribution#3589

Signed-off-by: Andrey Voronkov <voronkovaa@gmail.com>
Antiarchitect added a commit to Antiarchitect/distribution that referenced this pull request May 1, 2023
Based on distribution#3589

Signed-off-by: Andrey Voronkov <voronkovaa@gmail.com>
@davidspek
Copy link
Collaborator

Friendly ping @bainsy88

@milosgajdos
Copy link
Member

There is also #3890 which is more comprehensive.

We need to decide which one to keep focussing on.

@davidspek
Copy link
Collaborator

davidspek commented Aug 16, 2023

If #3890 is more comprehensive and more (recently) active then I’d say it’s safe to close this PR (also given that the author hasn’t responded to the reviews). As always, feel free to re-open this PR.

@davidspek davidspek closed this Aug 16, 2023
Antiarchitect pushed a commit to Antiarchitect/distribution that referenced this pull request Apr 17, 2024
Based on distribution#3589

Signed-off-by: Andrey Voronkov <andrey.voronkov@sbermarket.ru>
Antiarchitect pushed a commit to Antiarchitect/distribution that referenced this pull request Apr 17, 2024
Based on distribution#3589

Signed-off-by: Andrey Voronkov <andrey.voronkov@sbermarket.ru>
Antiarchitect pushed a commit to Antiarchitect/distribution that referenced this pull request Apr 17, 2024
Based on distribution#3589

Signed-off-by: Andrey Voronkov <=>
Antiarchitect added a commit to Antiarchitect/distribution that referenced this pull request Apr 17, 2024
Based on distribution#3589

Signed-off-by: Andrey Voronkov <voronkovaa@gmail.com>
Antiarchitect added a commit to Antiarchitect/distribution that referenced this pull request Apr 17, 2024
    Based on distribution#3589

Signed-off-by: Andrey Voronkov <voronkovaa@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

7 participants