redigolock

package module
v0.0.0-...-49ba144 Latest Latest
Warning

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

Go to latest
Published: Oct 18, 2013 License: MIT Imports: 4 Imported by: 0

README

Redigolock

A distributed optimistic locking manager implemented in Go, using the Redis data store with the Redigo client.

Installation

Install Redigolock using the "go get" command:

go get github.com/vube/redigolock

The Go distribution, a connection to a Redis server capable of keyless commands (ie, not behind nutcracker) and Redigo are Redigolock's dependencies.

Example

package main

import (
	"fmt"
	redigo "github.com/garyburd/redigo/redis"
	"github.com/vube/redigolock"
	"time"
)

func main() {
	host := "127.0.0.1:6381"
	key := "mylock"
	res := make(chan bool)

	for i := 0; i < 100; i++ {
		go func() {
			conn, err := redigo.Dial("tcp", host)

			if err != nil {
				fmt.Errorf("redigo.Dial failure due to '%s'", err)
				return
			}

			lock := redigolock.New(conn, key)

			status, err := lock.Lock()

			if status {
				// arbitrary distributed non-atomic operation
				v, _ := redigo.Int(conn.Do("GET", key))
				v++
				time.Sleep(100 * time.Millisecond)
				conn.Do("SET", key, v)
			} else {
				if err != nil {
					fmt.Errorf("lock operation failure due to '%s", err)
				} else {
					fmt.Errorf("timed out during lock contention")
				}
			}

			lock.UnlockIfLocked()
			res <- status
		}()
	}

	for i := 0; i < 100; i++ {
		<-res
	}

	conn, err := redigo.Dial("tcp", host)

	if err != nil {
		fmt.Errorf("redigo.Dial failure due to '%s'", err)
		return
	}

	v, _ := redigo.Int(conn.Do("GET", key))
	fmt.Printf("key = %d\n", v)
	conn.Do("DEL", key)
}

Output:

redigolock$ time go run example/example.go
key = 100

real	0m23.117s
user	0m0.292s
sys	0m1.020s

License

Redigolock is available under the MIT License.

Documentation

Index

Constants

View Source
const (
	// DefaultTimeout sets a default 30 second timeout on all lock attempts
	DefaultTimeout = 31000

	// DefaultAutoExpire sets a default 30 second TTL on all lock keys
	DefaultAutoExpire = 30000

	// DefaultHold sets a default artifical hold on the lock after an explicit
	// unlock
	DefaultHold = 0

	// DefaultTick sets a default retry on acquiring the lock after .25 seconds
	DefaultTick = 250
)

Variables

This section is empty.

Functions

This section is empty.

Types

type Redigoconn

type Redigoconn interface {
	Do(cmd string, args ...interface{}) (interface{}, error)
	Send(cmd string, args ...interface{}) error
	Close() error
}

Redigoconn sets up an interface which allows us to mock redigo.Conn for testing purposes

type Redigolock

type Redigolock struct {
	// The connection to Redis
	Conn Redigoconn

	// The base key we should work with
	Key string

	// How long before giving up on the lock. In milliseconds
	Timeout int64

	// How long to expire the lock if it's never unlocked. In milliseconds
	AutoExpire int64

	// How long to have the lock linger after it's unlocked. In milliseconds
	Hold int64

	// The retry interval before giving up on the lock. In milliseconds
	Tick time.Duration
	// contains filtered or unexported fields
}

Redigolock provides the configuration, as well as tracks the state, of our locking manager

func New

func New(conn Redigoconn, key string, extra ...interface{}) *Redigolock

New can be used to construct a new Redigolock struct which is used to hold the configurations for the behavior of the lock. Optional parameters can be passed to allow overriding all configurations

func (*Redigolock) KeepAlive

func (r *Redigolock) KeepAlive() error

KeepAlive will update the lock's expiration to keep it from expiring at the end of DefaultAutoExpire

func (*Redigolock) Lock

func (r *Redigolock) Lock() (bool, error)

Lock returns true if the lock operation succeeded and false if not, with an error if the operation failed due to any other reason than a normal timeout during an attempt to acquire the lock.

A lock attempt will fail under the following conditions:

  • The Redis connection fails
  • The Redis command fails (ie, nutcracker or another proxy service prevents our command set from being supported)
  • The key exists and contains an unexpected, non-integer value
  • The lock key exists and the value is a time greater than the current time, and our timeout is exceeded
  • The lock is obtained with another transaction and our timeout is exceeded
  • The key is modified in some way which invalidates our lock transaction and our timeout is exceeded

func (*Redigolock) LockFunc

func (r *Redigolock) LockFunc(call func()) (status bool, err error)

LockFunc allows for a routine to be surrounded by a lock. Wraps Lock/UnlockIfLocked.

func (*Redigolock) Unlock

func (r *Redigolock) Unlock() error

Unlock a lock

func (*Redigolock) UnlockIfLocked

func (r *Redigolock) UnlockIfLocked() error

UnlockIfLocked will release a lock only if we locked it, so you can defer the unlock and not break someone else's lock

Directories

Path Synopsis

Jump to

Keyboard shortcuts

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