content/local/locks.go

    基于ref的锁,ref可以是image的一个layer或image manifest文件

    这是tryLock的唯一入口,获取writer的函数

    1. func (s *store) Writer(ctx context.Context, opts ...content.WriterOpt) (content.Writer, error) {
    2. var wOpts content.WriterOpts
    3. for _, opt := range opts {
    4. if err := opt(&wOpts); err != nil {
    5. return nil, err
    6. }
    7. }
    8. // TODO(AkihiroSuda): we could create a random string or one calculated based on the context
    9. // https://github.com/containerd/containerd/issues/2129#issuecomment-380255019
    10. if wOpts.Ref == "" {
    11. return nil, errors.Wrap(errdefs.ErrInvalidArgument, "ref must not be empty")
    12. }
    13. var lockErr error
    14. for count := uint64(0); count < 10; count++ {
    15. if err := tryLock(wOpts.Ref); err != nil {
    16. if !errdefs.IsUnavailable(err) {
    17. return nil, err
    18. }
    19. lockErr = err
    20. } else {
    21. lockErr = nil
    22. break
    23. }
    24. time.Sleep(time.Millisecond * time.Duration(rand.Intn(1<<count)))
    25. }
    26. if lockErr != nil {
    27. return nil, lockErr
    28. }
    29. w, err := s.writer(ctx, wOpts.Ref, wOpts.Desc.Size, wOpts.Desc.Digest)
    30. if err != nil {
    31. unlock(wOpts.Ref)
    32. return nil, err
    33. }
    34. return w, nil // lock is now held by w.
    35. }