gitee.com/liuxuezhan/go-micro-v1.18.0@v1.0.0/sync/map.go (about)

     1  package sync
     2  
     3  import (
     4  	"bytes"
     5  	"encoding/base64"
     6  	"encoding/json"
     7  	"fmt"
     8  	"sort"
     9  
    10  	"gitee.com/liuxuezhan/go-micro-v1.18.0/store"
    11  	ckv "gitee.com/liuxuezhan/go-micro-v1.18.0/store/etcd"
    12  	lock "gitee.com/liuxuezhan/go-micro-v1.18.0/sync/lock/etcd"
    13  )
    14  
    15  type syncMap struct {
    16  	opts Options
    17  }
    18  
    19  func ekey(k interface{}) string {
    20  	b, _ := json.Marshal(k)
    21  	return base64.StdEncoding.EncodeToString(b)
    22  }
    23  
    24  func (m *syncMap) Read(key, val interface{}) error {
    25  	if key == nil {
    26  		return fmt.Errorf("key is nil")
    27  	}
    28  
    29  	kstr := ekey(key)
    30  
    31  	// lock
    32  	if err := m.opts.Lock.Acquire(kstr); err != nil {
    33  		return err
    34  	}
    35  	defer m.opts.Lock.Release(kstr)
    36  
    37  	// get key
    38  	kval, err := m.opts.Store.Read(kstr)
    39  	if err != nil {
    40  		return err
    41  	}
    42  
    43  	if len(kval) == 0 {
    44  		return store.ErrNotFound
    45  	}
    46  
    47  	// decode value
    48  	return json.Unmarshal(kval[0].Value, val)
    49  }
    50  
    51  func (m *syncMap) Write(key, val interface{}) error {
    52  	if key == nil {
    53  		return fmt.Errorf("key is nil")
    54  	}
    55  
    56  	kstr := ekey(key)
    57  
    58  	// lock
    59  	if err := m.opts.Lock.Acquire(kstr); err != nil {
    60  		return err
    61  	}
    62  	defer m.opts.Lock.Release(kstr)
    63  
    64  	// encode value
    65  	b, err := json.Marshal(val)
    66  	if err != nil {
    67  		return err
    68  	}
    69  
    70  	// set key
    71  	return m.opts.Store.Write(&store.Record{
    72  		Key:   kstr,
    73  		Value: b,
    74  	})
    75  }
    76  
    77  func (m *syncMap) Delete(key interface{}) error {
    78  	if key == nil {
    79  		return fmt.Errorf("key is nil")
    80  	}
    81  
    82  	kstr := ekey(key)
    83  
    84  	// lock
    85  	if err := m.opts.Lock.Acquire(kstr); err != nil {
    86  		return err
    87  	}
    88  	defer m.opts.Lock.Release(kstr)
    89  	return m.opts.Store.Delete(kstr)
    90  }
    91  
    92  func (m *syncMap) Iterate(fn func(key, val interface{}) error) error {
    93  	keyvals, err := m.opts.Store.List()
    94  	if err != nil {
    95  		return err
    96  	}
    97  
    98  	sort.Slice(keyvals, func(i, j int) bool {
    99  		return keyvals[i].Key < keyvals[j].Key
   100  	})
   101  
   102  	for _, keyval := range keyvals {
   103  		// lock
   104  		if err := m.opts.Lock.Acquire(keyval.Key); err != nil {
   105  			return err
   106  		}
   107  		// unlock
   108  		defer m.opts.Lock.Release(keyval.Key)
   109  
   110  		// unmarshal value
   111  		var val interface{}
   112  
   113  		if len(keyval.Value) > 0 && keyval.Value[0] == '{' {
   114  			if err := json.Unmarshal(keyval.Value, &val); err != nil {
   115  				return err
   116  			}
   117  		} else {
   118  			val = keyval.Value
   119  		}
   120  
   121  		// exec func
   122  		if err := fn(keyval.Key, val); err != nil {
   123  			return err
   124  		}
   125  
   126  		// save val
   127  		b, err := json.Marshal(val)
   128  		if err != nil {
   129  			return err
   130  		}
   131  
   132  		// no save
   133  		if i := bytes.Compare(keyval.Value, b); i == 0 {
   134  			return nil
   135  		}
   136  
   137  		// set key
   138  		if err := m.opts.Store.Write(&store.Record{
   139  			Key:   keyval.Key,
   140  			Value: b,
   141  		}); err != nil {
   142  			return err
   143  		}
   144  	}
   145  
   146  	return nil
   147  }
   148  
   149  func NewMap(opts ...Option) Map {
   150  	var options Options
   151  	for _, o := range opts {
   152  		o(&options)
   153  	}
   154  
   155  	if options.Lock == nil {
   156  		options.Lock = lock.NewLock()
   157  	}
   158  
   159  	if options.Store == nil {
   160  		options.Store = ckv.NewStore()
   161  	}
   162  
   163  	return &syncMap{
   164  		opts: options,
   165  	}
   166  }