-
Notifications
You must be signed in to change notification settings - Fork 1
/
provider_global.go
141 lines (117 loc) · 3.54 KB
/
provider_global.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
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
package log
import (
"fmt"
"reflect"
"strings"
"sync"
"sync/atomic"
"unsafe"
)
var (
providerPointer unsafe.Pointer
providerV = NewProviderFacade(getProvider)
knownProviders = map[string]Provider{}
knownProvidersMutex sync.RWMutex
)
// GetProvider returns the actual Provider.
//
// The Provider returned by this method is guarded by a facade
// (see NewProviderFacade()) which ensures that usages of this Provider will
// always call the global configured Provider depending on whether the Provider
// was configured before calling this method or afterwards.
func GetProvider() Provider {
return providerV
}
func getProvider() Provider {
for {
v := (*Provider)(atomic.LoadPointer(&providerPointer))
if v != nil && *v != nil {
return *v
}
p := exactOneProvider()
if atomic.CompareAndSwapPointer(&providerPointer, unsafe.Pointer(v), unsafe.Pointer(&p)) {
return p
}
}
}
func exactOneProvider() Provider {
knownProvidersMutex.RLock()
defer knownProvidersMutex.RUnlock()
if len(knownProviders) > 1 {
asStrings := make([]string, len(knownProviders))
var i int
for n, p := range knownProviders {
asStrings[i] = fmt.Sprintf("%d# %v(%s)", i+1, reflect.TypeOf(p), n)
i++
}
panic("There are more than provider registered; Got:\n\t" + strings.Join(asStrings, "\n\t"))
}
for _, p := range knownProviders {
return p
}
// Everything failed, using the fallbackProvider now...
return fallbackProviderV
}
// SetProvider forces the given Provider as the actual one which will be
// returned when calling GetProvider(). This will lead to that each Provider
// registered with RegisterProvider() will be ignored.
//
// This methods accepts also <nil>. In this case regular discovery mechanism
// will be enabled again when calling GetProvider().
//
// This methods always returns the previous set value (which can be <nil>, too).
func SetProvider(p Provider) Provider {
for {
oldP := (*Provider)(atomic.LoadPointer(&providerPointer))
if atomic.CompareAndSwapPointer(&providerPointer, unsafe.Pointer(oldP), unsafe.Pointer(&p)) {
if oldP != nil {
return *oldP
}
return nil
}
}
}
// RegisterProvider registers the given provider as a usable one. If
// GetProvider() is called each Provider which was registered with this method
// will be then taken into consideration to be returned.
//
// It is not possible to register more than one instance of a Provider with the
// same name.
func RegisterProvider(p Provider) Provider {
if p == nil {
panic("Provided Provider is nil")
}
knownProvidersMutex.Lock()
defer SetProvider(nil)
defer knownProvidersMutex.Unlock()
if existing := knownProviders[p.GetName()]; existing == p {
return p
} else if existing != nil {
panic(fmt.Sprintf("Multiple try of registering of Provider with the same name: %s\n"+
"\tAlready existing type: %v; new type: %v", p.GetName(), reflect.TypeOf(existing), reflect.TypeOf(p)))
}
knownProviders[p.GetName()] = p
return p
}
// UnregisterProvider is doing the exact opposite of RegisterProvider().
func UnregisterProvider(name string) Provider {
knownProvidersMutex.Lock()
defer SetProvider(nil)
defer knownProvidersMutex.Unlock()
existing := knownProviders[name]
delete(knownProviders, name)
return existing
}
// GetAllProviders returns all knows providers registered with
// RegisterProvider().
func GetAllProviders() []Provider {
knownProvidersMutex.RLock()
defer knownProvidersMutex.RUnlock()
result := make([]Provider, len(knownProviders))
var i int
for _, p := range knownProviders {
result[i] = p
i++
}
return result
}