Browse Source

Merge pull request #9626 from yudai/fix_set_inexist_dir

etcdserver: Fix v2v3api set to create parent directly if not exists
Gyuho Lee 7 years ago
parent
commit
dca3f5e3ad
2 changed files with 29 additions and 6 deletions
  1. 14 4
      etcdserver/api/v2v3/store.go
  2. 15 2
      etcdserver/v2store/store_test.go

+ 14 - 4
etcdserver/api/v2v3/store.go

@@ -143,10 +143,20 @@ func (s *v2v3Store) Set(
 
 	ecode := 0
 	applyf := func(stm concurrency.STM) error {
-		parent := path.Dir(nodePath)
-		if !isRoot(parent) && stm.Rev(s.mkPath(parent)+"/") == 0 {
-			ecode = v2error.EcodeKeyNotFound
-			return nil
+		// build path if any directories in path do not exist
+		dirs := []string{}
+		for p := path.Dir(nodePath); !isRoot(p); p = path.Dir(p) {
+			pp := s.mkPath(p)
+			if stm.Rev(pp) > 0 {
+				ecode = v2error.EcodeNotDir
+				return nil
+			}
+			if stm.Rev(pp+"/") == 0 {
+				dirs = append(dirs, pp+"/")
+			}
+		}
+		for _, d := range dirs {
+			stm.Put(d, "")
 		}
 
 		key := s.mkPath(nodePath)

+ 15 - 2
etcdserver/v2store/store_test.go

@@ -145,8 +145,21 @@ func TestSet(t *testing.T) {
 	testutil.AssertEqual(t, *e.PrevNode.Value, "bar")
 	testutil.AssertEqual(t, e.PrevNode.ModifiedIndex, uint64(2))
 
-	// Set /dir as a directory
+	// Set /a/b/c/d="efg"
 	eidx = 4
+	e, err = s.Set("/a/b/c/d", false, "efg", v2store.TTLOptionSet{ExpireTime: v2store.Permanent})
+	testutil.AssertNil(t, err)
+	testutil.AssertEqual(t, e.EtcdIndex, eidx)
+	testutil.AssertEqual(t, e.Node.Key, "/a/b/c/d")
+	testutil.AssertFalse(t, e.Node.Dir)
+	testutil.AssertEqual(t, *e.Node.Value, "efg")
+	testutil.AssertNil(t, e.Node.Nodes)
+	testutil.AssertNil(t, e.Node.Expiration)
+	testutil.AssertEqual(t, e.Node.TTL, int64(0))
+	testutil.AssertEqual(t, e.Node.ModifiedIndex, uint64(4))
+
+	// Set /dir as a directory
+	eidx = 5
 	e, err = s.Set("/dir", true, "", v2store.TTLOptionSet{ExpireTime: v2store.Permanent})
 	testutil.AssertNil(t, err)
 	testutil.AssertEqual(t, e.EtcdIndex, eidx)
@@ -157,7 +170,7 @@ func TestSet(t *testing.T) {
 	testutil.AssertNil(t, e.Node.Nodes)
 	testutil.AssertNil(t, e.Node.Expiration)
 	testutil.AssertEqual(t, e.Node.TTL, int64(0))
-	testutil.AssertEqual(t, e.Node.ModifiedIndex, uint64(4))
+	testutil.AssertEqual(t, e.Node.ModifiedIndex, uint64(5))
 }
 
 // Ensure that the store can create a new key if it doesn't already exist.