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

     1  // Package etcd is an etcd implementation of lock
     2  package etcd
     3  
     4  import (
     5  	"context"
     6  	"errors"
     7  	"log"
     8  	"path"
     9  	"strings"
    10  	"sync"
    11  
    12  	client "github.com/coreos/etcd/clientv3"
    13  	cc "github.com/coreos/etcd/clientv3/concurrency"
    14  	"gitee.com/liuxuezhan/go-micro-v1.18.0/sync/lock"
    15  )
    16  
    17  type etcdLock struct {
    18  	opts   lock.Options
    19  	path   string
    20  	client *client.Client
    21  
    22  	sync.Mutex
    23  	locks map[string]*elock
    24  }
    25  
    26  type elock struct {
    27  	s *cc.Session
    28  	m *cc.Mutex
    29  }
    30  
    31  func (e *etcdLock) Acquire(id string, opts ...lock.AcquireOption) error {
    32  	var options lock.AcquireOptions
    33  	for _, o := range opts {
    34  		o(&options)
    35  	}
    36  
    37  	// make path
    38  	path := path.Join(e.path, strings.Replace(e.opts.Prefix+id, "/", "-", -1))
    39  
    40  	var sopts []cc.SessionOption
    41  	if options.TTL > 0 {
    42  		sopts = append(sopts, cc.WithTTL(int(options.TTL.Seconds())))
    43  	}
    44  
    45  	s, err := cc.NewSession(e.client, sopts...)
    46  	if err != nil {
    47  		return err
    48  	}
    49  
    50  	m := cc.NewMutex(s, path)
    51  
    52  	if err := m.Lock(context.TODO()); err != nil {
    53  		return err
    54  	}
    55  
    56  	e.Lock()
    57  	e.locks[id] = &elock{
    58  		s: s,
    59  		m: m,
    60  	}
    61  	e.Unlock()
    62  	return nil
    63  }
    64  
    65  func (e *etcdLock) Release(id string) error {
    66  	e.Lock()
    67  	defer e.Unlock()
    68  	v, ok := e.locks[id]
    69  	if !ok {
    70  		return errors.New("lock not found")
    71  	}
    72  	err := v.m.Unlock(context.Background())
    73  	delete(e.locks, id)
    74  	return err
    75  }
    76  
    77  func (e *etcdLock) String() string {
    78  	return "etcd"
    79  }
    80  
    81  func NewLock(opts ...lock.Option) lock.Lock {
    82  	var options lock.Options
    83  	for _, o := range opts {
    84  		o(&options)
    85  	}
    86  
    87  	var endpoints []string
    88  
    89  	for _, addr := range options.Nodes {
    90  		if len(addr) > 0 {
    91  			endpoints = append(endpoints, addr)
    92  		}
    93  	}
    94  
    95  	if len(endpoints) == 0 {
    96  		endpoints = []string{"http://127.0.0.1:2379"}
    97  	}
    98  
    99  	// TODO: parse addresses
   100  	c, err := client.New(client.Config{
   101  		Endpoints: endpoints,
   102  	})
   103  	if err != nil {
   104  		log.Fatal(err)
   105  	}
   106  
   107  	return &etcdLock{
   108  		path:   "/micro/lock",
   109  		client: c,
   110  		opts:   options,
   111  		locks:  make(map[string]*elock),
   112  	}
   113  }