rwlock

package module
v1.2.0 Latest Latest
Warning

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

Go to latest
Published: May 3, 2026 License: MIT Imports: 3 Imported by: 0

README

redis-rwlock

Distributed RW-lock for Go backed by Redis. Readers acquire the lock shared; a writer acquires it exclusively.

Inspired by the Redis distributed locking pattern. All lock operations are single atomic Lua scripts.

Installation

module github.com/e-chip/redis-rwlock

go 1.24.0

Core package (no Redis dependency):

go get github.com/e-chip/redis-rwlock/pkg/rwlock

Pick an adapter for your Redis client:

# go-redis v9 (current)
go get github.com/e-chip/redis-rwlock/adapters/goredis9
# go-redis v6 (legacy)
go get github.com/e-chip/redis-rwlock/adapters/goredisv6

Usage

import (
    "github.com/e-chip/redis-rwlock/pkg/rwlock"
    goredis9 "github.com/e-chip/redis-rwlock/adapters/goredis9"
    goredis "github.com/redis/go-redis/v9"
)

client := goredis.NewClient(&goredis.Options{Addr: "localhost:6379"})

locker := rwlock.New(
    goredis9.New(client),
    "myapp:lock",          // global lock key
    "myapp:readers",       // reader reference counter key
    "myapp:writer_intent", // writer intent key
    rwlock.Options{},
)

// Shared read access — multiple readers run concurrently.
err := locker.Read(func() {
    // critical section
})

// Exclusive write access — no readers or other writers run concurrently.
err = locker.Write(func() {
    // critical section
})

Custom Redis client

Implement the two-method RedisClient interface to use any Redis client:

type RedisClient interface {
    Ping(ctx context.Context) error
    Eval(ctx context.Context, script string, keys []string, args ...interface{}) (int64, error)
}

Options

Option Default Minimum Description
LockTTL 1 s 100 ms Lock expiry. Automatically refreshed every LockTTL/2 while held. Keep lower than RetryCount × RetryInterval to avoid spurious ErrTimeout.
RetryCount 200 1 Number of acquisition attempts before returning ErrTimeout.
RetryInterval 10 ms 1 ms Pause between acquisition attempts.
Context context.Background() Cancelling the context returns ErrInterrupted.
AppID "" Prefix added to the writer token. Useful for debugging which instance holds the lock.
ReaderLockToken "read_c2d-75a1-4b5b-a6fb-b0754224c666" Shared token for all readers in a group. Override to create independent reader groups on the same keys.
Mode ModePreferWriter See Mutex modes.

Mutex modes

ModePreferWriter — writer-preferring (default). When a writer is waiting, it sets an intent key. New readers detect the intent and back off, letting the writer proceed as soon as existing readers finish. Prevents writer starvation.

ModePreferReader — reader-preferring. The intent key is still set by the writer but readers ignore it. A writer must wait until all readers (present and future) release the lock naturally. May starve writers under continuous read load.

Error reference

Error Meaning
ErrConnection Redis is unreachable (checked via Ping before each operation).
ErrTimeout Lock was not acquired within RetryCount × RetryInterval.
ErrInterrupted The provided Context was cancelled while waiting.
ErrNotReleased Lock was acquired but could not be released.
ErrUnknownMode Options.Mode was set to an unrecognised value.

Lua scripts

All lock operations are single atomic Lua scripts embedded in the binary (pkg/rwlock/lua/). The reference sources with comments live in lua/.

Documentation

Overview

Package rwlock is an adapter package to pkg/rwlock. Consider using pkg/rwlock package in new projects as this file may be eventually removed.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Locker

type Locker = rwlock.Locker

Locker is an alias type to #rwlock.Locker

func Make

func Make(redisClient *goredis.Client, keyLock, keyReadersCount, keyWriterIntent string, opts *Options) Locker

Make new instance of RW-Locker. Deprecated due to incorrect naming of the function. Use #rwlock.New instead.

func New added in v1.1.0

func New(redisClient *goredis.Client, keyLock, keyReadersCount, keyWriterIntent string, opts *Options) Locker

New instance of RW-Locker. Use #rwlock.New instead.

type Options

type Options = rwlock.Options

Options is an alias type to #rwlock.Options

Directories

Path Synopsis
adapters
goredisv9 module
pkg

Jump to

Keyboard shortcuts

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