فهرست منبع

Merge branch 'master' into moreStats

Xiang Li 12 سال پیش
والد
کامیت
197689fcb5
5فایلهای تغییر یافته به همراه142 افزوده شده و 95 حذف شده
  1. 5 4
      README.md
  2. 11 11
      build
  3. 2 0
      etcd_handlers.go
  4. 88 80
      store/store.go
  5. 36 0
      store/store_test.go

+ 5 - 4
README.md

@@ -30,6 +30,7 @@ You can build etcd from source:
 
 ```sh
 git clone https://github.com/coreos/etcd
+cd etcd
 ./build
 ```
 
@@ -141,7 +142,7 @@ Now you can try to get the key by sending:
 curl -L http://127.0.0.1:4001/v1/keys/foo
 ```
 
-If the TTL has expired, the key will be deleted, and you will be returned a 404.
+If the TTL has expired, the key will be deleted, and you will be returned a 100.
 
 ```json
 {"errorCode":100,"message":"Key Not Found","cause":"/foo"}
@@ -356,7 +357,7 @@ Let the join two more nodes to this cluster using the -C argument:
 Get the machines in the cluster:
 
 ```sh
-curl -L http://127.0.0.1:4001/machines
+curl -L http://127.0.0.1:4001/v1/machines
 ```
 
 We should see there are three nodes in the cluster
@@ -380,7 +381,7 @@ The key of the machine is based on the ```commit index``` when it was added. The
 Also try to get the current leader in the cluster
 
 ```
-curl -L http://127.0.0.1:4001/leader
+curl -L http://127.0.0.1:4001/v1/leader
 ```
 The first server we set up should be the leader, if it has not dead during these commands.
 
@@ -409,7 +410,7 @@ curl -L http://127.0.0.1:4002/v1/keys/foo
 A new leader should have been elected.
 
 ```
-curl -L http://127.0.0.1:4001/leader
+curl -L http://127.0.0.1:4001/v1/leader
 ```
 
 ```

+ 11 - 11
build

@@ -1,25 +1,25 @@
 #!/bin/bash
 
 ETCD_PACKAGE=github.com/coreos/etcd
-export GOPATH=${PWD}
-SRC_DIR=$GOPATH/src
-ETCD_DIR=$SRC_DIR/$ETCD_PACKAGE
+export GOPATH="${PWD}"
+SRC_DIR="$GOPATH/src"
+ETCD_DIR="$SRC_DIR/$ETCD_PACKAGE"
 
-ETCD_BASE=$(dirname ${ETCD_DIR})
-if [ ! -d ${ETCD_BASE} ]; then
-	mkdir -p ${ETCD_BASE}
+ETCD_BASE=$(dirname "${ETCD_DIR}")
+if [ ! -d "${ETCD_BASE}" ]; then
+	mkdir -p "${ETCD_BASE}"
 fi
 
-if [ ! -h ${ETCD_DIR} ]; then
-	ln -s ../../../ ${ETCD_DIR}
+if [ ! -h "${ETCD_DIR}" ]; then
+	ln -s ../../../ "${ETCD_DIR}"
 fi
 
 for i in third_party/*; do
-	if [ $i = "third_party/src" ]; then
+	if [ "$i" = "third_party/src" ]; then
 		continue
 	fi
-	cp -R $i src/
+	cp -R "$i" src/
 done
 
 ./scripts/release-version > release_version.go
-go build ${ETCD_PACKAGE}
+go build "${ETCD_PACKAGE}"

+ 2 - 0
etcd_handlers.go

@@ -49,6 +49,8 @@ func Multiplexer(w http.ResponseWriter, req *http.Request) error {
 		return GetHttpHandler(w, req)
 	case "POST":
 		return SetHttpHandler(w, req)
+	case "PUT":
+		return SetHttpHandler(w, req)
 	case "DELETE":
 		return DeleteHttpHandler(w, req)
 	default:

+ 88 - 80
store/store.go

@@ -326,75 +326,81 @@ func (s *Store) Get(key string) ([]byte, error) {
 	return json.Marshal(resps)
 }
 
-func (s *Store) RawGet(key string) ([]*Response, error) {
-	// Update stats
-	s.BasicStats.Gets++
+func (s *Store) rawGetNode(key string, node *Node) ([]*Response, error) {
+	resps := make([]*Response, 1)
 
-	key = path.Clean("/" + key)
+	isExpire := !node.ExpireTime.Equal(PERMANENT)
 
-	nodes, keys, ok := s.Tree.list(key)
-
-	if ok {
+	resps[0] = &Response{
+		Action: "GET",
+		Index:  s.Index,
+		Key:    key,
+		Value:  node.Value,
+	}
 
-		node, ok := nodes.(*Node)
+	// Update ttl
+	if isExpire {
+		TTL := int64(node.ExpireTime.Sub(time.Now()) / time.Second)
+		resps[0].Expiration = &node.ExpireTime
+		resps[0].TTL = TTL
+	}
 
-		if ok {
-			resps := make([]*Response, 1)
+	return resps, nil
+}
 
-			isExpire := !node.ExpireTime.Equal(PERMANENT)
+func (s *Store) rawGetNodeList(key string, keys []string, nodes []*Node) ([]*Response, error) {
+	resps := make([]*Response, len(nodes))
 
-			resps[0] = &Response{
-				Action: "GET",
-				Index:  s.Index,
-				Key:    key,
-				Value:  node.Value,
-			}
+	// TODO: check if nodes and keys are the same length
+	for i := 0; i < len(nodes); i++ {
+		var TTL int64
+		var isExpire bool = false
 
-			// Update ttl
-			if isExpire {
-				TTL := int64(node.ExpireTime.Sub(time.Now()) / time.Second)
-				resps[0].Expiration = &node.ExpireTime
-				resps[0].TTL = TTL
-			}
+		isExpire = !nodes[i].ExpireTime.Equal(PERMANENT)
 
-			return resps, nil
+		resps[i] = &Response{
+			Action: "GET",
+			Index:  s.Index,
+			Key:    path.Join(key, keys[i]),
 		}
 
-		nodes, _ := nodes.([]*Node)
-
-		resps := make([]*Response, len(nodes))
-		for i := 0; i < len(nodes); i++ {
-
-			var TTL int64
-			var isExpire bool = false
+		if len(nodes[i].Value) != 0 {
+			resps[i].Value = nodes[i].Value
+		} else {
+			resps[i].Dir = true
+		}
 
-			isExpire = !nodes[i].ExpireTime.Equal(PERMANENT)
+		// Update ttl
+		if isExpire {
+			TTL = int64(nodes[i].ExpireTime.Sub(time.Now()) / time.Second)
+			resps[i].Expiration = &nodes[i].ExpireTime
+			resps[i].TTL = TTL
+		}
 
-			resps[i] = &Response{
-				Action: "GET",
-				Index:  s.Index,
-				Key:    path.Join(key, keys[i]),
-			}
+	}
 
-			if len(nodes[i].Value) != 0 {
-				resps[i].Value = nodes[i].Value
-			} else {
-				resps[i].Dir = true
-			}
+	return resps, nil
+}
 
-			// Update ttl
-			if isExpire {
-				TTL = int64(nodes[i].ExpireTime.Sub(time.Now()) / time.Second)
-				resps[i].Expiration = &nodes[i].ExpireTime
-				resps[i].TTL = TTL
-			}
+func (s *Store) RawGet(key string) ([]*Response, error) {
+	// Update stats
+	s.BasicStats.Gets++
 
-		}
+	key = path.Clean("/" + key)
 
-		return resps, nil
+	nodes, keys, ok := s.Tree.list(key)
+	if !ok {
+		return nil, etcdErr.NewError(100, "get: "+key)
 	}
 
-	return nil, etcdErr.NewError(100, "get: "+key)
+	switch node := nodes.(type) {
+	case *Node:
+		return s.rawGetNode(key, node)
+	case []*Node:
+		return s.rawGetNodeList(key, keys, node)
+	default:
+		panic("invalid cast ")
+	}
 }
 
 func (s *Store) Delete(key string, index uint64) ([]byte, error) {
@@ -416,43 +422,41 @@ func (s *Store) internalDelete(key string, index uint64) ([]byte, error) {
 
 	node, ok := s.Tree.get(key)
 
-	if ok {
-
-		resp := Response{
-			Action:    "DELETE",
-			Key:       key,
-			PrevValue: node.Value,
-			Index:     index,
-		}
+	if !ok {
+		return nil, etcdErr.NewError(100, "delete: "+key)
+	}
 
-		if node.ExpireTime.Equal(PERMANENT) {
+	resp := Response{
+		Action:    "DELETE",
+		Key:       key,
+		PrevValue: node.Value,
+		Index:     index,
+	}
 
-			s.Tree.delete(key)
+	if node.ExpireTime.Equal(PERMANENT) {
 
-		} else {
-			resp.Expiration = &node.ExpireTime
-			// Kill the expire go routine
-			node.update <- PERMANENT
-			s.Tree.delete(key)
+		s.Tree.delete(key)
 
-		}
+	} else {
+		resp.Expiration = &node.ExpireTime
+		// Kill the expire go routine
+		node.update <- PERMANENT
+		s.Tree.delete(key)
 
-		msg, err := json.Marshal(resp)
+	}
 
-		s.watcher.notify(resp)
+	msg, err := json.Marshal(resp)
 
-		// notify the messager
-		if s.messager != nil && err == nil {
-			s.messager <- string(msg)
-		}
+	s.watcher.notify(resp)
 
-		s.addToResponseMap(index, &resp)
+	// notify the messager
+	if s.messager != nil && err == nil {
+		s.messager <- string(msg)
+	}
 
-		return msg, err
+	s.addToResponseMap(index, &resp)
 
-	} else {
-		return nil, etcdErr.NewError(100, "delete: "+key)
-	}
+	return msg, err
 }
 
 // Set the value of the key to the value if the given prevValue is equal to the value of the key
@@ -466,12 +470,16 @@ func (s *Store) TestAndSet(key string, prevValue string, value string, expireTim
 	resp := s.internalGet(key)
 
 	if resp == nil {
-		return nil, etcdErr.NewError(100, "testandset: "+key)
+		if prevValue != "" {
+			errmsg := fmt.Sprintf("TestAndSet: key not found and previousValue is not empty %s:%s ", key, prevValue)
+			return nil, etcdErr.NewError(100, errmsg)
+		}
+		return s.internalSet(key, value, expireTime, index)
 	}
 
 	if resp.Value == prevValue {
 
-		// If test success, do set
+		// If test succeed, do set
 		return s.internalSet(key, value, expireTime, index)
 	} else {
 

+ 36 - 0
store/store_test.go

@@ -31,6 +31,42 @@ func TestStoreGetDelete(t *testing.T) {
 	}
 }
 
+func TestTestAndSet(t *testing.T) {
+	s := CreateStore(100)
+	s.Set("foo", "bar", time.Unix(0, 0), 1)
+
+	_, err := s.TestAndSet("foo", "barbar", "barbar", time.Unix(0, 0), 2)
+
+	if err == nil {
+		t.Fatalf("test bar == barbar should fail")
+	}
+
+	_, err = s.TestAndSet("foo", "bar", "barbar", time.Unix(0, 0), 3)
+
+	if err != nil {
+		t.Fatalf("test bar == bar should succeed")
+	}
+
+	_, err = s.TestAndSet("foo", "", "barbar", time.Unix(0, 0), 4)
+
+	if err == nil {
+		t.Fatalf("test empty == bar should fail")
+	}
+
+	_, err = s.TestAndSet("fooo", "bar", "barbar", time.Unix(0, 0), 5)
+
+	if err == nil {
+		t.Fatalf("test bar == non-existing key should fail")
+	}
+
+	_, err = s.TestAndSet("fooo", "", "bar", time.Unix(0, 0), 6)
+
+	if err != nil {
+		t.Fatalf("test empty == non-existing key should succeed")
+	}
+
+}
+
 func TestSaveAndRecovery(t *testing.T) {
 
 	s := CreateStore(100)