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>
| ... | ... |
@@ -24,11 +24,6 @@ func (history *History) Swap(i, j int) {
|
| 24 | 24 |
containers[i], containers[j] = containers[j], containers[i] |
| 25 | 25 |
} |
| 26 | 26 |
|
| 27 |
-// Add the given container to history. |
|
| 28 |
-func (history *History) Add(container *Container) {
|
|
| 29 |
- *history = append(*history, container) |
|
| 30 |
-} |
|
| 31 |
- |
|
| 32 | 27 |
// sort orders the history by creation date in descendant order. |
| 33 | 28 |
func (history *History) sort() {
|
| 34 | 29 |
sort.Sort(history) |
| ... | ... |
@@ -41,14 +41,9 @@ func (c *memoryStore) Delete(id string) {
|
| 41 | 41 |
// List returns a sorted list of containers from the store. |
| 42 | 42 |
// The containers are ordered by creation date. |
| 43 | 43 |
func (c *memoryStore) List() []*Container {
|
| 44 |
- containers := new(History) |
|
| 45 |
- c.RLock() |
|
| 46 |
- for _, cont := range c.s {
|
|
| 47 |
- containers.Add(cont) |
|
| 48 |
- } |
|
| 49 |
- c.RUnlock() |
|
| 44 |
+ containers := History(c.all()) |
|
| 50 | 45 |
containers.sort() |
| 51 |
- return *containers |
|
| 46 |
+ return containers |
|
| 52 | 47 |
} |
| 53 | 48 |
|
| 54 | 49 |
// Size returns the number of containers in the store. |
| ... | ... |
@@ -60,9 +55,7 @@ func (c *memoryStore) Size() int {
|
| 60 | 60 |
|
| 61 | 61 |
// First returns the first container found in the store by a given filter. |
| 62 | 62 |
func (c *memoryStore) First(filter StoreFilter) *Container {
|
| 63 |
- c.RLock() |
|
| 64 |
- defer c.RUnlock() |
|
| 65 |
- for _, cont := range c.s {
|
|
| 63 |
+ for _, cont := range c.all() {
|
|
| 66 | 64 |
if filter(cont) {
|
| 67 | 65 |
return cont |
| 68 | 66 |
} |
| ... | ... |
@@ -74,11 +67,8 @@ func (c *memoryStore) First(filter StoreFilter) *Container {
|
| 74 | 74 |
// This operation is asyncronous in the memory store. |
| 75 | 75 |
// NOTE: Modifications to the store MUST NOT be done by the StoreReducer. |
| 76 | 76 |
func (c *memoryStore) ApplyAll(apply StoreReducer) {
|
| 77 |
- c.RLock() |
|
| 78 |
- defer c.RUnlock() |
|
| 79 |
- |
|
| 80 | 77 |
wg := new(sync.WaitGroup) |
| 81 |
- for _, cont := range c.s {
|
|
| 78 |
+ for _, cont := range c.all() {
|
|
| 82 | 79 |
wg.Add(1) |
| 83 | 80 |
go func(container *Container) {
|
| 84 | 81 |
apply(container) |
| ... | ... |
@@ -89,4 +79,14 @@ func (c *memoryStore) ApplyAll(apply StoreReducer) {
|
| 89 | 89 |
wg.Wait() |
| 90 | 90 |
} |
| 91 | 91 |
|
| 92 |
+func (c *memoryStore) all() []*Container {
|
|
| 93 |
+ c.RLock() |
|
| 94 |
+ containers := make([]*Container, 0, len(c.s)) |
|
| 95 |
+ for _, cont := range c.s {
|
|
| 96 |
+ containers = append(containers, cont) |
|
| 97 |
+ } |
|
| 98 |
+ c.RUnlock() |
|
| 99 |
+ return containers |
|
| 100 |
+} |
|
| 101 |
+ |
|
| 92 | 102 |
var _ Store = &memoryStore{}
|