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  }