Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat add dir_flag #376

Merged
merged 9 commits into from
Dec 9, 2013
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions error/error.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ const (
EcodeNodeExist = 105
EcodeKeyIsPreserved = 106
EcodeRootROnly = 107
EcodeDirNotEmpty = 108

EcodeValueRequired = 200
EcodePrevValueRequired = 201
Expand All @@ -59,6 +60,7 @@ func init() {
errors[EcodeNodeExist] = "Already exists" // create
errors[EcodeRootROnly] = "Root is read only"
errors[EcodeKeyIsPreserved] = "The prefix of given key is a keyword in etcd"
errors[EcodeDirNotEmpty] = "The directory is not empty"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Lets stay with unix tradition "Directory not empty"


// Post form related errors
errors[EcodeValueRequired] = "Value is Required in POST form"
Expand Down
4 changes: 2 additions & 2 deletions server/registry.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ func (r *Registry) Register(name string, peerURL string, url string) error {
// Write data to store.
key := path.Join(RegistryKey, name)
value := fmt.Sprintf("raft=%s&etcd=%s", peerURL, url)
_, err := r.store.Create(key, value, false, store.Permanent)
_, err := r.store.Create(key, false, value, false, store.Permanent)
log.Debugf("Register: %s", name)
return err
}
Expand All @@ -59,7 +59,7 @@ func (r *Registry) Unregister(name string) error {
// delete(r.nodes, name)

// Remove the key from the store.
_, err := r.store.Delete(path.Join(RegistryKey, name), false)
_, err := r.store.Delete(path.Join(RegistryKey, name), false, false)
log.Debugf("Unregister: %s", name)
return err
}
Expand Down
18 changes: 9 additions & 9 deletions server/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,14 +46,14 @@ func New(name string, urlStr string, bindAddr string, tlsConf *TLSConfig, tlsInf
TLSConfig: &tlsConf.Server,
Addr: bindAddr,
},
name: name,
store: store,
registry: registry,
url: urlStr,
tlsConf: tlsConf,
tlsInfo: tlsInfo,
peerServer: peerServer,
router: r,
name: name,
store: store,
registry: registry,
url: urlStr,
tlsConf: tlsConf,
tlsInfo: tlsInfo,
peerServer: peerServer,
router: r,
corsHandler: cors,
}

Expand Down Expand Up @@ -377,7 +377,7 @@ func (s *Server) SpeedTestHandler(w http.ResponseWriter, req *http.Request) erro
for i := 0; i < count; i++ {
go func() {
for j := 0; j < 10; j++ {
c := s.Store().CommandFactory().CreateSetCommand("foo", "bar", time.Unix(0, 0))
c := s.Store().CommandFactory().CreateSetCommand("foo", false, "bar", time.Unix(0, 0))
s.peerServer.RaftServer().Do(c)
}
c <- true
Expand Down
2 changes: 1 addition & 1 deletion server/v1/delete_key_handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,6 @@ import (
func DeleteKeyHandler(w http.ResponseWriter, req *http.Request, s Server) error {
vars := mux.Vars(req)
key := "/" + vars["key"]
c := s.Store().CommandFactory().CreateDeleteCommand(key, false)
c := s.Store().CommandFactory().CreateDeleteCommand(key, false, false)
return s.Dispatch(c, w, req)
}
4 changes: 2 additions & 2 deletions server/v1/set_key_handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,11 +36,11 @@ func SetKeyHandler(w http.ResponseWriter, req *http.Request, s Server) error {
c = s.Store().CommandFactory().CreateCompareAndSwapCommand(key, value, prevValueArr[0], 0, expireTime)
} else {
// test against existence
c = s.Store().CommandFactory().CreateCreateCommand(key, value, expireTime, false)
c = s.Store().CommandFactory().CreateCreateCommand(key, false, value, expireTime, false)
}

} else {
c = s.Store().CommandFactory().CreateSetCommand(key, value, expireTime)
c = s.Store().CommandFactory().CreateSetCommand(key, false, value, expireTime)
}

return s.Dispatch(c, w, req)
Expand Down
4 changes: 3 additions & 1 deletion server/v2/delete_handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,10 @@ import (
func DeleteHandler(w http.ResponseWriter, req *http.Request, s Server) error {
vars := mux.Vars(req)
key := "/" + vars["key"]

recursive := (req.FormValue("recursive") == "true")
dir := (req.FormValue("dir") == "true")

c := s.Store().CommandFactory().CreateDeleteCommand(key, recursive)
c := s.Store().CommandFactory().CreateDeleteCommand(key, dir, recursive)
return s.Dispatch(c, w, req)
}
3 changes: 2 additions & 1 deletion server/v2/post_handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,12 @@ func PostHandler(w http.ResponseWriter, req *http.Request, s Server) error {
key := "/" + vars["key"]

value := req.FormValue("value")
dir := (req.FormValue("dir") == "true")
expireTime, err := store.TTL(req.FormValue("ttl"))
if err != nil {
return etcdErr.NewError(etcdErr.EcodeTTLNaN, "Create", s.Store().Index())
}

c := s.Store().CommandFactory().CreateCreateCommand(key, value, expireTime, true)
c := s.Store().CommandFactory().CreateCreateCommand(key, dir, value, expireTime, true)
return s.Dispatch(c, w, req)
}
20 changes: 11 additions & 9 deletions server/v2/put_handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,31 +20,33 @@ func PutHandler(w http.ResponseWriter, req *http.Request, s Server) error {
req.ParseForm()

value := req.Form.Get("value")
dir := (req.FormValue("dir") == "true")

expireTime, err := store.TTL(req.Form.Get("ttl"))
if err != nil {
return etcdErr.NewError(etcdErr.EcodeTTLNaN, "Update", s.Store().Index())
}

_, valueOk := req.Form["prevValue"]
prevValue := req.Form.Get("prevValue")
prevValue := req.FormValue("prevValue")

_, indexOk := req.Form["prevIndex"]
prevIndexStr := req.Form.Get("prevIndex")
prevIndexStr := req.FormValue("prevIndex")

_, existOk := req.Form["prevExist"]
prevExist := req.Form.Get("prevExist")
prevExist := req.FormValue("prevExist")

// Set handler: create a new node or replace the old one.
if !valueOk && !indexOk && !existOk {
return SetHandler(w, req, s, key, value, expireTime)
return SetHandler(w, req, s, key, dir, value, expireTime)
}

// update with test
if existOk {
if prevExist == "false" {
// Create command: create a new node. Fail, if a node already exists
// Ignore prevIndex and prevValue
return CreateHandler(w, req, s, key, value, expireTime)
return CreateHandler(w, req, s, key, dir, value, expireTime)
}

if prevExist == "true" && !indexOk && !valueOk {
Expand Down Expand Up @@ -75,13 +77,13 @@ func PutHandler(w http.ResponseWriter, req *http.Request, s Server) error {
return s.Dispatch(c, w, req)
}

func SetHandler(w http.ResponseWriter, req *http.Request, s Server, key, value string, expireTime time.Time) error {
c := s.Store().CommandFactory().CreateSetCommand(key, value, expireTime)
func SetHandler(w http.ResponseWriter, req *http.Request, s Server, key string, dir bool, value string, expireTime time.Time) error {
c := s.Store().CommandFactory().CreateSetCommand(key, dir, value, expireTime)
return s.Dispatch(c, w, req)
}

func CreateHandler(w http.ResponseWriter, req *http.Request, s Server, key, value string, expireTime time.Time) error {
c := s.Store().CommandFactory().CreateCreateCommand(key, value, expireTime, false)
func CreateHandler(w http.ResponseWriter, req *http.Request, s Server, key string, dir bool, value string, expireTime time.Time) error {
c := s.Store().CommandFactory().CreateCreateCommand(key, dir, value, expireTime, false)
return s.Dispatch(c, w, req)
}

Expand Down
9 changes: 5 additions & 4 deletions store/command_factory.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,12 @@ var minVersion, maxVersion int
type CommandFactory interface {
Version() int
CreateUpgradeCommand() raft.Command
CreateSetCommand(key string, value string, expireTime time.Time) raft.Command
CreateCreateCommand(key string, value string, expireTime time.Time, unique bool) raft.Command
CreateSetCommand(key string, dir bool, value string, expireTime time.Time) raft.Command
CreateCreateCommand(key string, dir bool, value string, expireTime time.Time, unique bool) raft.Command
CreateUpdateCommand(key string, value string, expireTime time.Time) raft.Command
CreateDeleteCommand(key string, recursive bool) raft.Command
CreateCompareAndSwapCommand(key string, value string, prevValue string, prevIndex uint64, expireTime time.Time) raft.Command
CreateDeleteCommand(key string, dir, recursive bool) raft.Command
CreateCompareAndSwapCommand(key string, value string, prevValue string,
prevIndex uint64, expireTime time.Time) raft.Command
CreateSyncCommand(now time.Time) raft.Command
}

Expand Down
18 changes: 13 additions & 5 deletions store/node.go
Original file line number Diff line number Diff line change
Expand Up @@ -175,11 +175,19 @@ func (n *node) Add(child *node) *etcdErr.Error {
}

// Remove function remove the node.
func (n *node) Remove(recursive bool, callback func(path string)) *etcdErr.Error {
func (n *node) Remove(dir, recursive bool, callback func(path string)) *etcdErr.Error {

if n.IsDir() && !recursive {
// cannot delete a directory without set recursive to true
return etcdErr.NewError(etcdErr.EcodeNotFile, "", n.store.Index())
if n.IsDir() {
if !dir {
// cannot delete a directory without set recursive to true
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"without recursive set to true"

return etcdErr.NewError(etcdErr.EcodeNotFile, n.Path, n.store.Index())
}

if len(n.Children) != 0 && !recursive {
// cannot delete a directory if it is not empty and the operation
// is not recursive
return etcdErr.NewError(etcdErr.EcodeDirNotEmpty, n.Path, n.store.Index())
}
}

if !n.IsDir() { // key-value pair
Expand All @@ -202,7 +210,7 @@ func (n *node) Remove(recursive bool, callback func(path string)) *etcdErr.Error
}

for _, child := range n.Children { // delete all children
child.Remove(true, callback)
child.Remove(true, true, callback)
}

// delete self
Expand Down
57 changes: 27 additions & 30 deletions store/store.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,17 +42,20 @@ type Store interface {
Version() int
CommandFactory() CommandFactory
Index() uint64

Get(nodePath string, recursive, sorted bool) (*Event, error)
Set(nodePath string, value string, expireTime time.Time) (*Event, error)
Set(nodePath string, dir bool, value string, expireTime time.Time) (*Event, error)
Update(nodePath string, newValue string, expireTime time.Time) (*Event, error)
Create(nodePath string, value string, incrementalSuffix bool,
Create(nodePath string, dir bool, value string, unique bool,
expireTime time.Time) (*Event, error)
CompareAndSwap(nodePath string, prevValue string, prevIndex uint64,
value string, expireTime time.Time) (*Event, error)
Delete(nodePath string, recursive bool) (*Event, error)
Delete(nodePath string, recursive, dir bool) (*Event, error)
Watch(prefix string, recursive bool, sinceIndex uint64) (<-chan *Event, error)

Save() ([]byte, error)
Recovery(state []byte) error

TotalTransactions() uint64
JsonStats() []byte
DeleteExpiredKeys(cutoff time.Time)
Expand Down Expand Up @@ -156,10 +159,10 @@ func (s *store) Get(nodePath string, recursive, sorted bool) (*Event, error) {
// Create function creates the node at nodePath. Create will help to create intermediate directories with no ttl.
// If the node has already existed, create will fail.
// If any node on the path is a file, create will fail.
func (s *store) Create(nodePath string, value string, unique bool, expireTime time.Time) (*Event, error) {
func (s *store) Create(nodePath string, dir bool, value string, unique bool, expireTime time.Time) (*Event, error) {
s.worldLock.Lock()
defer s.worldLock.Unlock()
e, err := s.internalCreate(nodePath, value, unique, false, expireTime, Create)
e, err := s.internalCreate(nodePath, dir, value, unique, false, expireTime, Create)

if err == nil {
s.Stats.Inc(CreateSuccess)
Expand All @@ -171,10 +174,10 @@ func (s *store) Create(nodePath string, value string, unique bool, expireTime ti
}

// Set function creates or replace the node at nodePath.
func (s *store) Set(nodePath string, value string, expireTime time.Time) (*Event, error) {
func (s *store) Set(nodePath string, dir bool, value string, expireTime time.Time) (*Event, error) {
s.worldLock.Lock()
defer s.worldLock.Unlock()
e, err := s.internalCreate(nodePath, value, false, true, expireTime, Set)
e, err := s.internalCreate(nodePath, dir, value, false, true, expireTime, Set)

if err == nil {
s.Stats.Inc(SetSuccess)
Expand Down Expand Up @@ -239,7 +242,7 @@ func (s *store) CompareAndSwap(nodePath string, prevValue string, prevIndex uint

// Delete function deletes the node at the given path.
// If the node is a directory, recursive must be true to delete it.
func (s *store) Delete(nodePath string, recursive bool) (*Event, error) {
func (s *store) Delete(nodePath string, dir, recursive bool) (*Event, error) {
nodePath = path.Clean(path.Join("/", nodePath))
// we do not allow the user to change "/"
if nodePath == "/" {
Expand Down Expand Up @@ -272,7 +275,7 @@ func (s *store) Delete(nodePath string, recursive bool) (*Event, error) {
s.WatcherHub.notifyWatchers(e, path, true)
}

err = n.Remove(recursive, callback)
err = n.Remove(dir, recursive, callback)

if err != nil {
s.Stats.Inc(DeleteFail)
Expand Down Expand Up @@ -363,22 +366,16 @@ func (s *store) Update(nodePath string, newValue string, expireTime time.Time) (
e := newEvent(Update, nodePath, nextIndex, n.CreatedIndex)
eNode := e.Node

if len(newValue) != 0 {
if n.IsDir() {
// if the node is a directory, we cannot update value
s.Stats.Inc(UpdateFail)
return nil, etcdErr.NewError(etcdErr.EcodeNotFile, nodePath, currIndex)
}

eNode.PrevValue = n.Value
n.Write(newValue, nextIndex)
eNode.Value = newValue

} else {
// do not update value
eNode.Value = n.Value
if n.IsDir() && len(newValue) != 0 {
// if the node is a directory, we cannot update value to non-empty
s.Stats.Inc(UpdateFail)
return nil, etcdErr.NewError(etcdErr.EcodeNotFile, nodePath, currIndex)
}

eNode.PrevValue = n.Value
n.Write(newValue, nextIndex)
eNode.Value = newValue

// update ttl
n.UpdateTTL(expireTime)

Expand All @@ -393,7 +390,7 @@ func (s *store) Update(nodePath string, newValue string, expireTime time.Time) (
return e, nil
}

func (s *store) internalCreate(nodePath string, value string, unique bool, replace bool,
func (s *store) internalCreate(nodePath string, dir bool, value string, unique, replace bool,
expireTime time.Time, action string) (*Event, error) {

currIndex, nextIndex := s.CurrentIndex, s.CurrentIndex+1
Expand All @@ -415,10 +412,10 @@ func (s *store) internalCreate(nodePath string, value string, unique bool, repla
expireTime = Permanent
}

dir, newNodeName := path.Split(nodePath)
dirName, nodeName := path.Split(nodePath)

// walk through the nodePath, create dirs and get the last directory node
d, err := s.walk(dir, s.checkDir)
d, err := s.walk(dirName, s.checkDir)

if err != nil {
s.Stats.Inc(SetFail)
Expand All @@ -429,7 +426,7 @@ func (s *store) internalCreate(nodePath string, value string, unique bool, repla
e := newEvent(action, nodePath, nextIndex, nextIndex)
eNode := e.Node

n, _ := d.GetChild(newNodeName)
n, _ := d.GetChild(nodeName)

// force will try to replace a existing file
if n != nil {
Expand All @@ -439,13 +436,13 @@ func (s *store) internalCreate(nodePath string, value string, unique bool, repla
}
eNode.PrevValue, _ = n.Read()

n.Remove(false, nil)
n.Remove(false, false, nil)
} else {
return nil, etcdErr.NewError(etcdErr.EcodeNodeExist, nodePath, currIndex)
}
}

if len(value) != 0 { // create file
if !dir { // create file
eNode.Value = value

n = newKV(s, nodePath, value, nextIndex, d, "", expireTime)
Expand Down Expand Up @@ -512,7 +509,7 @@ func (s *store) DeleteExpiredKeys(cutoff time.Time) {
}

s.ttlKeyHeap.pop()
node.Remove(true, nil)
node.Remove(true, true, nil)

s.CurrentIndex++

Expand Down
Loading