VOL-2339: DHCP issue on second ONU, when two ONUs exist on same PON
- Process to_remove before to_add items in UpdateFlowsIncrementally
method
- Sequentially add flows for a given pon, onu, uni inorder to avoid
PON resource collisions. Used lock per key so that different
subscribers do not have to wait for each other to add flows.
- Wait for any flow removes for the subscriber to complete before
adding flows.
Change-Id: I095291b9a53fd0f19dc79f2b44923ec786a26d6e
diff --git a/vendor/github.com/EagleChen/mapmutex/mutex.go b/vendor/github.com/EagleChen/mapmutex/mutex.go
new file mode 100644
index 0000000..2555e55
--- /dev/null
+++ b/vendor/github.com/EagleChen/mapmutex/mutex.go
@@ -0,0 +1,90 @@
+package mapmutex
+
+import (
+ "math/rand"
+ "sync"
+ "time"
+)
+
+// Mutex is the mutex with synchronized map
+// it's for reducing unnecessary locks among different keys
+type Mutex struct {
+ locks map[interface{}]interface{}
+ m *sync.Mutex
+ maxRetry int
+ maxDelay float64 // in nanosend
+ baseDelay float64 // in nanosecond
+ factor float64
+ jitter float64
+}
+
+// TryLock tries to aquire the lock.
+func (m *Mutex) TryLock(key interface{}) (gotLock bool) {
+ for i := 0; i < m.maxRetry; i++ {
+ m.m.Lock()
+ if _, ok := m.locks[key]; ok { // if locked
+ m.m.Unlock()
+ time.Sleep(m.backoff(i))
+ } else { // if unlock, lockit
+ m.locks[key] = struct{}{}
+ m.m.Unlock()
+ return true
+ }
+ }
+
+ return false
+}
+
+// Unlock unlocks for the key
+// please call Unlock only after having aquired the lock
+func (m *Mutex) Unlock(key interface{}) {
+ m.m.Lock()
+ delete(m.locks, key)
+ m.m.Unlock()
+}
+
+// borrowed from grpc
+func (m *Mutex) backoff(retries int) time.Duration {
+ if retries == 0 {
+ return time.Duration(m.baseDelay) * time.Nanosecond
+ }
+ backoff, max := m.baseDelay, m.maxDelay
+ for backoff < max && retries > 0 {
+ backoff *= m.factor
+ retries--
+ }
+ if backoff > max {
+ backoff = max
+ }
+ backoff *= 1 + m.jitter*(rand.Float64()*2-1)
+ if backoff < 0 {
+ return 0
+ }
+ return time.Duration(backoff) * time.Nanosecond
+}
+
+// NewMapMutex returns a mapmutex with default configs
+func NewMapMutex() *Mutex {
+ return &Mutex{
+ locks: make(map[interface{}]interface{}),
+ m: &sync.Mutex{},
+ maxRetry: 200,
+ maxDelay: 100000000, // 0.1 second
+ baseDelay: 10, // 10 nanosecond
+ factor: 1.1,
+ jitter: 0.2,
+ }
+}
+
+// NewCustomizedMapMutex returns a customized mapmutex
+func NewCustomizedMapMutex(mRetry int, mDelay, bDelay, factor, jitter float64) *Mutex {
+ return &Mutex{
+ locks: make(map[interface{}]interface{}),
+ m: &sync.Mutex{},
+ maxRetry: mRetry,
+ maxDelay: mDelay,
+ baseDelay: bDelay,
+ factor: factor,
+ jitter: jitter,
+ }
+}