File: mutex.go

package info (click to toggle)
golang-github-juju-mutex 2.0.0-1
  • links: PTS, VCS
  • area: main
  • in suites: bookworm, sid, trixie
  • size: 148 kB
  • sloc: makefile: 18
file content (92 lines) | stat: -rw-r--r-- 2,493 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
// Copyright 2016 Canonical Ltd.
// Licensed under the LGPLv3, see LICENCE file for details.

package mutex

import (
	"regexp"
	"time"

	"github.com/juju/errors"
)

var (
	validName = regexp.MustCompile("^[a-zA-Z][a-zA-Z0-9-]*$")
)

// Releaser defines the Release method that is the only thing that can be done
// to a acquired mutex.
type Releaser interface {
	// Release releases the mutex. Release may be called multiple times, but
	// only the first call will release this instance of the mutex. Release is
	// unable to release the mutex successfully it will call panic to forcibly
	// release the mutex.
	Release()
}

// Clock provides an interface for dealing with clocks.
type Clock interface {
	// After waits for the duration to elapse and then sends the
	// current time on the returned channel.
	After(time.Duration) <-chan time.Time

	// Now returns the current clock time.
	Now() time.Time
}

// Spec defines the name of the mutex and behaviour of the Acquire function.
type Spec struct {
	// Name is required, and must start with a letter and contain at most
	// 40 letters, numbers or dashes.
	Name string

	// Clock must be provided and is exposed for testing purposes.
	Clock Clock

	// Delay defines how often to check for lock acquisition, for
	// compatibility code that requires polling.
	Delay time.Duration

	// Timeout allows the caller to specify how long to wait. If Timeout
	// is zero, then the call will block forever.
	Timeout time.Duration

	// Cancel if signalled will cause the Acquire method to return with ErrCancelled.
	Cancel <-chan struct{}
}

// Acquire will attempt to acquire the named mutex. If the Timout value
// is hit, ErrTimeout is returned. If the Cancel channel is signalled,
// ErrCancelled is returned.
func Acquire(spec Spec) (Releaser, error) {
	if err := spec.Validate(); err != nil {
		return nil, errors.Trace(err)
	}

	var timeout <-chan time.Time
	if spec.Timeout > 0 {
		timeout = spec.Clock.After(spec.Timeout)
	}

	return acquire(spec, timeout)
}

// Validate checks the attributes of Spec for validity.
func (s *Spec) Validate() error {
	if len(s.Name) > 40 {
		return errors.NotValidf("Name longer than 40 characters")
	}
	if !validName.MatchString(s.Name) {
		return errors.NotValidf("Name %q", s.Name)
	}
	if s.Clock == nil {
		return errors.NotValidf("missing Clock")
	}
	if s.Delay <= 0 {
		return errors.NotValidf("non positive Delay")
	}
	if s.Timeout < 0 {
		return errors.NotValidf("negative Timeout")
	}
	return nil
}