@cryptotaxi247 / kubo / commits / a3d236269

use a single coarse package lock

Brian Tiger Chow committed Jan 13, 2015 at 20:46 UTC a3d236269108d759359109cc9d91922057cd58d3
2 files changed +25 -32
repo/fsrepo/fsrepo.go
+22 -16
@@ -7,6 +7,7 @@ import (
7 "os"
8 "path"
9 "path/filepath"
10 + "sync"
11
12 repo "github.com/jbenet/go-ipfs/repo"
13 common "github.com/jbenet/go-ipfs/repo/common"
@@ -18,6 +19,13 @@ import (
19 )
20
21 var (
22 +
23 + // packageLock must be held to while performing any operation that modifies an
24 + // FSRepo's state field. This includes Init, Open, Close, and Remove.
25 + packageLock sync.Mutex // protects openerCounter and lockfiles
26 + // lockfiles holds references to the Closers that ensure that repos are
27 + // only accessed by one process at a time.
28 + lockfiles map[string]io.Closer
29 // openerCounter prevents the fsrepo from being removed while there exist open
30 // FSRepo handles. It also ensures that the Init is atomic.
31 //
@@ -26,8 +34,6 @@ var (
34 // If an operation is used when repo is Open and the operation does not
35 // change the repo's state, the package lock does not need to be acquired.
36 openerCounter *opener.Counter
29 -
30 - lockfiles map[string]io.Closer
37 )
38
39 func init() {
@@ -61,8 +67,8 @@ func ConfigAt(repoPath string) (*config.Config, error) {
67
68 // Init initializes a new FSRepo at the given path with the provided config.
69 func Init(path string, conf *config.Config) error {
64 - openerCounter.Lock() // lock must be held to ensure atomicity (prevent Removal)
65 - defer openerCounter.Unlock()
70 + packageLock.Lock() // lock must be held to ensure atomicity (prevent Removal)
71 + defer packageLock.Unlock()
72
73 if isInitializedUnsynced(path) {
74 return nil
@@ -79,8 +85,8 @@ func Init(path string, conf *config.Config) error {
85
86 // Remove recursively removes the FSRepo at |path|.
87 func Remove(path string) error {
82 - openerCounter.Lock()
83 - defer openerCounter.Unlock()
88 + packageLock.Lock()
89 + defer packageLock.Unlock()
90 if openerCounter.NumOpeners(path) != 0 {
91 return errors.New("repo in use")
92 }
@@ -90,16 +96,16 @@ func Remove(path string) error {
96 // LockedByOtherProcess returns true if the FSRepo is locked by another
97 // process. If true, then the repo cannot be opened by this process.
98 func LockedByOtherProcess(repoPath string) bool {
93 - openerCounter.Lock()
94 - defer openerCounter.Unlock()
99 + packageLock.Lock()
100 + defer packageLock.Unlock()
101 // NB: the lock is only held when repos are Open
102 return lockfile.Locked(repoPath) && openerCounter.NumOpeners(repoPath) == 0
103 }
104
105 // Open returns an error if the repo is not initialized.
106 func (r *FSRepo) Open() error {
101 - openerCounter.Lock()
102 - defer openerCounter.Unlock()
107 + packageLock.Lock()
108 + defer packageLock.Unlock()
109 if r.state != unopened {
110 return debugerror.Errorf("repo is %s", r.state)
111 }
@@ -232,8 +238,8 @@ func (r *FSRepo) SetConfigKey(key string, value interface{}) error {
238
239 // Close closes the FSRepo, releasing held resources.
240 func (r *FSRepo) Close() error {
235 - openerCounter.Lock()
236 - defer openerCounter.Unlock()
241 + packageLock.Lock()
242 + defer packageLock.Unlock()
243 if r.state != opened {
244 return debugerror.Errorf("repo is %s", r.state)
245 }
@@ -245,8 +251,8 @@ var _ repo.Repo = &FSRepo{}
251
252 // IsInitialized returns true if the repo is initialized at provided |path|.
253 func IsInitialized(path string) bool {
248 - openerCounter.Lock()
249 - defer openerCounter.Unlock()
254 + packageLock.Lock()
255 + defer packageLock.Unlock()
256 return isInitializedUnsynced(path)
257 }
258
@@ -279,7 +285,7 @@ func initCheckDir(path string) error {
285 }
286
287 // transitionToOpened manages the state transition to |opened|. Caller must hold
282 -// openerCounter lock.
288 +// the package mutex.
289 func transitionToOpened(r *FSRepo) error {
290 r.state = opened
291 if countBefore := openerCounter.NumOpeners(r.path); countBefore == 0 { // #first
@@ -293,7 +299,7 @@ func transitionToOpened(r *FSRepo) error {
299 }
300
301 // transitionToClosed manages the state transition to |closed|. Caller must
296 -// hold openerCounter lock.
302 +// hold the package mutex.
303 func transitionToClosed(r *FSRepo) error {
304 r.state = closed
305 if err := openerCounter.RemoveOpener(r.path); err != nil {
repo/fsrepo/opener/counter.go
+3 -16
@@ -1,13 +1,10 @@
1 package fsrepo
2
3 -import (
4 - "path"
5 - "sync"
6 -)
3 +import "path"
4 +
5 +// TODO this could be made into something more generic.
6
7 type Counter struct {
9 - // lock protects repos
10 - lock sync.Mutex
8 // repos maps repo paths to the number of openers holding an FSRepo handle
9 // to it
10 repos map[string]int
@@ -19,16 +16,6 @@ func NewCounter() *Counter {
16 }
17 }
18
22 -// Lock must be held to while performing any operation that modifies an
23 -// FSRepo's state field. This includes Init, Open, Close, and Remove.
24 -func (l *Counter) Lock() {
25 - l.lock.Lock()
26 -}
27 -
28 -func (l *Counter) Unlock() {
29 - l.lock.Unlock()
30 -}
31 -
19 // NumOpeners returns the number of FSRepos holding a handle to the repo at
20 // this path. This method is not thread-safe. The caller must have this object
21 // locked.