forked from vitessio/vitess
/
file.go
104 lines (91 loc) · 2.77 KB
/
file.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
package etcdtopo
import (
"fmt"
"path"
"golang.org/x/net/context"
"github.com/coreos/go-etcd/etcd"
"github.com/youtube/vitess/go/vt/topo"
)
// Create is part of the topo.Backend interface.
func (s *Server) Create(ctx context.Context, cell, filePath string, contents []byte) (topo.Version, error) {
c, err := s.clientForCell(cell)
if err != nil {
return nil, err
}
resp, err := c.Create(filePath, string(contents), 0 /* ttl */)
if err != nil {
return nil, convertError(err)
}
return EtcdVersion(resp.Node.ModifiedIndex), nil
}
// Update is part of the topo.Backend interface.
func (s *Server) Update(ctx context.Context, cell, filePath string, contents []byte, version topo.Version) (topo.Version, error) {
c, err := s.clientForCell(cell)
if err != nil {
return nil, err
}
var resp *etcd.Response
if version == nil {
resp, err = c.Set(filePath, string(contents), 0 /* ttl */)
} else {
resp, err = c.CompareAndSwap(filePath, string(contents), 0 /* ttl */, "" /* prevValue */, uint64(version.(EtcdVersion)))
}
if err != nil {
return nil, convertError(err)
}
return EtcdVersion(resp.Node.ModifiedIndex), nil
}
// Get is part of the topo.Backend interface.
func (s *Server) Get(ctx context.Context, cell, filePath string) ([]byte, topo.Version, error) {
c, err := s.clientForCell(cell)
if err != nil {
return nil, nil, err
}
resp, err := c.Get(filePath, false /* sort */, false /* recursive */)
if err != nil {
return nil, nil, convertError(err)
}
if resp.Node == nil {
return nil, nil, fmt.Errorf("got bad empty node for %v", filePath)
}
return []byte(resp.Node.Value), EtcdVersion(resp.Node.ModifiedIndex), nil
}
// Delete is part of the topo.Backend interface.
func (s *Server) Delete(ctx context.Context, cell, filePath string, version topo.Version) error {
c, err := s.clientForCell(cell)
if err != nil {
return err
}
if version == nil {
_, err = c.Delete(filePath, false /* recursive */)
} else {
_, err = c.CompareAndDelete(filePath, "" /* prevValue */, uint64(version.(EtcdVersion)))
}
if err != nil {
return convertError(err)
}
// Now recursively delete the parent dirs if empty
return s.recursiveDeleteParentIfEmpty(ctx, c, filePath)
}
func (s *Server) recursiveDeleteParentIfEmpty(ctx context.Context, c Client, filePath string) error {
dir := path.Dir(filePath)
if dir == "" || dir == "/" || dir == "." {
// we reached the top
return nil
}
_, err := c.DeleteDir(dir)
if err == nil {
// this worked, keep going up
return s.recursiveDeleteParentIfEmpty(ctx, c, dir)
}
etcdErr, ok := err.(*etcd.EtcdError)
if !ok {
return err
}
if etcdErr.ErrorCode == EcodeDirNotEmpty || etcdErr.ErrorCode == EcodeKeyNotFound {
// We found a non-empty dir, or someone else already
// removed the directory, done.
return nil
}
return etcdErr
}