Browse Source

New error-system for Etcd with docs

Hongchao Deng 12 years ago
parent
commit
effc8285f2
7 changed files with 122 additions and 35 deletions
  1. 58 0
      Documentation/errorcode.md
  2. 1 1
      command.go
  3. 25 7
      error/error.go
  4. 9 9
      etcd_handlers.go
  5. 6 1
      file_system/event.go
  6. 6 6
      file_system/file_system.go
  7. 17 11
      file_system/node.go

+ 58 - 0
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"

+ 1 - 1
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)

+ 25 - 7
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"
 
 }
 

+ 9 - 9
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)
 

+ 6 - 1
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) {

+ 6 - 6
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)

+ 17 - 11
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