Thread safety
This commit is contained in:
parent
60d28df429
commit
4211a872b7
45
dir.go
45
dir.go
@ -26,6 +26,7 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
"os"
|
"os"
|
||||||
"path"
|
"path"
|
||||||
|
"sync"
|
||||||
|
|
||||||
"bazil.org/fuse"
|
"bazil.org/fuse"
|
||||||
"bazil.org/fuse/fs"
|
"bazil.org/fuse/fs"
|
||||||
@ -42,22 +43,23 @@ type verDir struct {
|
|||||||
node *verNode
|
node *verNode
|
||||||
inode uint64
|
inode uint64
|
||||||
parent *verDir
|
parent *verDir
|
||||||
|
mutex sync.Mutex
|
||||||
}
|
}
|
||||||
|
|
||||||
func newVerDir(node *verNode, parent *verDir) *verDir {
|
func newVerDir(node *verNode, parent *verDir) *verDir {
|
||||||
dirs := make(map[string]*verDir)
|
dirs := make(map[string]*verDir)
|
||||||
files := make(map[string]*verFile)
|
files := make(map[string]*verFile)
|
||||||
|
mutex := sync.Mutex{}
|
||||||
|
|
||||||
return &verDir{dirs, files, node, allocInode(), parent}
|
return &verDir{dirs, files, node, allocInode(), parent, mutex}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (vd *verDir) version() error {
|
func (vd *verDir) version() error {
|
||||||
if vd.node.flags&NodeFlagVer == NodeFlagVer {
|
if vd.node.flags&NodeFlagNew == NodeFlagNew {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
node := newVerNode(vd.node.path, vd.node.ver.db.lastVersion(), vd.node, NodeFlagDir|NodeFlagVer)
|
node := newVerNode(vd.node.path, vd.node.ver.db.lastVersion(), vd.node, NodeFlagDir|NodeFlagNew)
|
||||||
|
|
||||||
if err := os.MkdirAll(node.rebasedPath(), 0755); err != nil {
|
if err := os.MkdirAll(node.rebasedPath(), 0755); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -78,7 +80,7 @@ func (vd *verDir) createDir(name string) (*verDir, error) {
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
node := newVerNode(childPath, vd.node.ver, nil, NodeFlagDir|NodeFlagVer)
|
node := newVerNode(childPath, vd.node.ver, nil, NodeFlagDir|NodeFlagNew)
|
||||||
dir := newVerDir(node, vd)
|
dir := newVerDir(node, vd)
|
||||||
vd.dirs[name] = dir
|
vd.dirs[name] = dir
|
||||||
node.ver.meta.createNode(node.path)
|
node.ver.meta.createNode(node.path)
|
||||||
@ -86,24 +88,24 @@ func (vd *verDir) createDir(name string) (*verDir, error) {
|
|||||||
return dir, nil
|
return dir, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (vd *verDir) createFile(name string, flags fuse.OpenFlags, mode os.FileMode) (*verFile, *verFileHandle, error) {
|
func (vd *verDir) createFile(name string, flags fuse.OpenFlags, mode os.FileMode) (*verFile, *verFileHandle, fuse.HandleID, error) {
|
||||||
if err := vd.version(); err != nil {
|
if err := vd.version(); err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, 0, err
|
||||||
}
|
}
|
||||||
|
|
||||||
childPath := path.Join(vd.node.path, name)
|
childPath := path.Join(vd.node.path, name)
|
||||||
node := newVerNode(childPath, vd.node.ver, nil, NodeFlagVer)
|
node := newVerNode(childPath, vd.node.ver, nil, NodeFlagNew)
|
||||||
file := newVerFile(node, vd)
|
file := newVerFile(node, vd)
|
||||||
|
|
||||||
handle, err := file.open(flags, mode)
|
handle, id, err := file.open(flags, mode)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, 0, err
|
||||||
}
|
}
|
||||||
|
|
||||||
vd.files[name] = file
|
vd.files[name] = file
|
||||||
node.ver.meta.createNode(node.path)
|
node.ver.meta.createNode(node.path)
|
||||||
|
|
||||||
return file, handle, nil
|
return file, handle, id, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Node
|
// Node
|
||||||
@ -129,11 +131,14 @@ func (vd *verDir) Setattr(ctx context.Context, req *fuse.SetattrRequest, resp *f
|
|||||||
|
|
||||||
// NodeCreater
|
// NodeCreater
|
||||||
func (vd *verDir) Create(ctx context.Context, req *fuse.CreateRequest, resp *fuse.CreateResponse) (node fs.Node, handle fs.Handle, err error) {
|
func (vd *verDir) Create(ctx context.Context, req *fuse.CreateRequest, resp *fuse.CreateResponse) (node fs.Node, handle fs.Handle, err error) {
|
||||||
|
vd.mutex.Lock()
|
||||||
|
defer vd.mutex.Unlock()
|
||||||
|
|
||||||
if req.Mode.IsDir() {
|
if req.Mode.IsDir() {
|
||||||
node, err = vd.createDir(req.Name)
|
node, err = vd.createDir(req.Name)
|
||||||
handle = node
|
handle = node
|
||||||
} else if req.Mode.IsRegular() {
|
} else if req.Mode.IsRegular() {
|
||||||
node, handle, err = vd.createFile(req.Name, req.Flags, req.Mode)
|
node, handle, resp.Handle, err = vd.createFile(req.Name, req.Flags, req.Mode)
|
||||||
} else {
|
} else {
|
||||||
err = errors.New("unsupported filetype")
|
err = errors.New("unsupported filetype")
|
||||||
}
|
}
|
||||||
@ -143,16 +148,22 @@ func (vd *verDir) Create(ctx context.Context, req *fuse.CreateRequest, resp *fus
|
|||||||
|
|
||||||
// NodeMkdirer
|
// NodeMkdirer
|
||||||
func (vd *verDir) Mkdir(ctx context.Context, req *fuse.MkdirRequest) (fs.Node, error) {
|
func (vd *verDir) Mkdir(ctx context.Context, req *fuse.MkdirRequest) (fs.Node, error) {
|
||||||
|
vd.mutex.Lock()
|
||||||
|
defer vd.mutex.Unlock()
|
||||||
|
|
||||||
return vd.createDir(req.Name)
|
return vd.createDir(req.Name)
|
||||||
}
|
}
|
||||||
|
|
||||||
// NodeRemover
|
// NodeRemover
|
||||||
func (vd *verDir) Remove(ctx context.Context, req *fuse.RemoveRequest) error {
|
func (vd *verDir) Remove(ctx context.Context, req *fuse.RemoveRequest) error {
|
||||||
|
vd.mutex.Lock()
|
||||||
|
defer vd.mutex.Unlock()
|
||||||
|
|
||||||
if req.Dir {
|
if req.Dir {
|
||||||
node := vd.dirs[req.Name].node
|
node := vd.dirs[req.Name].node
|
||||||
ver := node.ver
|
ver := node.ver
|
||||||
|
|
||||||
if node.flags&NodeFlagVer == NodeFlagVer {
|
if node.flags&NodeFlagNew == NodeFlagNew {
|
||||||
if err := os.Remove(node.rebasedPath()); err != nil {
|
if err := os.Remove(node.rebasedPath()); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -166,7 +177,7 @@ func (vd *verDir) Remove(ctx context.Context, req *fuse.RemoveRequest) error {
|
|||||||
node := vd.files[req.Name].node
|
node := vd.files[req.Name].node
|
||||||
ver := node.ver
|
ver := node.ver
|
||||||
|
|
||||||
if node.flags&NodeFlagVer == NodeFlagVer {
|
if node.flags&NodeFlagNew == NodeFlagNew {
|
||||||
if err := os.Remove(node.rebasedPath()); err != nil {
|
if err := os.Remove(node.rebasedPath()); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -183,6 +194,9 @@ func (vd *verDir) Remove(ctx context.Context, req *fuse.RemoveRequest) error {
|
|||||||
|
|
||||||
// NodeRequestLookuper
|
// NodeRequestLookuper
|
||||||
func (vd *verDir) Lookup(ctx context.Context, name string) (fs.Node, error) {
|
func (vd *verDir) Lookup(ctx context.Context, name string) (fs.Node, error) {
|
||||||
|
vd.mutex.Lock()
|
||||||
|
defer vd.mutex.Unlock()
|
||||||
|
|
||||||
if dir, ok := vd.dirs[name]; ok {
|
if dir, ok := vd.dirs[name]; ok {
|
||||||
return dir, nil
|
return dir, nil
|
||||||
}
|
}
|
||||||
@ -196,6 +210,9 @@ func (vd *verDir) Lookup(ctx context.Context, name string) (fs.Node, error) {
|
|||||||
|
|
||||||
// HandleReadDirAller
|
// HandleReadDirAller
|
||||||
func (vd *verDir) ReadDirAll(ctx context.Context) ([]fuse.Dirent, error) {
|
func (vd *verDir) ReadDirAll(ctx context.Context) ([]fuse.Dirent, error) {
|
||||||
|
vd.mutex.Lock()
|
||||||
|
defer vd.mutex.Unlock()
|
||||||
|
|
||||||
entries := []fuse.Dirent{{Inode: vd.inode, Name: ".", Type: fuse.DT_Dir}}
|
entries := []fuse.Dirent{{Inode: vd.inode, Name: ".", Type: fuse.DT_Dir}}
|
||||||
if vd.parent != nil {
|
if vd.parent != nil {
|
||||||
entry := fuse.Dirent{Inode: vd.parent.inode, Name: "..", Type: fuse.DT_Dir}
|
entry := fuse.Dirent{Inode: vd.parent.inode, Name: "..", Type: fuse.DT_Dir}
|
||||||
|
48
file.go
48
file.go
@ -24,6 +24,7 @@ package main
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"os"
|
"os"
|
||||||
|
"sync"
|
||||||
|
|
||||||
"bazil.org/fuse"
|
"bazil.org/fuse"
|
||||||
"bazil.org/fuse/fs"
|
"bazil.org/fuse/fs"
|
||||||
@ -34,24 +35,28 @@ import (
|
|||||||
// verFile
|
// verFile
|
||||||
//
|
//
|
||||||
|
|
||||||
|
type handleMap map[fuse.HandleID]*verFileHandle
|
||||||
|
|
||||||
type verFile struct {
|
type verFile struct {
|
||||||
node *verNode
|
node *verNode
|
||||||
inode uint64
|
inode uint64
|
||||||
parent *verDir
|
parent *verDir
|
||||||
handles map[uint64]*verFileHandle
|
handles handleMap
|
||||||
|
mutex sync.Mutex
|
||||||
}
|
}
|
||||||
|
|
||||||
func newVerFile(node *verNode, parent *verDir) *verFile {
|
func newVerFile(node *verNode, parent *verDir) *verFile {
|
||||||
return &verFile{node, allocInode(), parent, make(map[uint64]*verFileHandle)}
|
handles := make(handleMap)
|
||||||
|
mutex := sync.Mutex{}
|
||||||
|
return &verFile{node, allocInode(), parent, handles, mutex}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (vf *verFile) version() error {
|
func (vf *verFile) version() error {
|
||||||
if vf.node.flags&NodeFlagVer == NodeFlagVer {
|
if vf.node.flags&NodeFlagNew == NodeFlagNew {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
node := newVerNode(vf.node.path, vf.node.ver.db.lastVersion(), vf.node, NodeFlagVer)
|
node := newVerNode(vf.node.path, vf.node.ver.db.lastVersion(), vf.node, NodeFlagNew)
|
||||||
|
|
||||||
if _, err := copyFile(vf.node.rebasedPath(), node.rebasedPath()); err != nil {
|
if _, err := copyFile(vf.node.rebasedPath(), node.rebasedPath()); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -62,10 +67,13 @@ func (vf *verFile) version() error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (vf *verFile) open(flags fuse.OpenFlags, mode os.FileMode) (*verFileHandle, error) {
|
func (vf *verFile) open(flags fuse.OpenFlags, mode os.FileMode) (*verFileHandle, fuse.HandleID, error) {
|
||||||
|
vf.mutex.Lock()
|
||||||
|
defer vf.mutex.Unlock()
|
||||||
|
|
||||||
if !flags.IsReadOnly() {
|
if !flags.IsReadOnly() {
|
||||||
if err := vf.version(); err != nil {
|
if err := vf.version(); err != nil {
|
||||||
return nil, err
|
return nil, 0, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -73,18 +81,20 @@ func (vf *verFile) open(flags fuse.OpenFlags, mode os.FileMode) (*verFileHandle,
|
|||||||
|
|
||||||
handle, err := os.OpenFile(path, int(flags), mode)
|
handle, err := os.OpenFile(path, int(flags), mode)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, 0, err
|
||||||
}
|
}
|
||||||
|
|
||||||
id := allocHandleId()
|
id := allocHandleId()
|
||||||
verHandle := &verFileHandle{vf, path, handle, id}
|
verHandle := &verFileHandle{vf, path, handle}
|
||||||
vf.handles[id] = verHandle
|
vf.handles[id] = verHandle
|
||||||
|
|
||||||
return verHandle, nil
|
return verHandle, id, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (vf *verFile) release(handle uint64) {
|
func (vf *verFile) release(handle fuse.HandleID) {
|
||||||
|
vf.mutex.Lock()
|
||||||
delete(vf.handles, handle)
|
delete(vf.handles, handle)
|
||||||
|
vf.mutex.Unlock()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Node
|
// Node
|
||||||
@ -106,23 +116,20 @@ func (vf *verFile) Setattr(ctx context.Context, req *fuse.SetattrRequest, resp *
|
|||||||
|
|
||||||
// NodeOpener
|
// NodeOpener
|
||||||
func (vf *verFile) Open(ctx context.Context, req *fuse.OpenRequest, resp *fuse.OpenResponse) (fs.Handle, error) {
|
func (vf *verFile) Open(ctx context.Context, req *fuse.OpenRequest, resp *fuse.OpenResponse) (fs.Handle, error) {
|
||||||
handle, err := vf.open(req.Flags, 0644)
|
handle, id, err := vf.open(req.Flags, 0644)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
resp.Handle = id
|
||||||
return handle, nil
|
return handle, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// NodeFsyncer
|
// NodeFsyncer
|
||||||
func (vf *verFile) Fsync(ctx context.Context, req *fuse.FsyncRequest) error {
|
func (vf *verFile) Fsync(ctx context.Context, req *fuse.FsyncRequest) error {
|
||||||
for _, vfh := range vf.handles {
|
vf.mutex.Lock()
|
||||||
if err := vfh.handle.Sync(); err != nil {
|
defer vf.mutex.Unlock()
|
||||||
return err
|
return vf.handles[req.Handle].handle.Sync()
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
@ -133,7 +140,6 @@ type verFileHandle struct {
|
|||||||
node *verFile
|
node *verFile
|
||||||
path string
|
path string
|
||||||
handle *os.File
|
handle *os.File
|
||||||
id uint64
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// HandleReader
|
// HandleReader
|
||||||
@ -177,6 +183,6 @@ func (vfh *verFileHandle) Release(ctx context.Context, req *fuse.ReleaseRequest)
|
|||||||
vfh.handle.Close()
|
vfh.handle.Close()
|
||||||
vfh.handle = nil
|
vfh.handle = nil
|
||||||
|
|
||||||
vfh.node.release(vfh.id)
|
vfh.node.release(req.Handle)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
2
node.go
2
node.go
@ -36,7 +36,7 @@ import (
|
|||||||
|
|
||||||
const (
|
const (
|
||||||
NodeFlagDir = 1 << iota
|
NodeFlagDir = 1 << iota
|
||||||
NodeFlagVer
|
NodeFlagNew
|
||||||
)
|
)
|
||||||
|
|
||||||
type verNode struct {
|
type verNode struct {
|
||||||
|
6
util.go
6
util.go
@ -32,6 +32,8 @@ import (
|
|||||||
"strconv"
|
"strconv"
|
||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"bazil.org/fuse"
|
||||||
)
|
)
|
||||||
|
|
||||||
var inodeCnt, handleCnt uint64
|
var inodeCnt, handleCnt uint64
|
||||||
@ -40,8 +42,8 @@ func allocInode() uint64 {
|
|||||||
return atomic.AddUint64(&inodeCnt, 1)
|
return atomic.AddUint64(&inodeCnt, 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
func allocHandleId() uint64 {
|
func allocHandleId() fuse.HandleID {
|
||||||
return atomic.AddUint64(&handleCnt, 1)
|
return fuse.HandleID(atomic.AddUint64(&handleCnt, 1))
|
||||||
}
|
}
|
||||||
|
|
||||||
func copyFile(src, dst string) (int64, error) {
|
func copyFile(src, dst string) (int64, error) {
|
||||||
|
Loading…
Reference in New Issue
Block a user