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/README.md b/vendor/github.com/EagleChen/mapmutex/README.md
new file mode 100644
index 0000000..9ee890d
--- /dev/null
+++ b/vendor/github.com/EagleChen/mapmutex/README.md
@@ -0,0 +1,73 @@
+# mapmutex
+
+mapmutex is a simple implementation to act as a group of mutex.
+
+## What's it for?
+Synchronization is needed in many cases. But in some cases, you don't want a gaint lock to block totally irrelevant actions. Instead, you need many fine-grained tiny locks to only block on same resource.
+
+Take an example. A website have many users. Each user has a different counter. While one user want to increment the counter at the same time in different devices(say, from a pad and a phone), these increments need to happen one by one. But user A's incremntation has nothing to do with user B's incrementation, they don't have to affect each other.
+This is where this package comes in. You can lock for each user (by using user id as key) without blocking other users.
+
+## Performance
+As shown by the result of benchmark(in `mutex_test.go`), it's several times faster than one giant mutex.
+```
+(11 times faster)
+BenchmarkMutex1000_100_20_20-4          	       1	20164937908 ns/op
+BenchmarkMapMutex1000_100_20_20-4       	       1	1821899222 ns/op 
+
+(7 times faster)
+BenchmarkMutex1000_20_20_20-4           	       1	19726327623 ns/op
+BenchmarkMapMutex1000_20_20_20-4        	       1	2759654813 ns/op
+
+(11 times faster)
+BenchmarkMutex1000_20_40_20-4           	       1	20380128848 ns/op
+BenchmarkMapMutex1000_20_40_20-4        	       1	1828899343 ns/op
+
+(only 2 keys in map, 2 times faster)
+(in case of only one key in map, it's the same as one gaint lock)
+BenchmarkMutex1000_2_40_20-4            	       1	20721092007 ns/op
+BenchmarkMapMutex1000_2_40_20-4         	       1	10818512020 ns/op (989 of 1000 success)
+
+(9 times faster)
+BenchmarkMutex1000_20_40_60-4           	       1	60341833247 ns/op
+BenchmarkMapMutex1000_20_40_60-4        	       1	6240238975 ns/op
+
+(11 times faster)
+BenchmarkMutex10000_20_40_20-4          	       1	205493472245 ns/op
+BenchmarkMapMutex10000_20_40_20-4       	       1	18677416055 ns/op
+```
+
+## How to get
+```
+go get github.com/EagleChen/mapmutex
+```
+
+## How to use
+```
+mutex := mapmutex.NewMapMutex()
+if mutex.TryLock(key) { // for example, key can be user id
+    // do the real job here
+
+    mutex.Unlock(key)
+}
+```
+
+TryLock itself will retry several times to aquire the lock. But in the application level, you can also try several times when the lock cannot be got.
+```
+got := false
+for i := 0; && i < retryTimes; i++ {
+    if got = mutex.TryLock(key); got {
+        break
+    }
+}
+if got {
+    // do the real job here
+
+    mutex.Unlock(key)
+}
+```
+
+## How to tune
+1. Use `NewCustomizedMapMutex` to customize how hard 'TryLock' will try to get the lock. The parameters controls how many times to try, how long to wait before another try when failing to aquire the lock, etc. They may be very different for various use cases.
+
+2. Change some source code for your use case. For general use, `map[interface{}]interface{}` is used for storing 'locks'. But it can be changed to `map[int]bool` if your `key` is `int` and `map[string]bool` if you `key` is `string`. As far as i know, this trick will improve the performance, a little bit.
\ No newline at end of file
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,
+	}
+}
diff --git a/vendor/modules.txt b/vendor/modules.txt
index ea3c340..8fe9dde 100644
--- a/vendor/modules.txt
+++ b/vendor/modules.txt
@@ -1,5 +1,7 @@
 # github.com/DataDog/zstd v1.4.1
 github.com/DataDog/zstd
+# github.com/EagleChen/mapmutex v0.0.0-20180418073615-e1a5ae258d8d
+github.com/EagleChen/mapmutex
 # github.com/Shopify/sarama v1.23.1
 github.com/Shopify/sarama
 # github.com/armon/go-metrics v0.0.0-20190430140413-ec5e00d3c878