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,
+	}
+}