/
util.go
65 lines (63 loc) · 1.52 KB
/
util.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
package waffle
import (
"github.com/dforsyth/donut"
"launchpad.net/gozk/zookeeper"
"log"
)
// XXX pulled this out of donut, maybe i should make a zk util lib?
// Watch the children at path until a byte is sent on the returned channel
// Uses the SafeMap more like a set, so you'll have to use Contains() for entries
func watchZKChildren(zk *zookeeper.Conn, path string, children *donut.SafeMap, onChange func(*donut.SafeMap)) (chan byte, error) {
initial, _, watch, err := zk.ChildrenW(path)
if err != nil {
return nil, err
}
m := children.RangeLock()
for _, node := range initial {
m[node] = nil
}
children.RangeUnlock()
kill := make(chan byte, 1)
log.Printf("watching "+path+" len is %d", children.Len())
go func() {
defer close(kill)
var nodes []string
var err error
for {
select {
case <-kill:
// close(watch)
log.Printf("got kill")
return
case event := <-watch:
if !event.Ok() {
continue
}
// close(watch)
nodes, _, watch, err = zk.ChildrenW(path)
if err != nil {
log.Printf("Error in watchZkChildren: %v", err)
// XXX I should really provide some way for the client to find out about this error...
return
}
m := children.RangeLock()
// mark all dead
for k := range m {
m[k] = 0
}
for _, node := range nodes {
m[node] = 1
}
for k, v := range m {
if v.(int) == 0 {
delete(m, k)
}
}
children.RangeUnlock()
onChange(children)
}
}
}()
log.Printf("watcher setup on %s", path)
return kill, nil
}