avoid deadlock in syncMap.Iterate (#909)
Previously, when syncMap iterates a list of records which have the same content in different order, a deadlock might happen. By enforcing a certain order, the deadlock can be avoided.
This commit is contained in:
		| @@ -5,6 +5,7 @@ import ( | ||||
| 	"encoding/base64" | ||||
| 	"encoding/json" | ||||
| 	"fmt" | ||||
| 	"sort" | ||||
|  | ||||
| 	"github.com/micro/go-micro/store" | ||||
| 	ckv "github.com/micro/go-micro/store/etcd" | ||||
| @@ -94,6 +95,10 @@ func (m *syncMap) Iterate(fn func(key, val interface{}) error) error { | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	sort.Slice(keyvals, func(i, j int) bool { | ||||
| 		return keyvals[i].Key < keyvals[j].Key | ||||
| 	}) | ||||
|  | ||||
| 	for _, keyval := range keyvals { | ||||
| 		// lock | ||||
| 		if err := m.opts.Lock.Acquire(keyval.Key); err != nil { | ||||
|   | ||||
							
								
								
									
										39
									
								
								sync/map_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										39
									
								
								sync/map_test.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,39 @@ | ||||
| package sync | ||||
|  | ||||
| import ( | ||||
| 	"testing" | ||||
| 	"time" | ||||
|  | ||||
| 	store "github.com/micro/go-micro/store" | ||||
| 	mem_store "github.com/micro/go-micro/store/memory" | ||||
| 	mem_lock "github.com/micro/go-micro/sync/lock/memory" | ||||
| ) | ||||
|  | ||||
| func TestIterate(t *testing.T) { | ||||
| 	s1 := mem_store.NewStore() | ||||
| 	s2 := mem_store.NewStore() | ||||
| 	recA := &store.Record{ | ||||
| 		Key:   "A", | ||||
| 		Value: nil, | ||||
| 	} | ||||
| 	recB := &store.Record{ | ||||
| 		Key:   "B", | ||||
| 		Value: nil, | ||||
| 	} | ||||
| 	s1.Write(recA) | ||||
| 	s1.Write(recB) | ||||
| 	s2.Write(recB) | ||||
| 	s2.Write(recA) | ||||
|  | ||||
| 	f := func(key, val interface{}) error { | ||||
| 		time.Sleep(1 * time.Millisecond) | ||||
| 		return nil | ||||
| 	} | ||||
| 	l := mem_lock.NewLock() | ||||
| 	m1 := NewMap(WithStore(s1), WithLock(l)) | ||||
| 	m2 := NewMap(WithStore(s2), WithLock(l)) | ||||
| 	go func() { | ||||
| 		m2.Iterate(f) | ||||
| 	}() | ||||
| 	m1.Iterate(f) | ||||
| } | ||||
		Reference in New Issue
	
	Block a user