github.com/m3db/m3@v1.5.0/src/dbnode/storage/block/lease.go (about)

     1  // Copyright (c) 2019 Uber Technologies, Inc.
     2  //
     3  // Permission is hereby granted, free of charge, to any person obtaining a copy
     4  // of this software and associated documentation files (the "Software"), to deal
     5  // in the Software without restriction, including without limitation the rights
     6  // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
     7  // copies of the Software, and to permit persons to whom the Software is
     8  // furnished to do so, subject to the following conditions:
     9  //
    10  // The above copyright notice and this permission notice shall be included in
    11  // all copies or substantial portions of the Software.
    12  //
    13  // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    14  // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    15  // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
    16  // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    17  // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    18  // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
    19  // THE SOFTWARE.
    20  
    21  package block
    22  
    23  import (
    24  	"errors"
    25  	"fmt"
    26  	"sync"
    27  )
    28  
    29  var (
    30  	errLeaserAlreadyRegistered        = errors.New("leaser already registered")
    31  	errLeaserNotRegistered            = errors.New("leaser not registered")
    32  	errOpenLeaseVerifierNotSet        = errors.New("cannot open leases while verifier is not set")
    33  	errUpdateOpenLeasesVerifierNotSet = errors.New("cannot update open leases while verifier is not set")
    34  	errConcurrentUpdateOpenLeases     = errors.New("cannot call updateOpenLeases() concurrently")
    35  )
    36  
    37  type leaseManager struct {
    38  	sync.Mutex
    39  	updateOpenLeasesInProgress sync.Map
    40  	leasers                    []Leaser
    41  	verifier                   LeaseVerifier
    42  }
    43  
    44  // NewLeaseManager creates a new lease manager with a provided
    45  // lease verifier (to ensure leases are valid when made).
    46  func NewLeaseManager(verifier LeaseVerifier) LeaseManager {
    47  	return &leaseManager{
    48  		verifier: verifier,
    49  	}
    50  }
    51  
    52  func (m *leaseManager) RegisterLeaser(leaser Leaser) error {
    53  	m.Lock()
    54  	defer m.Unlock()
    55  
    56  	if m.isRegistered(leaser) {
    57  		return errLeaserAlreadyRegistered
    58  	}
    59  	m.leasers = append(m.leasers, leaser)
    60  
    61  	return nil
    62  }
    63  
    64  func (m *leaseManager) UnregisterLeaser(leaser Leaser) error {
    65  	m.Lock()
    66  	defer m.Unlock()
    67  
    68  	var leasers []Leaser
    69  	for _, l := range m.leasers {
    70  		if l != leaser {
    71  			leasers = append(leasers, l)
    72  		}
    73  	}
    74  
    75  	if len(leasers) != len(m.leasers)-1 {
    76  		return errLeaserNotRegistered
    77  	}
    78  
    79  	m.leasers = leasers
    80  
    81  	return nil
    82  }
    83  
    84  func (m *leaseManager) OpenLease(
    85  	leaser Leaser,
    86  	descriptor LeaseDescriptor,
    87  	state LeaseState,
    88  ) error {
    89  	// NB(r): Take exclusive lock so that upgrade leases can't be called
    90  	// while we are verifying a lease (racey)
    91  	// NB(bodu): We don't use defer here since the lease verifier takes out a
    92  	// a db lock when retrieving flush states resulting in a potential deadlock.
    93  	m.Lock()
    94  
    95  	if m.verifier == nil {
    96  		m.Unlock()
    97  		return errOpenLeaseVerifierNotSet
    98  	}
    99  
   100  	if !m.isRegistered(leaser) {
   101  		m.Unlock()
   102  		return errLeaserNotRegistered
   103  	}
   104  
   105  	m.Unlock()
   106  	return m.verifier.VerifyLease(descriptor, state)
   107  }
   108  
   109  func (m *leaseManager) OpenLatestLease(
   110  	leaser Leaser,
   111  	descriptor LeaseDescriptor,
   112  ) (LeaseState, error) {
   113  	// NB(r): Take exclusive lock so that upgrade leases can't be called
   114  	// while we are verifying a lease (racey)
   115  	// NB(bodu): We don't use defer here since the lease verifier takes out a
   116  	// a db lock when retrieving flush states resulting in a potential deadlock.
   117  	m.Lock()
   118  
   119  	if m.verifier == nil {
   120  		m.Unlock()
   121  		return LeaseState{}, errOpenLeaseVerifierNotSet
   122  	}
   123  
   124  	if !m.isRegistered(leaser) {
   125  		m.Unlock()
   126  		return LeaseState{}, errLeaserNotRegistered
   127  	}
   128  
   129  	m.Unlock()
   130  	return m.verifier.LatestState(descriptor)
   131  }
   132  
   133  func (m *leaseManager) UpdateOpenLeases(
   134  	descriptor LeaseDescriptor,
   135  	state LeaseState,
   136  ) (UpdateLeasesResult, error) {
   137  	m.Lock()
   138  	if m.verifier == nil {
   139  		m.Unlock()
   140  		return UpdateLeasesResult{}, errUpdateOpenLeasesVerifierNotSet
   141  	}
   142  	// NB(rartoul): Release lock while calling UpdateOpenLease() so that
   143  	// calls to OpenLease() and OpenLatestLease() are not blocked which
   144  	// would blocks reads and could cause deadlocks if those calls were
   145  	// made while holding locks that would not allow UpdateOpenLease() to
   146  	// return before being released.
   147  	m.Unlock()
   148  
   149  	hashableDescriptor := NewHashableLeaseDescriptor(descriptor)
   150  	if _, ok := m.updateOpenLeasesInProgress.LoadOrStore(hashableDescriptor, struct{}{}); ok {
   151  		// Prevent UpdateOpenLeases() calls from happening concurrently (since the lock
   152  		// is not held for the duration) to ensure that Leaser's receive all updates
   153  		// and in the correct order.
   154  		return UpdateLeasesResult{}, errConcurrentUpdateOpenLeases
   155  	}
   156  
   157  	defer m.updateOpenLeasesInProgress.Delete(hashableDescriptor)
   158  
   159  	var result UpdateLeasesResult
   160  	for _, l := range m.leasers {
   161  		r, err := l.UpdateOpenLease(descriptor, state)
   162  		if err != nil {
   163  			return result, err
   164  		}
   165  
   166  		switch r {
   167  		case UpdateOpenLease:
   168  			result.LeasersUpdatedLease++
   169  		case NoOpenLease:
   170  			result.LeasersNoOpenLease++
   171  		default:
   172  			return result, fmt.Errorf("unknown update open lease result: %d", r)
   173  		}
   174  	}
   175  
   176  	return result, nil
   177  }
   178  
   179  func (m *leaseManager) SetLeaseVerifier(leaseVerifier LeaseVerifier) error {
   180  	m.Lock()
   181  	defer m.Unlock()
   182  	m.verifier = leaseVerifier
   183  	return nil
   184  }
   185  
   186  func (m *leaseManager) isRegistered(leaser Leaser) bool {
   187  	for _, l := range m.leasers {
   188  		if l == leaser {
   189  			return true
   190  		}
   191  	}
   192  	return false
   193  }