etcd/file_system/file_system.go
2013-09-03 14:30:42 -04:00

140 lines
2.8 KiB
Go

package fileSystem
import (
"fmt"
"path/filepath"
"strings"
"time"
etcdErr "github.com/coreos/etcd/error"
)
type FileSystem struct {
Root *Node
EventHistory *EventHistory
WatcherHub *watcherHub
Index uint64
Term uint64
}
func New() *FileSystem {
return &FileSystem{
Root: newDir("/", 0, 0, nil, ""),
WatcherHub: newWatchHub(1000),
}
}
func (fs *FileSystem) InternalGet(path string, index uint64, term uint64) (*Node, error) {
fmt.Println("GET: ", path)
path = filepath.Clean("/" + path)
// update file system known index and term
fs.Index, fs.Term = index, term
walkFunc := func(parent *Node, dirName string) (*Node, error) {
child, ok := parent.Children[dirName]
if ok {
return child, nil
}
return nil, etcdErr.NewError(100, "get")
}
f, err := fs.walk(path, walkFunc)
if err != nil {
return nil, err
}
return f, nil
}
func (fs *FileSystem) Set(path string, value string, expireTime time.Time, index uint64, term uint64) error {
path = filepath.Clean("/" + path)
// update file system known index and term
fs.Index, fs.Term = index, term
dir, name := filepath.Split(path)
// walk through the path and get the last directory node
d, err := fs.walk(dir, fs.checkDir)
if err != nil {
return err
}
f := newFile(name, value, fs.Index, fs.Term, d, "", expireTime)
err = d.Add(f)
if err == nil {
if expireTime != Permanent {
go f.Expire()
}
}
return err
}
func (fs *FileSystem) TestAndSet() {
}
func (fs *FileSystem) TestIndexAndSet() {
}
func (fs *FileSystem) Delete(path string, recurisive bool, index uint64, term uint64) error {
n, err := fs.InternalGet(path, index, term)
if err != nil {
return err
}
return n.Remove(recurisive)
}
// walk function walks all the path and apply the walkFunc on each directory
func (fs *FileSystem) walk(path string, walkFunc func(prev *Node, component string) (*Node, error)) (*Node, error) {
components := strings.Split(path, "/")
curr := fs.Root
var err error
for i := 1; i < len(components); i++ {
if len(components[i]) == 0 { // ignore empty string
return curr, nil
}
curr, err = walkFunc(curr, components[i])
if err != nil {
return nil, err
}
}
return curr, nil
}
// checkDir function will check whether the component is a directory under parent node.
// If it is a directory, this function will return the pointer to that node.
// If it does not exist, this function will create a new directory and return the pointer to that node.
// If it is a file, this function will return error.
func (fs *FileSystem) checkDir(parent *Node, dirName string) (*Node, error) {
subDir, ok := parent.Children[dirName]
if ok {
return subDir, nil
}
n := newDir(filepath.Join(parent.Path, dirName), fs.Index, fs.Term, parent, parent.ACL)
parent.Children[dirName] = n
return n, nil
}