github.com/niedbalski/juju@v0.0.0-20190215020005-8ff100488e47/provider/dummy/leasestore.go (about)

     1  // Copyright 2012, 2013 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package dummy
     5  
     6  import (
     7  	"sync"
     8  	"time"
     9  
    10  	"github.com/juju/clock"
    11  	"github.com/juju/errors"
    12  
    13  	"github.com/juju/juju/core/lease"
    14  	"github.com/juju/juju/core/raftlease"
    15  )
    16  
    17  // leaseStore implements lease.Store as simply as possible for use in
    18  // the dummy provider. Heavily cribbed from raftlease.FSM.
    19  type leaseStore struct {
    20  	mu       sync.Mutex
    21  	clock    clock.Clock
    22  	entries  map[lease.Key]*entry
    23  	trapdoor raftlease.TrapdoorFunc
    24  	target   raftlease.NotifyTarget
    25  }
    26  
    27  // entry holds the details of a lease.
    28  type entry struct {
    29  	// holder identifies the current holder of the lease.
    30  	holder string
    31  
    32  	// start is the global time at which the lease started.
    33  	start time.Time
    34  
    35  	// duration is the duration for which the lease is valid,
    36  	// from the start time.
    37  	duration time.Duration
    38  }
    39  
    40  func newLeaseStore(clock clock.Clock, target raftlease.NotifyTarget, trapdoor raftlease.TrapdoorFunc) *leaseStore {
    41  	return &leaseStore{
    42  		clock:    clock,
    43  		entries:  make(map[lease.Key]*entry),
    44  		target:   target,
    45  		trapdoor: trapdoor,
    46  	}
    47  }
    48  
    49  // Autoexpire is part of lease.Store.
    50  func (*leaseStore) Autoexpire() bool { return false }
    51  
    52  // ClaimLease is part of lease.Store.
    53  func (s *leaseStore) ClaimLease(key lease.Key, req lease.Request) error {
    54  	s.mu.Lock()
    55  	defer s.mu.Unlock()
    56  	if _, found := s.entries[key]; found {
    57  		return lease.ErrInvalid
    58  	}
    59  	s.entries[key] = &entry{
    60  		holder:   req.Holder,
    61  		start:    s.clock.Now(),
    62  		duration: req.Duration,
    63  	}
    64  	s.target.Claimed(key, req.Holder)
    65  	return nil
    66  }
    67  
    68  // ExtendLease is part of lease.Store.
    69  func (s *leaseStore) ExtendLease(key lease.Key, req lease.Request) error {
    70  	s.mu.Lock()
    71  	defer s.mu.Unlock()
    72  	entry, found := s.entries[key]
    73  	if !found {
    74  		return lease.ErrInvalid
    75  	}
    76  	if entry.holder != req.Holder {
    77  		return lease.ErrInvalid
    78  	}
    79  	now := s.clock.Now()
    80  	expiry := now.Add(req.Duration)
    81  	if !expiry.After(entry.start.Add(entry.duration)) {
    82  		// No extension needed - the lease already expires after the
    83  		// new time.
    84  		return nil
    85  	}
    86  	// entry is a pointer back into the f.entries map, so this update
    87  	// isn't lost.
    88  	entry.start = now
    89  	entry.duration = req.Duration
    90  	return nil
    91  }
    92  
    93  // Expire is part of lease.Store.
    94  func (s *leaseStore) ExpireLease(key lease.Key) error {
    95  	s.mu.Lock()
    96  	defer s.mu.Unlock()
    97  	entry, found := s.entries[key]
    98  	if !found {
    99  		return lease.ErrInvalid
   100  	}
   101  	expiry := entry.start.Add(entry.duration)
   102  	if !s.clock.Now().After(expiry) {
   103  		return lease.ErrInvalid
   104  	}
   105  	delete(s.entries, key)
   106  	s.target.Expired(key)
   107  	return nil
   108  }
   109  
   110  // Leases is part of lease.Store.
   111  func (s *leaseStore) Leases(keys ...lease.Key) map[lease.Key]lease.Info {
   112  	s.mu.Lock()
   113  	defer s.mu.Unlock()
   114  
   115  	filter := make(map[lease.Key]bool)
   116  	filtering := len(keys) > 0
   117  	if filtering {
   118  		for _, key := range keys {
   119  			filter[key] = true
   120  		}
   121  	}
   122  
   123  	results := make(map[lease.Key]lease.Info)
   124  	for key, entry := range s.entries {
   125  		if filtering && !filter[key] {
   126  			continue
   127  		}
   128  
   129  		results[key] = lease.Info{
   130  			Holder:   entry.holder,
   131  			Expiry:   entry.start.Add(entry.duration),
   132  			Trapdoor: s.trapdoor(key, entry.holder),
   133  		}
   134  	}
   135  	return results
   136  }
   137  
   138  // Refresh is part of lease.Store.
   139  func (s *leaseStore) Refresh() error {
   140  	return nil
   141  }
   142  
   143  // PinLease is part of lease.Store.
   144  func (s *leaseStore) PinLease(key lease.Key, entity string) error {
   145  	return errors.NotImplementedf("lease pinning")
   146  }
   147  
   148  // UnpinLease is part of lease.Store.
   149  func (s *leaseStore) UnpinLease(key lease.Key, entity string) error {
   150  	return errors.NotImplementedf("lease unpinning")
   151  }
   152  
   153  // Pinned is part of the Store interface.
   154  func (s *leaseStore) Pinned() map[lease.Key][]string {
   155  	return nil
   156  }