github.com/xmidt-org/webpa-common@v1.11.9/concurrent/keyValue.go (about) 1 package concurrent 2 3 import ( 4 "sync" 5 ) 6 7 // KeyValueStorage is the map type used by KeyValue. It is the type that is 8 // directly modifiable by operations. 9 type KeyValueStorage map[interface{}]interface{} 10 11 // KeyValueOperation represents an atomic operation that is allowed to mutate the 12 // storage of a KeyValue. Operations are always executed within a critical 13 // section bounded by a write lock. 14 type KeyValueOperation interface { 15 Execute(KeyValueStorage) 16 } 17 18 // KeyValueOperationFunc is a function type that implements KeyValueOperation. 19 type KeyValueOperationFunc func(KeyValueStorage) 20 21 func (f KeyValueOperationFunc) Execute(storage KeyValueStorage) { 22 f(storage) 23 } 24 25 // KeyValueTransformer is a binary operation that produces a result from a key/value pair. 26 // Transformers cannot mutate the storage of a KeyValue. Transformers are always 27 // executed within the context of a read lock. Multiple transformers can execute 28 // simultaneously. 29 type KeyValueTransformer interface { 30 Execute(key, value interface{}) interface{} 31 } 32 33 // KeyValueTransformerFunc is a function type that implements KeyValueTransformer. 34 type KeyValueTransformerFunc func(key, value interface{}) interface{} 35 36 func (f KeyValueTransformerFunc) Execute(key, value interface{}) interface{} { 37 return f(key, value) 38 } 39 40 // KeyValue is a concurrent mapping of arbitrary types with a completely asynchronous API. 41 // Instances of this type must be created via NewKeyValue. 42 type KeyValue struct { 43 storage KeyValueStorage 44 lock sync.RWMutex 45 } 46 47 // NewKeyValue initializes and returns a distinct KeyValue instance. 48 func NewKeyValue() *KeyValue { 49 return &KeyValue{ 50 storage: make(KeyValueStorage), 51 } 52 } 53 54 // Apply uses the given transformer to produce a result for each key/value pair in the storage. 55 // A channel of channels is returned: The channel has a buffer size of 1 and will receive another 56 // channel containing the results of applying the transformer. 57 func (kv *KeyValue) Apply(transformer KeyValueTransformer) <-chan chan interface{} { 58 output := make(chan chan interface{}, 1) 59 go func() { 60 kv.lock.RLock() 61 defer kv.lock.RUnlock() 62 defer close(output) 63 64 results := make(chan interface{}, len(kv.storage)) 65 defer close(results) 66 output <- results 67 68 for key, value := range kv.storage { 69 results <- transformer.Execute(key, value) 70 } 71 }() 72 73 return output 74 } 75 76 // Keys is a special usage of Apply: It returns a channel which in turn receives a channel 77 // containing the keys in the internal storage. 78 func (kv *KeyValue) Keys() <-chan chan interface{} { 79 return kv.Apply( 80 KeyValueTransformerFunc( 81 func(key, value interface{}) interface{} { return key }, 82 ), 83 ) 84 } 85 86 // Values is a special usage of Apply: It returns a channel which in turn receives a channel 87 // containing the values in the internal storage. 88 func (kv *KeyValue) Values() <-chan chan interface{} { 89 return kv.Apply( 90 KeyValueTransformerFunc( 91 func(key, value interface{}) interface{} { return value }, 92 ), 93 ) 94 } 95 96 // Do asynchronously executes a bulk operation against the internal storage. 97 // This method contends on the internal write lock. 98 func (kv *KeyValue) Do(operation KeyValueOperation) { 99 go func() { 100 kv.lock.Lock() 101 defer kv.lock.Unlock() 102 operation.Execute(kv.storage) 103 }() 104 } 105 106 // Get asynchronously obtains the value associated with the given key. The returned 107 // channel always receives exactly one (1) value. It will receive nil if the given 108 // key was not present in the storage. 109 func (kv *KeyValue) Get(key interface{}) <-chan interface{} { 110 output := make(chan interface{}, 1) 111 go func() { 112 kv.lock.RLock() 113 defer kv.lock.RUnlock() 114 defer close(output) 115 output <- kv.storage[key] 116 }() 117 118 return output 119 } 120 121 // Add asynchronously adds (or, replaces) a key/value pair. 122 func (kv *KeyValue) Add(key, value interface{}) { 123 go func() { 124 kv.lock.Lock() 125 defer kv.lock.Unlock() 126 kv.storage[key] = value 127 }() 128 } 129 130 // Delete asynchronously removes zero or more keys from the internal storage. 131 func (kv *KeyValue) Delete(keys ...interface{}) { 132 if len(keys) > 0 { 133 go func() { 134 kv.lock.Lock() 135 defer kv.lock.Unlock() 136 for _, key := range keys { 137 delete(kv.storage, key) 138 } 139 }() 140 } 141 }