From a131632d3d94e15e467c1741738a1d448cba3753 Mon Sep 17 00:00:00 2001 From: Xiang Li Date: Fri, 12 Jul 2013 08:41:28 -0700 Subject: [PATCH 1/7] error handling --- client_handlers.go | 61 +++++++++++++++++++----- command.go | 4 +- etcd.go | 4 +- store/error.go | 23 +++++++++ store/store.go | 113 +++++++++++++++++++++++++++++++-------------- 5 files changed, 156 insertions(+), 49 deletions(-) create mode 100644 store/error.go diff --git a/client_handlers.go b/client_handlers.go index fd447be0d..acb64919b 100644 --- a/client_handlers.go +++ b/client_handlers.go @@ -1,6 +1,7 @@ package main import ( + "github.com/coreos/etcd/store" "net/http" "strconv" "time" @@ -40,6 +41,13 @@ func SetHttpHandler(w *http.ResponseWriter, req *http.Request) { command.Key = key command.Value = req.FormValue("value") + + if len(command.Value) == 0 { + (*w).WriteHeader(http.StatusBadRequest) + (*w).Write([]byte("Set: Value Required\n")) + return + } + strDuration := req.FormValue("ttl") var err error @@ -66,6 +74,19 @@ func TestAndSetHttpHandler(w http.ResponseWriter, req *http.Request) { command.PrevValue = req.FormValue("prevValue") command.Value = req.FormValue("value") + + if len(command.Value) == 0 { + (w).WriteHeader(http.StatusBadRequest) + (w).Write([]byte("TestAndSet: Value Required\n")) + return + } + + if len(command.PrevValue) == 0 { + (w).WriteHeader(http.StatusBadRequest) + (w).Write([]byte("TestAndSet: PrevValue Required\n")) + return + } + strDuration := req.FormValue("ttl") var err error @@ -97,22 +118,31 @@ func DeleteHttpHandler(w *http.ResponseWriter, req *http.Request) { func dispatch(c Command, w *http.ResponseWriter, req *http.Request, client bool) { if raftServer.State() == "leader" { if body, err := raftServer.Do(c); err != nil { - warn("Commit failed %v", err) + if _, ok := err.(store.NotFoundError); ok { + http.NotFound((*w), req) + return + } + + if _, ok := err.(store.TestFail); ok { + (*w).WriteHeader(http.StatusBadRequest) + (*w).Write([]byte(err.Error() + "\n")) + return + } (*w).WriteHeader(http.StatusInternalServerError) return } else { - (*w).WriteHeader(http.StatusOK) - - if body == nil { - return - } body, ok := body.([]byte) if !ok { panic("wrong type") } - (*w).Write(body) + if body == nil { + http.NotFound((*w), req) + } else { + (*w).WriteHeader(http.StatusOK) + (*w).Write(body) + } return } } else { @@ -174,18 +204,23 @@ func GetHttpHandler(w *http.ResponseWriter, req *http.Request) { command.Key = key if body, err := command.Apply(raftServer); err != nil { - warn("raftd: Unable to write file: %v", err) + + if _, ok := err.(store.NotFoundError); ok { + http.NotFound((*w), req) + return + } + (*w).WriteHeader(http.StatusInternalServerError) return } else { - (*w).WriteHeader(http.StatusOK) - body, ok := body.([]byte) if !ok { panic("wrong type") } + (*w).WriteHeader(http.StatusOK) (*w).Write(body) + return } @@ -201,7 +236,10 @@ func ListHttpHandler(w http.ResponseWriter, req *http.Request) { command.Prefix = prefix if body, err := command.Apply(raftServer); err != nil { - warn("Unable to write file: %v", err) + if _, ok := err.(store.NotFoundError); ok { + http.NotFound(w, req) + return + } w.WriteHeader(http.StatusInternalServerError) return } else { @@ -238,6 +276,7 @@ func WatchHttpHandler(w http.ResponseWriter, req *http.Request) { sinceIndex, err := strconv.ParseUint(string(content), 10, 64) if err != nil { w.WriteHeader(http.StatusBadRequest) + (w).Write([]byte("Watch From Index: Vaild Index Required\n")) } command.SinceIndex = sinceIndex diff --git a/command.go b/command.go index 1aeb5e2d8..865b308e3 100644 --- a/command.go +++ b/command.go @@ -2,6 +2,7 @@ package main import ( "encoding/json" + //"errors" "github.com/coreos/etcd/store" "github.com/coreos/go-raft" "time" @@ -60,8 +61,7 @@ func (c *GetCommand) CommandName() string { // Get the value of key func (c *GetCommand) Apply(server *raft.Server) (interface{}, error) { - res := etcdStore.Get(c.Key) - return json.Marshal(res) + return etcdStore.Get(c.Key) } // List command diff --git a/etcd.go b/etcd.go index 45522d1ff..4d324a33e 100644 --- a/etcd.go +++ b/etcd.go @@ -91,9 +91,9 @@ const ( ELECTIONTIMTOUT = 200 * time.Millisecond HEARTBEATTIMEOUT = 50 * time.Millisecond // Timeout for internal raft http connection - // The origin timeout for http is 45 seconds + // The origin timeout for http is 45 seconds // which is too long for our usage. - HTTPTIMEOUT = time.Second + HTTPTIMEOUT = time.Second ) //------------------------------------------------------------------------------ diff --git a/store/error.go b/store/error.go new file mode 100644 index 000000000..32ac4204d --- /dev/null +++ b/store/error.go @@ -0,0 +1,23 @@ +package store + +import ( + "fmt" + ) + +type NotFoundError string + +func (e NotFoundError) Error() string { + return fmt.Sprintf("Key %s Not Found", string(e)) +} + +type NotFile string + +func (e NotFile) Error() string { + return fmt.Sprintf("Try to set value to a dir %s", string(e)) +} + +type TestFail string + +func (e TestFail) Error() string { + return fmt.Sprintf("Test %s fails", string(e)) +} \ No newline at end of file diff --git a/store/store.go b/store/store.go index d4bc4e8f4..a50e4d68b 100644 --- a/store/store.go +++ b/store/store.go @@ -64,17 +64,17 @@ type Node struct { type Response struct { Action string `json:"action"` Key string `json:"key"` - PrevValue string `json:"prevValue"` - Value string `json:"value"` + PrevValue string `json:"prevValue,omitempty"` + Value string `json:"value,omitempty"` // If the key existed before the action, this field should be true // If the key did not exist before the action, this field should be false - Exist bool `json:"exist"` + NewKey bool `json:"newKey,omitempty"` - Expiration time.Time `json:"expiration"` + Expiration *time.Time `json:"expiration,omitempty"` // Time to live in second - TTL int64 `json:"ttl"` + TTL int64 `json:"ttl,omitempty"` // The command index of the raft machine when the command is executed Index uint64 `json:"index"` @@ -142,6 +142,14 @@ func (s *Store) Set(key string, value string, expireTime time.Time, index uint64 isExpire := !expireTime.Equal(PERMANENT) + // base response + resp := Response{ + Action: "SET", + Key: key, + Value: value, + Index: index, + } + // When the slow follower receive the set command // the key may be expired, we should not add the node // also if the node exist, we need to delete the node @@ -154,10 +162,9 @@ func (s *Store) Set(key string, value string, expireTime time.Time, index uint64 // Update ttl if isExpire { TTL = int64(expireTime.Sub(time.Now()) / time.Second) - } else { - // For permanent value, we set ttl to -1 - TTL = -1 - } + resp.Expiration = &expireTime + resp.TTL = TTL + } // Get the node node, ok := s.Tree.get(key) @@ -186,7 +193,7 @@ func (s *Store) Set(key string, value string, expireTime time.Time, index uint64 // Update the information of the node s.Tree.set(key, Node{value, expireTime, node.update}) - resp := Response{"SET", key, node.Value, value, true, expireTime, TTL, index} + resp.PrevValue = node.Value s.watcher.notify(resp) @@ -207,13 +214,18 @@ func (s *Store) Set(key string, value string, expireTime time.Time, index uint64 update := make(chan time.Time) - s.Tree.set(key, Node{value, expireTime, update}) + ok := s.Tree.set(key, Node{value, expireTime, update}) + + if !ok { + err := NotFile(key) + return nil, err + } if isExpire { go s.monitorExpiration(key, update, expireTime) } - resp := Response{"SET", key, "", value, false, expireTime, TTL, index} + resp.NewKey = true msg, err := json.Marshal(resp) @@ -232,7 +244,19 @@ func (s *Store) Set(key string, value string, expireTime time.Time, index uint64 } // Get the value of the key -func (s *Store) Get(key string) Response { +func (s *Store) Get(key string) ([]byte, error) { + resp := s.internalGet(key) + + if resp != nil { + return json.Marshal(resp) + } else { + err := NotFoundError(key) + return nil, err + } +} + +// Get the value of the key and return the raw response +func (s *Store) internalGet(key string) *Response { key = path.Clean("/" + key) @@ -244,21 +268,29 @@ func (s *Store) Get(key string) Response { isExpire = !node.ExpireTime.Equal(PERMANENT) + resp := &Response{ + Action: "GET", + Key: key, + Value: node.Value, + Index: s.Index, + } + // Update ttl if isExpire { TTL = int64(node.ExpireTime.Sub(time.Now()) / time.Second) - } else { - TTL = -1 - } + resp.Expiration = &node.ExpireTime + resp.TTL = TTL + } - return Response{"GET", key, node.Value, node.Value, true, node.ExpireTime, TTL, s.Index} + return resp } else { // we do not found the key - return Response{"GET", key, "", "", false, time.Unix(0, 0), 0, s.Index} + return nil } } + // List all the item in the prefix func (s *Store) List(prefix string) ([]byte, error) { @@ -273,7 +305,8 @@ func (s *Store) List(prefix string) ([]byte, error) { } } - return json.Marshal(ln) + err := NotFoundError(prefix) + return nil, err } // Delete the key @@ -288,20 +321,25 @@ func (s *Store) Delete(key string, index uint64) ([]byte, error) { if ok { + resp := Response{ + Action: "DELETE", + Key: key, + PrevValue: node.Value, + Index: index, + } + if node.ExpireTime.Equal(PERMANENT) { s.Tree.delete(key) } else { - + resp.Expiration = &node.ExpireTime // Kill the expire go routine node.update <- PERMANENT s.Tree.delete(key) } - resp := Response{"DELETE", key, node.Value, "", true, node.ExpireTime, 0, index} - msg, err := json.Marshal(resp) s.watcher.notify(resp) @@ -317,28 +355,29 @@ func (s *Store) Delete(key string, index uint64) ([]byte, error) { return msg, err } else { - - resp := Response{"DELETE", key, "", "", false, time.Unix(0, 0), 0, index} - - s.addToResponseMap(index, &resp) - - return json.Marshal(resp) + err := NotFoundError(key) + return nil, err } } // Set the value of the key to the value if the given prevValue is equal to the value of the key func (s *Store) TestAndSet(key string, prevValue string, value string, expireTime time.Time, index uint64) ([]byte, error) { - resp := s.Get(key) + resp := s.internalGet(key) - if resp.PrevValue == prevValue { + if resp == nil { + err := NotFoundError(key) + return nil, err + } + + if resp.Value == prevValue { // If test success, do set return s.Set(key, value, expireTime, index) } else { - // If fails, return the result of get which contains the current - // status of the key-value pair - return json.Marshal(resp) + // If fails, return err + err := TestFail(fmt.Sprintf("%s==%s", resp.Value, prevValue)) + return nil, err } } @@ -371,7 +410,13 @@ func (s *Store) monitorExpiration(key string, update chan time.Time, expireTime s.Tree.delete(key) - resp := Response{"DELETE", key, node.Value, "", true, node.ExpireTime, 0, s.Index} + resp := Response{ + Action: "DELETE", + Key: key, + PrevValue: node.Value, + Expiration: &node.ExpireTime, + Index: s.Index, + } msg, err := json.Marshal(resp) From 00d2d6eb4eaec5ed56e8bda5d14dfc426a8d9e5b Mon Sep 17 00:00:00 2001 From: Xiang Li Date: Fri, 12 Jul 2013 08:56:10 -0700 Subject: [PATCH 2/7] gofmt --- etcd.go | 4 ++-- transporter.go | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/etcd.go b/etcd.go index 6cfafcc72..f2a9bb845 100644 --- a/etcd.go +++ b/etcd.go @@ -90,9 +90,9 @@ const ( const ( ELECTIONTIMTOUT = 200 * time.Millisecond HEARTBEATTIMEOUT = 50 * time.Millisecond - + // Timeout for internal raft http connection - // The original timeout for http is 45 seconds + // The original timeout for http is 45 seconds // which is too long for our usage. HTTPTIMEOUT = time.Second ) diff --git a/transporter.go b/transporter.go index c68f062da..159f015ab 100644 --- a/transporter.go +++ b/transporter.go @@ -102,12 +102,12 @@ func (t transporter) GetLeaderClientAddress() string { // Send server side POST request func (t transporter) Post(path string, body io.Reader) (*http.Response, error) { - resp, err := t.client.Post(t.scheme + path, "application/json", body) - return resp, err + resp, err := t.client.Post(t.scheme+path, "application/json", body) + return resp, err } // Send server side GET request func (t transporter) Get(path string) (*http.Response, error) { - resp, err := t.client.Get(t.scheme + path) - return resp, err + resp, err := t.client.Get(t.scheme + path) + return resp, err } From 8fe8711d8d2a6b0c45b238d8aaecb3275122a307 Mon Sep 17 00:00:00 2001 From: Xiang Li Date: Fri, 12 Jul 2013 10:42:07 -0700 Subject: [PATCH 3/7] return json format error --- client_handlers.go | 36 +++++++++++++++++++++++------------- error.go | 18 ++++++++++++++++++ 2 files changed, 41 insertions(+), 13 deletions(-) create mode 100644 error.go diff --git a/client_handlers.go b/client_handlers.go index acb64919b..81a0b0ed1 100644 --- a/client_handlers.go +++ b/client_handlers.go @@ -44,7 +44,8 @@ func SetHttpHandler(w *http.ResponseWriter, req *http.Request) { if len(command.Value) == 0 { (*w).WriteHeader(http.StatusBadRequest) - (*w).Write([]byte("Set: Value Required\n")) + + (*w).Write(newJsonError("400", "Value is Required")) return } @@ -55,8 +56,10 @@ func SetHttpHandler(w *http.ResponseWriter, req *http.Request) { command.ExpireTime, err = durationToExpireTime(strDuration) if err != nil { - warn("The given duration is not a number: %v", err) - (*w).WriteHeader(http.StatusInternalServerError) + + (*w).WriteHeader(http.StatusBadRequest) + + (*w).Write(newJsonError("400", "The given TTL is not a number")) } dispatch(command, w, req, true) @@ -76,14 +79,17 @@ func TestAndSetHttpHandler(w http.ResponseWriter, req *http.Request) { command.Value = req.FormValue("value") if len(command.Value) == 0 { - (w).WriteHeader(http.StatusBadRequest) - (w).Write([]byte("TestAndSet: Value Required\n")) + w.WriteHeader(http.StatusBadRequest) + + w.Write(newJsonError("400", "TestAndSet: Value Required")) + return } if len(command.PrevValue) == 0 { - (w).WriteHeader(http.StatusBadRequest) - (w).Write([]byte("TestAndSet: PrevValue Required\n")) + w.WriteHeader(http.StatusBadRequest) + + w.Write(newJsonError("400", "TestAndSet: PrevValue Required")) return } @@ -94,8 +100,9 @@ func TestAndSetHttpHandler(w http.ResponseWriter, req *http.Request) { command.ExpireTime, err = durationToExpireTime(strDuration) if err != nil { - warn("The given duration is not a number: %v", err) - w.WriteHeader(http.StatusInternalServerError) + w.WriteHeader(http.StatusBadRequest) + + w.Write(newJsonError("400", "The given TTL is not a number")) } dispatch(command, &w, req, true) @@ -125,10 +132,11 @@ func dispatch(c Command, w *http.ResponseWriter, req *http.Request, client bool) if _, ok := err.(store.TestFail); ok { (*w).WriteHeader(http.StatusBadRequest) - (*w).Write([]byte(err.Error() + "\n")) + (*w).Write(newJsonError("400", err.Error())) return } (*w).WriteHeader(http.StatusInternalServerError) + (*w).Write(newJsonError("500", "Internal Error")) return } else { @@ -149,6 +157,7 @@ func dispatch(c Command, w *http.ResponseWriter, req *http.Request, client bool) // current no leader if raftServer.Leader() == "" { (*w).WriteHeader(http.StatusInternalServerError) + (*w).Write(newJsonError("500", "During Leader Election Period")) return } @@ -175,9 +184,8 @@ func dispatch(c Command, w *http.ResponseWriter, req *http.Request, client bool) http.Redirect(*w, req, url, http.StatusTemporaryRedirect) return } - (*w).WriteHeader(http.StatusInternalServerError) - + (*w).Write(newJsonError("500", "Internal Error")) return } @@ -211,6 +219,7 @@ func GetHttpHandler(w *http.ResponseWriter, req *http.Request) { } (*w).WriteHeader(http.StatusInternalServerError) + (*w).Write(newJsonError("500", "Internal Error")) return } else { body, ok := body.([]byte) @@ -241,6 +250,7 @@ func ListHttpHandler(w http.ResponseWriter, req *http.Request) { return } w.WriteHeader(http.StatusInternalServerError) + w.Write(newJsonError("500", "Internal Error")) return } else { w.WriteHeader(http.StatusOK) @@ -276,7 +286,7 @@ func WatchHttpHandler(w http.ResponseWriter, req *http.Request) { sinceIndex, err := strconv.ParseUint(string(content), 10, 64) if err != nil { w.WriteHeader(http.StatusBadRequest) - (w).Write([]byte("Watch From Index: Vaild Index Required\n")) + w.Write(newJsonError("400", "Watch From Index: Vaild Index Required")) } command.SinceIndex = sinceIndex diff --git a/error.go b/error.go new file mode 100644 index 000000000..99af5eca2 --- /dev/null +++ b/error.go @@ -0,0 +1,18 @@ +package main + +import ( + "encoding/json" +) + +type jsonError struct { + StatusCode string `json:"statusCode"` + Message string `json:"message"` +} + +func newJsonError(statusCode string, message string) []byte { + b, _ := json.Marshal(jsonError{ + StatusCode: "400", + Message: "Set: Value Required", + }) + return b +} From 78d50fe9d15c61ebe8aeb11c738cbb30ed562d89 Mon Sep 17 00:00:00 2001 From: Xiang Li Date: Fri, 12 Jul 2013 10:43:29 -0700 Subject: [PATCH 4/7] fix a copy paste error --- error.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/error.go b/error.go index 99af5eca2..f4b46bdbb 100644 --- a/error.go +++ b/error.go @@ -11,8 +11,8 @@ type jsonError struct { func newJsonError(statusCode string, message string) []byte { b, _ := json.Marshal(jsonError{ - StatusCode: "400", - Message: "Set: Value Required", + StatusCode: statusCode, + Message: message, }) return b } From 0aa70e125cd2c92c513aef2dc7097ff704d81cf8 Mon Sep 17 00:00:00 2001 From: Xiang Li Date: Fri, 12 Jul 2013 13:35:43 -0700 Subject: [PATCH 5/7] create error map --- client_handlers.go | 24 ++++++++++++------------ error.go | 31 +++++++++++++++++++++++++------ store/error.go | 10 +++------- store/store.go | 2 +- 4 files changed, 41 insertions(+), 26 deletions(-) diff --git a/client_handlers.go b/client_handlers.go index 81a0b0ed1..c151b05d9 100644 --- a/client_handlers.go +++ b/client_handlers.go @@ -45,7 +45,7 @@ func SetHttpHandler(w *http.ResponseWriter, req *http.Request) { if len(command.Value) == 0 { (*w).WriteHeader(http.StatusBadRequest) - (*w).Write(newJsonError("400", "Value is Required")) + (*w).Write(newJsonError(200, "")) return } @@ -59,7 +59,7 @@ func SetHttpHandler(w *http.ResponseWriter, req *http.Request) { (*w).WriteHeader(http.StatusBadRequest) - (*w).Write(newJsonError("400", "The given TTL is not a number")) + (*w).Write(newJsonError(202, "")) } dispatch(command, w, req, true) @@ -81,7 +81,7 @@ func TestAndSetHttpHandler(w http.ResponseWriter, req *http.Request) { if len(command.Value) == 0 { w.WriteHeader(http.StatusBadRequest) - w.Write(newJsonError("400", "TestAndSet: Value Required")) + w.Write(newJsonError(200, "TestAndSet")) return } @@ -89,7 +89,7 @@ func TestAndSetHttpHandler(w http.ResponseWriter, req *http.Request) { if len(command.PrevValue) == 0 { w.WriteHeader(http.StatusBadRequest) - w.Write(newJsonError("400", "TestAndSet: PrevValue Required")) + w.Write(newJsonError(201, "TestAndSet")) return } @@ -102,7 +102,7 @@ func TestAndSetHttpHandler(w http.ResponseWriter, req *http.Request) { if err != nil { w.WriteHeader(http.StatusBadRequest) - w.Write(newJsonError("400", "The given TTL is not a number")) + w.Write(newJsonError(202, "TestAndSet")) } dispatch(command, &w, req, true) @@ -132,11 +132,11 @@ func dispatch(c Command, w *http.ResponseWriter, req *http.Request, client bool) if _, ok := err.(store.TestFail); ok { (*w).WriteHeader(http.StatusBadRequest) - (*w).Write(newJsonError("400", err.Error())) + (*w).Write(newJsonError(101, err.Error())) return } (*w).WriteHeader(http.StatusInternalServerError) - (*w).Write(newJsonError("500", "Internal Error")) + (*w).Write(newJsonError(300, "")) return } else { @@ -157,7 +157,7 @@ func dispatch(c Command, w *http.ResponseWriter, req *http.Request, client bool) // current no leader if raftServer.Leader() == "" { (*w).WriteHeader(http.StatusInternalServerError) - (*w).Write(newJsonError("500", "During Leader Election Period")) + (*w).Write(newJsonError(300, "")) return } @@ -185,7 +185,7 @@ func dispatch(c Command, w *http.ResponseWriter, req *http.Request, client bool) return } (*w).WriteHeader(http.StatusInternalServerError) - (*w).Write(newJsonError("500", "Internal Error")) + (*w).Write(newJsonError(300, "")) return } @@ -219,7 +219,7 @@ func GetHttpHandler(w *http.ResponseWriter, req *http.Request) { } (*w).WriteHeader(http.StatusInternalServerError) - (*w).Write(newJsonError("500", "Internal Error")) + (*w).Write(newJsonError(300, "")) return } else { body, ok := body.([]byte) @@ -250,7 +250,7 @@ func ListHttpHandler(w http.ResponseWriter, req *http.Request) { return } w.WriteHeader(http.StatusInternalServerError) - w.Write(newJsonError("500", "Internal Error")) + w.Write(newJsonError(300, "")) return } else { w.WriteHeader(http.StatusOK) @@ -286,7 +286,7 @@ func WatchHttpHandler(w http.ResponseWriter, req *http.Request) { sinceIndex, err := strconv.ParseUint(string(content), 10, 64) if err != nil { w.WriteHeader(http.StatusBadRequest) - w.Write(newJsonError("400", "Watch From Index: Vaild Index Required")) + w.Write(newJsonError(203, "Watch From Index")) } command.SinceIndex = sinceIndex diff --git a/error.go b/error.go index f4b46bdbb..4de0c7494 100644 --- a/error.go +++ b/error.go @@ -4,15 +4,34 @@ import ( "encoding/json" ) -type jsonError struct { - StatusCode string `json:"statusCode"` - Message string `json:"message"` +var errors map[int]string + +func init() { + errors = make(map[int]string) + + // command related errors + errors[100] = "Key Not Found" + errors[101] = "The given PrevValue is not equal to the value of the key" + // 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" } -func newJsonError(statusCode string, message string) []byte { +type jsonError struct { + ErrorCode int `json:"errorCode"` + Message string `json:"message"` + Cause string `json:"cause,omitempty"` +} + +func newJsonError(errorCode int, cause string) []byte { b, _ := json.Marshal(jsonError{ - StatusCode: statusCode, - Message: message, + ErrorCode: errorCode, + Message: errors[errorCode], + Cause: cause, }) return b } diff --git a/store/error.go b/store/error.go index 32ac4204d..3f13f83a5 100644 --- a/store/error.go +++ b/store/error.go @@ -1,23 +1,19 @@ package store -import ( - "fmt" - ) - type NotFoundError string func (e NotFoundError) Error() string { - return fmt.Sprintf("Key %s Not Found", string(e)) + return string(e) } type NotFile string func (e NotFile) Error() string { - return fmt.Sprintf("Try to set value to a dir %s", string(e)) + return string(e) } type TestFail string func (e TestFail) Error() string { - return fmt.Sprintf("Test %s fails", string(e)) + return string(e) } \ No newline at end of file diff --git a/store/store.go b/store/store.go index a50e4d68b..5289208fe 100644 --- a/store/store.go +++ b/store/store.go @@ -376,7 +376,7 @@ func (s *Store) TestAndSet(key string, prevValue string, value string, expireTim } else { // If fails, return err - err := TestFail(fmt.Sprintf("%s==%s", resp.Value, prevValue)) + err := TestFail(fmt.Sprintf("TestAndSet: %s!=%s", resp.Value, prevValue)) return nil, err } From 0b6428edbaf4da7e99847c8960d28d7d55d9820c Mon Sep 17 00:00:00 2001 From: Xiang Li Date: Fri, 12 Jul 2013 13:38:45 -0700 Subject: [PATCH 6/7] add addition msg --- client_handlers.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/client_handlers.go b/client_handlers.go index c151b05d9..07e360db7 100644 --- a/client_handlers.go +++ b/client_handlers.go @@ -45,7 +45,7 @@ func SetHttpHandler(w *http.ResponseWriter, req *http.Request) { if len(command.Value) == 0 { (*w).WriteHeader(http.StatusBadRequest) - (*w).Write(newJsonError(200, "")) + (*w).Write(newJsonError(200, "Set")) return } @@ -59,7 +59,7 @@ func SetHttpHandler(w *http.ResponseWriter, req *http.Request) { (*w).WriteHeader(http.StatusBadRequest) - (*w).Write(newJsonError(202, "")) + (*w).Write(newJsonError(202, "Set")) } dispatch(command, w, req, true) @@ -136,7 +136,7 @@ func dispatch(c Command, w *http.ResponseWriter, req *http.Request, client bool) return } (*w).WriteHeader(http.StatusInternalServerError) - (*w).Write(newJsonError(300, "")) + (*w).Write(newJsonError(300, "No Leader")) return } else { From 3e436473036f4c757403d86dfd009017fc554184 Mon Sep 17 00:00:00 2001 From: Xiang Li Date: Fri, 12 Jul 2013 14:18:02 -0700 Subject: [PATCH 7/7] read machines conf from file --- etcd.go | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/etcd.go b/etcd.go index f2a9bb845..045f8c995 100644 --- a/etcd.go +++ b/etcd.go @@ -29,6 +29,8 @@ import ( var verbose bool var machines string +var machinesFile string + var cluster []string var address string @@ -53,7 +55,8 @@ var maxSize int func init() { flag.BoolVar(&verbose, "v", false, "verbose logging") - flag.StringVar(&machines, "C", "", "the ip address and port of a existing machines in cluster, sepearate by comma") + flag.StringVar(&machines, "C", "", "the ip address and port of a existing machines in the cluster, sepearate by comma") + flag.StringVar(&machinesFile, "CF", "", "the file contains a list of existing machines in the cluster, seperate by comma") flag.StringVar(&address, "a", "0.0.0.0", "the ip address of the local machine") flag.IntVar(&clientPort, "c", 4001, "the port to communicate with clients") @@ -142,14 +145,22 @@ var info *Info func main() { flag.Parse() - cluster = strings.Split(machines, ",") + if machines != "" { + cluster = strings.Split(machines, ",") + } else if machinesFile != "" { + b, err := ioutil.ReadFile(machinesFile) + if err != nil { + fatal("Unable to read the given machines file: %s", err) + } + cluster = strings.Split(string(b), ",") + } // Setup commands. registerCommands() // Read server info from file or grab it from user. if err := os.MkdirAll(dirPath, 0744); err != nil { - fatal("Unable to create path: %v", err) + fatal("Unable to create path: %s", err) } info = getInfo(dirPath)