lockgate

package module
v0.0.0-...-32bcf5a Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Apr 23, 2020 License: Apache-2.0 Imports: 15 Imported by: 0

README

Lockgate

Lockgate is a locking library for go.

  • Classical interface:
    • 2 types of locks: shared and exclusive;
    • 2 modes of locking: blocking and non-blocking.
  • File locks on the single host are supported.
  • Kubernetes-based distributed locks are supported:
    • kubernetes locker is configured by an arbitrary kubernetes resource;
    • locks are stored in the annotations of the specified resource;
    • properly use native kubernetes optimistic locking to handle simultaneous access to the resource.

This library is used in the werf CI/CD tool to implement synchronization of multiple werf build and deploy processes running from single or multiple hosts using Kubernetes or local file locks.

If you have an Open Source project using lockgate, feel free to list it here.

Installation

go get -u github.com/flant/lockgate

Usage

In the following example a locker object instance is created using either NewFileLocker or NewKubernetesLocker constructor — user should select needed locker implementation. The rest of the sample uses lockgate.Locker interface to acquire and release locks.

import "github.com/flant/lockgate"

func main() {
	// Create Kubernetes based locker in ns/mynamespace cm/myconfigmap.
	// Initialize kubeDynamicClient from https://github.com/kubernetes/client-go.
        locker := lockgate.NewKubernetesLocker(                                                          
                kubeDynamicClient, schema.GroupVersionResource{                                         
                        Group:    "",                                                                    
                        Version:  "v1",                                                                  
                        Resource: "configmaps",                                                          
                }, "myconfigmap", "mynamespace",                                                              
        )
	
	// OR create file based locker backed by /var/locks/mylocks_service_dir directory
    	locker, err := lockgate.NewFileLocker("/var/locks/mylocks_service_dir")
	if err != nil {
		fmt.Fprintf(os.Stderr, "ERROR: failed to create file locker: %s\n", err)
		os.Exit(1)
	}

        // Case 1: simple blocking lock

	acquired, lock, err := locker.Acquire("myresource", lockgate.AcquireOptions{Shared: false, Timeout: 30*time.Second}
	if err != nil {
		fmt.Fprintf(os.Stderr, "ERROR: failed to lock myresource: %s\n", err)
		os.Exit(1)
	}

	// ...

	if err := locker.Release(lock); err != nil {
		fmt.Fprintf(os.Stderr, "ERROR: failed to unlock myresource: %s\n", err)
		os.Exit(1)
	}

	// Case 2: WithAcquire wrapper

	if err := lockgate.WithAcquire(locker, "myresource", lockgate.AcquireOptions{Shared: false, Timeout: 30*time.Second}, func(acquired bool) error {
		// ...
	}); err != nil {
		fmt.Fprintf(os.Stderr, "ERROR: failed to perform an operation with locker myresource: %s\n", err)
		os.Exit(1)
	}
	
	// Case 3: non-blocking

	acquired, lock, err := locker.Acquire("myresource", lockgate.AcquireOptions{Shared: false, NonBlocking: true})
	if err != nil {
		fmt.Fprintf(os.Stderr, "ERROR: failed to lock myresource: %s\n", err)
		os.Exit(1)
	}

	if acquired {
		// ...
	} else {
		// ...
	}

	if err := locker.Release(lock); err != nil {
		fmt.Fprintf(os.Stderr, "ERROR: failed to unlock myresource: %s\n", err)
		os.Exit(1)
	}
}

Documentation

Index

Constants

This section is empty.

Variables

View Source
var (
	ErrLockAlreadyLeased        = default_errors.New("lock already leased")
	ErrNoExistingLockLeaseFound = default_errors.New("no existing lock lease found")
)

Functions

func WithAcquire

func WithAcquire(locker Locker, lockName string, opts AcquireOptions, f func(acquired bool) error) (resErr error)

Types

type AcquireOptions

type AcquireOptions struct {
	NonBlocking bool
	Timeout     time.Duration
	Shared      bool

	OnWaitFunc      func(lock LockHandle, doWait func() error) error
	OnLostLeaseFunc func(lock LockHandle) error
}

type FileLocker

type FileLocker struct {
	LocksDir string
	// contains filtered or unexported fields
}

func NewFileLocker

func NewFileLocker(locksDir string) (*FileLocker, error)

func (*FileLocker) Acquire

func (locker *FileLocker) Acquire(lockName string, opts AcquireOptions) (bool, LockHandle, error)

func (*FileLocker) Release

func (locker *FileLocker) Release(lockHandle LockHandle) error

type KubernetesLocker

type KubernetesLocker struct {
	KubernetesInterface dynamic.Interface
	GVR                 schema.GroupVersionResource
	ResourceName        string
	Namespace           string
	// contains filtered or unexported fields
}

func NewKubernetesLocker

func NewKubernetesLocker(kubernetesInterface dynamic.Interface, gvr schema.GroupVersionResource, resourceName string, namespace string) *KubernetesLocker

func (*KubernetesLocker) Acquire

func (locker *KubernetesLocker) Acquire(lockName string, opts AcquireOptions) (bool, LockHandle, error)

func (*KubernetesLocker) Release

func (locker *KubernetesLocker) Release(lockHandle LockHandle) error

type LeaseRenewWorkerDescriptor

type LeaseRenewWorkerDescriptor struct {
	DoneChan           chan struct{}
	SharedLeaseCounter int64
}

type LockHandle

type LockHandle struct {
	UUID     string
	LockName string
}

type LockLeaseRecord

type LockLeaseRecord struct {
	LockHandle
	ExpireAtTimestamp  int64
	SharedHoldersCount int64
	IsShared           bool
}

type Locker

type Locker interface {
	Acquire(lockName string, opts AcquireOptions) (bool, LockHandle, error)
	Release(lock LockHandle) error
}

Locker is an abstract interface to interact with the locker. Locker implementation is always thread safe so it is possible to use a single Locker in multiple goroutines.

Note that LockHandle objects should be managed by the user manually to acquire multiple locks from the same process: to release a lock user must pass the same LockHandle object that was given by Acquire method to the Release method.

Directories

Path Synopsis
pkg
playground
one
two

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL