소스 검색

Release memoryStore locks before filter/apply

Rework memoryStore so that filters and apply run
on a cloned list of containers after the lock has
been released. This avoids possible deadlocks when
these filter/apply callbacks take locks for a
container.

Fixes #22732

Signed-off-by: Tonis Tiigi <tonistiigi@gmail.com>
Tonis Tiigi 9 년 전
부모
커밋
bd2b3d363f
2개의 변경된 파일14개의 추가작업 그리고 19개의 파일을 삭제
  1. 0 5
      container/history.go
  2. 14 14
      container/memory_store.go

+ 0 - 5
container/history.go

@@ -24,11 +24,6 @@ func (history *History) Swap(i, j int) {
 	containers[i], containers[j] = containers[j], containers[i]
 	containers[i], containers[j] = containers[j], containers[i]
 }
 }
 
 
-// Add the given container to history.
-func (history *History) Add(container *Container) {
-	*history = append(*history, container)
-}
-
 // sort orders the history by creation date in descendant order.
 // sort orders the history by creation date in descendant order.
 func (history *History) sort() {
 func (history *History) sort() {
 	sort.Sort(history)
 	sort.Sort(history)

+ 14 - 14
container/memory_store.go

@@ -41,14 +41,9 @@ func (c *memoryStore) Delete(id string) {
 // List returns a sorted list of containers from the store.
 // List returns a sorted list of containers from the store.
 // The containers are ordered by creation date.
 // The containers are ordered by creation date.
 func (c *memoryStore) List() []*Container {
 func (c *memoryStore) List() []*Container {
-	containers := new(History)
-	c.RLock()
-	for _, cont := range c.s {
-		containers.Add(cont)
-	}
-	c.RUnlock()
+	containers := History(c.all())
 	containers.sort()
 	containers.sort()
-	return *containers
+	return containers
 }
 }
 
 
 // Size returns the number of containers in the store.
 // Size returns the number of containers in the store.
@@ -60,9 +55,7 @@ func (c *memoryStore) Size() int {
 
 
 // First returns the first container found in the store by a given filter.
 // First returns the first container found in the store by a given filter.
 func (c *memoryStore) First(filter StoreFilter) *Container {
 func (c *memoryStore) First(filter StoreFilter) *Container {
-	c.RLock()
-	defer c.RUnlock()
-	for _, cont := range c.s {
+	for _, cont := range c.all() {
 		if filter(cont) {
 		if filter(cont) {
 			return cont
 			return cont
 		}
 		}
@@ -74,11 +67,8 @@ func (c *memoryStore) First(filter StoreFilter) *Container {
 // This operation is asyncronous in the memory store.
 // This operation is asyncronous in the memory store.
 // NOTE: Modifications to the store MUST NOT be done by the StoreReducer.
 // NOTE: Modifications to the store MUST NOT be done by the StoreReducer.
 func (c *memoryStore) ApplyAll(apply StoreReducer) {
 func (c *memoryStore) ApplyAll(apply StoreReducer) {
-	c.RLock()
-	defer c.RUnlock()
-
 	wg := new(sync.WaitGroup)
 	wg := new(sync.WaitGroup)
-	for _, cont := range c.s {
+	for _, cont := range c.all() {
 		wg.Add(1)
 		wg.Add(1)
 		go func(container *Container) {
 		go func(container *Container) {
 			apply(container)
 			apply(container)
@@ -89,4 +79,14 @@ func (c *memoryStore) ApplyAll(apply StoreReducer) {
 	wg.Wait()
 	wg.Wait()
 }
 }
 
 
+func (c *memoryStore) all() []*Container {
+	c.RLock()
+	containers := make([]*Container, 0, len(c.s))
+	for _, cont := range c.s {
+		containers = append(containers, cont)
+	}
+	c.RUnlock()
+	return containers
+}
+
 var _ Store = &memoryStore{}
 var _ Store = &memoryStore{}