refactor(fsrepo): move OpenerCounter

This commit is contained in:
Brian Tiger Chow 2015-01-13 00:34:51 -08:00
parent 97b865ff6f
commit 89afdabb7e
2 changed files with 26 additions and 25 deletions

View File

@ -10,23 +10,24 @@ import (
repo "github.com/jbenet/go-ipfs/repo"
common "github.com/jbenet/go-ipfs/repo/common"
config "github.com/jbenet/go-ipfs/repo/config"
opener "github.com/jbenet/go-ipfs/repo/fsrepo/opener"
util "github.com/jbenet/go-ipfs/util"
debugerror "github.com/jbenet/go-ipfs/util/debugerror"
)
var (
// pkgLock prevents the fsrepo from being removed while there exist open
// openerCounter prevents the fsrepo from being removed while there exist open
// FSRepo handles. It also ensures that the Init is atomic.
//
// packageLock also protects numOpenedRepos
//
// If an operation is used when repo is Open and the operation does not
// change the repo's state, the package lock does not need to be acquired.
pkgLock *packageLock
openerCounter *opener.Counter
)
func init() {
pkgLock = makePackageLock()
openerCounter = opener.NewCounter()
}
// FSRepo represents an IPFS FileSystem Repo. It is not thread-safe.
@ -47,8 +48,8 @@ func At(path string) *FSRepo {
// Init initializes a new FSRepo at the given path with the provided config.
func Init(path string, conf *config.Config) error {
pkgLock.Lock() // lock must be held to ensure atomicity (prevent Removal)
defer pkgLock.Unlock()
openerCounter.Lock() // lock must be held to ensure atomicity (prevent Removal)
defer openerCounter.Unlock()
if isInitializedUnsynced(path) {
return nil
@ -65,9 +66,9 @@ func Init(path string, conf *config.Config) error {
// Remove recursively removes the FSRepo at |path|.
func Remove(path string) error {
pkgLock.Lock()
defer pkgLock.Unlock()
if pkgLock.NumOpeners(path) != 0 {
openerCounter.Lock()
defer openerCounter.Unlock()
if openerCounter.NumOpeners(path) != 0 {
return errors.New("repo in use")
}
return os.RemoveAll(path)
@ -75,8 +76,8 @@ func Remove(path string) error {
// Open returns an error if the repo is not initialized.
func (r *FSRepo) Open() error {
pkgLock.Lock()
defer pkgLock.Unlock()
openerCounter.Lock()
defer openerCounter.Unlock()
if r.state != unopened {
return debugerror.Errorf("repo is %s", r.state)
}
@ -118,7 +119,7 @@ func (r *FSRepo) Open() error {
}
r.state = opened
pkgLock.AddOpener(r.path)
openerCounter.AddOpener(r.path)
return nil
}
@ -211,12 +212,12 @@ func (r *FSRepo) SetConfigKey(key string, value interface{}) error {
// Close closes the FSRepo, releasing held resources.
func (r *FSRepo) Close() error {
pkgLock.Lock()
defer pkgLock.Unlock()
openerCounter.Lock()
defer openerCounter.Unlock()
if r.state != opened {
return debugerror.Errorf("repo is %s", r.state)
}
pkgLock.RemoveOpener(r.path)
openerCounter.RemoveOpener(r.path)
return nil // TODO release repo lock
}
@ -225,13 +226,13 @@ var _ repo.Interface = &FSRepo{}
// IsInitialized returns true if the repo is initialized at provided |path|.
func IsInitialized(path string) bool {
pkgLock.Lock()
defer pkgLock.Unlock()
openerCounter.Lock()
defer openerCounter.Unlock()
return isInitializedUnsynced(path)
}
// isInitializedUnsynced reports whether the repo is initialized. Caller must
// hold pkgLock.
// hold openerCounter lock.
func isInitializedUnsynced(path string) bool {
configFilename, err := config.Filename(path)
if err != nil {

View File

@ -5,7 +5,7 @@ import (
"sync"
)
type packageLock struct {
type Counter struct {
// lock protects repos
lock sync.Mutex
// repos maps repo paths to the number of openers holding an FSRepo handle
@ -13,39 +13,39 @@ type packageLock struct {
repos map[string]int
}
func makePackageLock() *packageLock {
return &packageLock{
func NewCounter() *Counter {
return &Counter{
repos: make(map[string]int),
}
}
// Lock must be held to while performing any operation that modifies an
// FSRepo's state field. This includes Init, Open, Close, and Remove.
func (l *packageLock) Lock() {
func (l *Counter) Lock() {
l.lock.Lock()
}
func (l *packageLock) Unlock() {
func (l *Counter) Unlock() {
l.lock.Unlock()
}
// NumOpeners returns the number of FSRepos holding a handle to the repo at
// this path. This method is not thread-safe. The caller must have this object
// locked.
func (l *packageLock) NumOpeners(repoPath string) int {
func (l *Counter) NumOpeners(repoPath string) int {
return l.repos[key(repoPath)]
}
// AddOpener messages that an FSRepo holds a handle to the repo at this path.
// This method is not thread-safe. The caller must have this object locked.
func (l *packageLock) AddOpener(repoPath string) {
func (l *Counter) AddOpener(repoPath string) {
l.repos[key(repoPath)]++
}
// RemoveOpener messgaes that an FSRepo no longer holds a handle to the repo at
// this path. This method is not thread-safe. The caller must have this object
// locked.
func (l *packageLock) RemoveOpener(repoPath string) {
func (l *Counter) RemoveOpener(repoPath string) {
l.repos[key(repoPath)]--
}