-
Notifications
You must be signed in to change notification settings - Fork 0
/
process_registry.go
executable file
·102 lines (87 loc) · 2.13 KB
/
process_registry.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
package actor
import (
"sync/atomic"
cmap "github.com/orcaman/concurrent-map"
)
type ProcessRegistryValue struct {
SequenceID uint64
Address string
LocalPIDs cmap.ConcurrentMap
RemoteHandlers []AddressResolver
}
var (
localAddress = "nonhost"
)
// ProcessRegistry is a registry of all active processes.
//
// NOTE: This should only be used for advanced scenarios
var ProcessRegistry = &ProcessRegistryValue{
Address: localAddress,
LocalPIDs: cmap.New(),
}
// An AddressResolver is used to resolve remote actors
type AddressResolver func(*PID) (Process, bool)
func (pr *ProcessRegistryValue) RegisterAddressResolver(handler AddressResolver) {
pr.RemoteHandlers = append(pr.RemoteHandlers, handler)
}
const (
digits = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ~+"
)
func uint64ToId(u uint64) string {
var buf [13]byte
i := 13
// base is power of 2: use shifts and masks instead of / and %
for u >= 64 {
i--
buf[i] = digits[uintptr(u)&0x3f]
u >>= 6
}
// u < base
i--
buf[i] = digits[uintptr(u)]
i--
buf[i] = '$'
return string(buf[i:])
}
func (pr *ProcessRegistryValue) NextId() string {
counter := atomic.AddUint64(&pr.SequenceID, 1)
return uint64ToId(counter)
}
func (pr *ProcessRegistryValue) Add(process Process, id string) (*PID, bool) {
return &PID{
Address: pr.Address,
Id: id,
}, pr.LocalPIDs.SetIfAbsent(id, process)
}
func (pr *ProcessRegistryValue) Remove(pid *PID) {
ref, _ := pr.LocalPIDs.Pop(pid.Id)
if l, ok := ref.(*localProcess); ok {
atomic.StoreInt32(&l.dead, 1)
}
}
func (pr *ProcessRegistryValue) Get(pid *PID) (Process, bool) {
if pid == nil {
return deadLetter, false
}
if pid.Address != localAddress && pid.Address != pr.Address {
for _, handler := range pr.RemoteHandlers {
ref, ok := handler(pid)
if ok {
return ref, true
}
}
return deadLetter, false
}
ref, ok := pr.LocalPIDs.Get(pid.Id)
if !ok {
return deadLetter, false
}
return ref.(Process), true
}
func (pr *ProcessRegistryValue) GetLocal(id string) (Process, bool) {
ref, ok := pr.LocalPIDs.Get(id)
if !ok {
return deadLetter, false
}
return ref.(Process), true
}