From effc8285f2f985a275d499b4acd04203076bba63 Mon Sep 17 00:00:00 2001 From: Hongchao Deng Date: Sun, 8 Sep 2013 18:46:16 -0400 Subject: [PATCH] New error-system for Etcd with docs --- Documentation/errorcode.md | 58 ++++++++++++++++++++++++++++++++++++++ command.go | 2 +- error/error.go | 32 ++++++++++++++++----- etcd_handlers.go | 18 ++++++------ file_system/event.go | 7 ++++- file_system/file_system.go | 12 ++++---- file_system/node.go | 28 ++++++++++-------- 7 files changed, 122 insertions(+), 35 deletions(-) create mode 100644 Documentation/errorcode.md diff --git a/Documentation/errorcode.md b/Documentation/errorcode.md new file mode 100644 index 000000000..3a0443f8b --- /dev/null +++ b/Documentation/errorcode.md @@ -0,0 +1,58 @@ +Error Code +====== + +This document describes the error code in **Etcd** project. + +It's categorized into four groups: + +- Command Related Error +- Post Form Related Error +- Raft Related Error +- Etcd Related Error + +Error code corresponding strerror +------ + + const ( + EcodeKeyNotFound = 100 + EcodeTestFailed = 101 + EcodeNotFile = 102 + EcodeNoMoreMachine = 103 + EcodeNotDir = 104 + EcodeNodeExist = 105 + EcodeKeyIsPreserved = 106 + + EcodeValueRequired = 200 + EcodePrevValueRequired = 201 + EcodeTTLNaN = 202 + EcodeIndexNaN = 203 + + EcodeRaftInternal = 300 + EcodeLeaderElect = 301 + + EcodeWatcherCleared = 400 + EcodeEventIndexCleared = 401 + ) + + // command related errors + errors[100] = "Key Not Found" + errors[101] = "Test Failed" //test and set + errors[102] = "Not A File" + errors[103] = "Reached the max number of machines in the cluster" + errors[104] = "Not A Directory" + errors[105] = "Already exists" // create + errors[106] = "The prefix of given key is a keyword in etcd" + + // Post form related errors + errors[200] = "Value is Required in POST form" + errors[201] = "PrevValue is Required in POST form" + errors[202] = "The given TTL in POST form is not a number" + errors[203] = "The given index in POST form is not a number" + + // raft related errors + errors[300] = "Raft Internal Error" + errors[301] = "During Leader Election" + + // etcd related errors + errors[400] = "watcher is cleared due to etcd recovery" + errors[401] = "The event in requested index is outdated and cleared" diff --git a/command.go b/command.go index b9c3a83f6..d03b4dc2e 100644 --- a/command.go +++ b/command.go @@ -156,7 +156,7 @@ func (c *JoinCommand) Apply(raftServer *raft.Server) (interface{}, error) { num := machineNum() if num == maxClusterSize { debug("Reject join request from ", c.Name) - return []byte{0}, etcdErr.NewError(103, "") + return []byte{0}, etcdErr.NewError(etcdErr.EcodeNoMoreMachine, "") } addNameToURL(c.Name, c.RaftVersion, c.RaftURL, c.EtcdURL) diff --git a/error/error.go b/error/error.go index baa395fb9..d97158cf1 100644 --- a/error/error.go +++ b/error/error.go @@ -7,18 +7,38 @@ import ( var errors map[int]string -const () +const ( + EcodeKeyNotFound = 100 + EcodeTestFailed = 101 + EcodeNotFile = 102 + EcodeNoMoreMachine = 103 + EcodeNotDir = 104 + EcodeNodeExist = 105 + EcodeKeyIsPreserved = 106 + + EcodeValueRequired = 200 + EcodePrevValueRequired = 201 + EcodeTTLNaN = 202 + EcodeIndexNaN = 203 + + EcodeRaftInternal = 300 + EcodeLeaderElect = 301 + + EcodeWatcherCleared = 400 + EcodeEventIndexCleared = 401 +) func init() { errors = make(map[int]string) // command related errors errors[100] = "Key Not Found" - errors[101] = "Test Failed" + errors[101] = "Test Failed" //test and set errors[102] = "Not A File" errors[103] = "Reached the max number of machines in the cluster" errors[104] = "Not A Directory" - errors[105] = "Already exists" + errors[105] = "Already exists" // create + errors[106] = "The prefix of given key is a keyword in etcd" // Post form related errors errors[200] = "Value is Required in POST form" @@ -30,11 +50,9 @@ func init() { errors[300] = "Raft Internal Error" errors[301] = "During Leader Election" - // keyword - errors[400] = "The prefix of the given key is a keyword in etcd" - // etcd related errors - errors[500] = "watcher is cleared due to etcd recovery" + errors[400] = "watcher is cleared due to etcd recovery" + errors[401] = "The event in requested index is outdated and cleared" } diff --git a/etcd_handlers.go b/etcd_handlers.go index c0e82530a..7b8b0829e 100644 --- a/etcd_handlers.go +++ b/etcd_handlers.go @@ -68,7 +68,7 @@ func SetHttpHandler(w http.ResponseWriter, req *http.Request) error { key := req.URL.Path[len("/v1/keys/"):] if store.CheckKeyword(key) { - return etcdErr.NewError(400, "Set") + return etcdErr.NewError(etcdErr.EcodeKeyIsPreserved, "Set") } debugf("[recv] POST %v/v1/keys/%s [%s]", e.url, key, req.RemoteAddr) @@ -76,7 +76,7 @@ func SetHttpHandler(w http.ResponseWriter, req *http.Request) error { value := req.FormValue("value") if len(value) == 0 { - return etcdErr.NewError(200, "Set") + return etcdErr.NewError(etcdErr.EcodeValueRequired, "Set") } prevValue := req.FormValue("prevValue") @@ -86,7 +86,7 @@ func SetHttpHandler(w http.ResponseWriter, req *http.Request) error { expireTime, err := durationToExpireTime(strDuration) if err != nil { - return etcdErr.NewError(202, "Set") + return etcdErr.NewError(etcdErr.EcodeTTLNaN, "Set") } if len(prevValue) != 0 { @@ -131,7 +131,7 @@ func dispatch(c Command, w http.ResponseWriter, req *http.Request, etcd bool) er return err } else { if body == nil { - return etcdErr.NewError(300, "Empty result from raft") + return etcdErr.NewError(etcdErr.EcodeRaftInternal, "Empty result from raft") } else { body, _ := body.([]byte) w.WriteHeader(http.StatusOK) @@ -144,7 +144,7 @@ func dispatch(c Command, w http.ResponseWriter, req *http.Request, etcd bool) er leader := r.Leader() // current no leader if leader == "" { - return etcdErr.NewError(300, "") + return etcdErr.NewError(etcdErr.EcodeRaftInternal, "") } // tell the client where is the leader @@ -165,7 +165,7 @@ func dispatch(c Command, w http.ResponseWriter, req *http.Request, etcd bool) er http.Redirect(w, req, url, http.StatusTemporaryRedirect) return nil } - return etcdErr.NewError(300, "") + return etcdErr.NewError(etcdErr.EcodeRaftInternal, "") } //-------------------------------------- @@ -185,7 +185,7 @@ func dispatch(c Command, w http.ResponseWriter, req *http.Request, etcd bool) er // w.Write([]byte(raftURL)) // return nil // } else { -// return etcdErr.NewError(301, "") +// return etcdErr.NewError(etcdErr.EcodeLeaderElect, "") // } // } @@ -254,7 +254,7 @@ func WatchHttpHandler(w http.ResponseWriter, req *http.Request) error { sinceIndex, err := strconv.ParseUint(string(content), 10, 64) if err != nil { - return etcdErr.NewError(203, "Watch From Index") + return etcdErr.NewError(etcdErr.EcodeIndexNaN, "Watch From Index") } command.SinceIndex = sinceIndex @@ -264,7 +264,7 @@ func WatchHttpHandler(w http.ResponseWriter, req *http.Request) error { } if body, err := command.Apply(r.Server); err != nil { - return etcdErr.NewError(500, key) + return etcdErr.NewError(etcdErr.EcodeWatcherCleared, key) } else { w.WriteHeader(http.StatusOK) diff --git a/file_system/event.go b/file_system/event.go index 1b2a00dbe..8bea67de2 100644 --- a/file_system/event.go +++ b/file_system/event.go @@ -1,6 +1,8 @@ package fileSystem import ( + "fmt" + etcdErr "github.com/coreos/etcd/error" "strings" "sync" "time" @@ -108,7 +110,10 @@ func (eh *EventHistory) scan(prefix string, index uint64) (*Event, error) { if start < 0 { // TODO: Add error type - return nil, nil + return nil, + etcdErr.NewError(etcdErr.EcodeEventIndexCleared, + fmt.Sprintf("prefix:%v index:%v", prefix, index), + ) } if start >= uint64(eh.Queue.size) { diff --git a/file_system/file_system.go b/file_system/file_system.go index 154f2d464..5f97a03d8 100644 --- a/file_system/file_system.go +++ b/file_system/file_system.go @@ -74,7 +74,7 @@ func (fs *FileSystem) Create(nodePath string, value string, expireTime time.Time _, err := fs.InternalGet(nodePath, index, term) if err == nil { // key already exists - return nil, etcdErr.NewError(105, nodePath) + return nil, etcdErr.NewError(etcdErr.EcodeNodeExist, nodePath) } etcdError, _ := err.(etcdErr.Error) @@ -140,7 +140,7 @@ func (fs *FileSystem) Update(nodePath string, value string, expireTime time.Time if n.IsDir() { // if the node is a directory, we can only update ttl if len(value) != 0 { - return nil, etcdErr.NewError(102, nodePath) + return nil, etcdErr.NewError(etcdErr.EcodeNotFile, nodePath) } } else { // if the node is a file, we can update value and ttl @@ -179,7 +179,7 @@ func (fs *FileSystem) TestAndSet(nodePath string, prevValue string, prevIndex ui } if f.IsDir() { // can only test and set file - return nil, etcdErr.NewError(102, nodePath) + return nil, etcdErr.NewError(etcdErr.EcodeNotFile, nodePath) } if f.Value == prevValue || f.ModifiedIndex == prevIndex { @@ -195,7 +195,7 @@ func (fs *FileSystem) TestAndSet(nodePath string, prevValue string, prevIndex ui } cause := fmt.Sprintf("[%v/%v] [%v/%v]", prevValue, f.Value, prevIndex, f.ModifiedIndex) - return nil, etcdErr.NewError(101, cause) + return nil, etcdErr.NewError(etcdErr.EcodeTestFailed, cause) } // Delete function deletes the node at the given path. @@ -262,7 +262,7 @@ func (fs *FileSystem) InternalGet(nodePath string, index uint64, term uint64) (* walkFunc := func(parent *Node, name string) (*Node, error) { if !parent.IsDir() { - return nil, etcdErr.NewError(104, parent.Path) + return nil, etcdErr.NewError(etcdErr.EcodeNotDir, parent.Path) } child, ok := parent.Children[name] @@ -270,7 +270,7 @@ func (fs *FileSystem) InternalGet(nodePath string, index uint64, term uint64) (* return child, nil } - return nil, etcdErr.NewError(100, path.Join(parent.Path, name)) + return nil, etcdErr.NewError(etcdErr.EcodeKeyNotFound, path.Join(parent.Path, name)) } f, err := fs.walk(nodePath, walkFunc) diff --git a/file_system/node.go b/file_system/node.go index 362584712..de39c5545 100644 --- a/file_system/node.go +++ b/file_system/node.go @@ -93,7 +93,7 @@ func (n *Node) Remove(recursive bool, callback func(path string)) error { } if !recursive { - return etcdErr.NewError(102, "") + return etcdErr.NewError(etcdErr.EcodeNotFile, "") } for _, child := range n.Children { // delete all children @@ -116,21 +116,21 @@ func (n *Node) Remove(recursive bool, callback func(path string)) error { return nil } -// Get function gets the value of the node. +// Read function gets the value of the node. // If the receiver node is not a key-value pair, a "Not A File" error will be returned. func (n *Node) Read() (string, error) { if n.IsDir() { - return "", etcdErr.NewError(102, "") + return "", etcdErr.NewError(etcdErr.EcodeNotFile, "") } return n.Value, nil } -// Set function set the value of the node to the given value. +// Write function set the value of the node to the given value. // If the receiver node is a directory, a "Not A File" error will be returned. func (n *Node) Write(value string, index uint64, term uint64) error { if n.IsDir() { - return etcdErr.NewError(102, "") + return etcdErr.NewError(etcdErr.EcodeNotFile, "") } n.Value = value @@ -146,7 +146,7 @@ func (n *Node) List() ([]*Node, error) { n.mu.Lock() defer n.mu.Unlock() if !n.IsDir() { - return nil, etcdErr.NewError(104, "") + return nil, etcdErr.NewError(etcdErr.EcodeNotDir, "") } nodes := make([]*Node, len(n.Children)) @@ -160,12 +160,18 @@ func (n *Node) List() ([]*Node, error) { return nodes, nil } +// GetFile function returns the file node under the directory node. +// On success, it returns the file node +// If the node that calls this function is not a directory, it returns +// Not Directory Error +// If the node corresponding to the name string is not file, it returns +// Not File Error func (n *Node) GetFile(name string) (*Node, error) { n.mu.Lock() defer n.mu.Unlock() if !n.IsDir() { - return nil, etcdErr.NewError(104, n.Path) + return nil, etcdErr.NewError(etcdErr.EcodeNotDir, n.Path) } f, ok := n.Children[name] @@ -174,7 +180,7 @@ func (n *Node) GetFile(name string) (*Node, error) { if !f.IsDir() { return f, nil } else { - return nil, etcdErr.NewError(102, f.Path) + return nil, etcdErr.NewError(etcdErr.EcodeNotFile, f.Path) } } @@ -190,11 +196,11 @@ func (n *Node) Add(child *Node) error { n.mu.Lock() defer n.mu.Unlock() if n.status == removed { - return etcdErr.NewError(100, "") + return etcdErr.NewError(etcdErr.EcodeKeyNotFound, "") } if !n.IsDir() { - return etcdErr.NewError(104, "") + return etcdErr.NewError(etcdErr.EcodeNotDir, "") } _, name := path.Split(child.Path) @@ -202,7 +208,7 @@ func (n *Node) Add(child *Node) error { _, ok := n.Children[name] if ok { - return etcdErr.NewError(105, "") + return etcdErr.NewError(etcdErr.EcodeNodeExist, "") } n.Children[name] = child