rowlock

package module
v0.4.0 Latest Latest
Warning

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

Go to latest
Published: Jan 1, 2021 License: BSD-3-Clause Imports: 2 Imported by: 1

README

PkgGoDev Go Report Card

RowLock

RowLock is a Go library. A row lock is a set of locks associated with rows. Instead of locking and unlocking globally, you only operate locks on a row level.

(Example code on pkg.go.dev)

License

BSD 3-Clause.

Documentation

Overview

Package rowlock provides an implementation of row lock.

A row lock is a set of locks associated with rows. Instead of locking and unlocking globally, you only operate locks on a row level.

RowLock provides optional RLock and RUnlock functions to use separated read and write locks. In order to take advantage of them, NewLocker function used in NewRowLock must returns an implementation of RWLocker (for example, RWMutexNewLocker returns a new sync.RWMutex). If the locker returned by NewLocker didn't implement RLocker function defined in RWLocker, RLock will work the same as Lock and RUnlock will work the same as Unlock.

Example
package main

import (
	"fmt"
	"sync"
	"time"

	"go.yhsif.com/rowlock"
)

func main() {
	lock := rowlock.NewRowLock(rowlock.MutexNewLocker)
	key1 := "key1"
	key2 := "key2"
	round := time.Millisecond * 50

	keys := []string{key1, key1, key2, key2}
	sleeps := []time.Duration{
		time.Millisecond * 250,
		time.Millisecond * 200,
		time.Millisecond * 350,
		time.Millisecond * 300,
	}

	var wg sync.WaitGroup
	wg.Add(len(keys))

	for i := range keys {
		go func(key string, sleep time.Duration) {
			started := time.Now()
			defer wg.Done()
			time.Sleep(sleep)
			lock.Lock(key)
			defer lock.Unlock(key)
			elapsed := time.Now().Sub(started).Round(round)
			// The same key with longer sleep will get an elapsed time about
			// 2 * the same key with shorter sleep instead of its own sleep time,
			// because that's when the other goroutine releases the lock.
			fmt.Printf("%s got lock after about %v\n", key, elapsed)
			time.Sleep(sleep)
		}(keys[i], sleeps[i])
	}

	wg.Wait()
}
Output:

key1 got lock after about 200ms
key2 got lock after about 300ms
key1 got lock after about 400ms
key2 got lock after about 600ms

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

func MutexNewLocker

func MutexNewLocker() sync.Locker

MutexNewLocker is a NewLocker using sync.Mutex.

func RWMutexNewLocker

func RWMutexNewLocker() sync.Locker

RWMutexNewLocker is a NewLocker using sync.RWMutex.

Example
package main

import (
	"fmt"
	"sync"
	"time"

	"go.yhsif.com/rowlock"
)

func main() {
	lock := rowlock.NewRowLock(rowlock.RWMutexNewLocker)
	key1 := "key1"
	key2 := "key2"
	round := time.Millisecond * 50

	var wg sync.WaitGroup

	readKeys := []string{key1, key1, key2, key2}
	readSleeps := []time.Duration{
		time.Millisecond * 250,
		time.Millisecond * 200,
		time.Millisecond * 350,
		time.Millisecond * 300,
	}
	wg.Add(len(readKeys))

	writeKeys := []string{key1, key1, key2, key2}
	writeSleeps := []time.Duration{
		time.Millisecond * 350,
		time.Millisecond * 150,
		time.Millisecond * 450,
		time.Millisecond * 200,
	}
	wg.Add(len(writeKeys))

	// Read locks
	for i := range readKeys {
		go func(key string, sleep time.Duration) {
			started := time.Now()
			defer wg.Done()
			time.Sleep(sleep)
			lock.RLock(key)
			defer lock.RUnlock(key)
			elapsed := time.Now().Sub(started).Round(round)
			// Should be:
			//   max(shorter write sleep time * 2, self sleep time)
			fmt.Printf("%s got read lock after about %v\n", key, elapsed)
			time.Sleep(sleep)
		}(readKeys[i], readSleeps[i])
	}

	// Write locks
	for i := range writeKeys {
		go func(key string, sleep time.Duration) {
			started := time.Now()
			defer wg.Done()
			time.Sleep(sleep)
			lock.Lock(key)
			defer lock.Unlock(key)
			elapsed := time.Now().Sub(started).Round(round)
			// For the longer sleep one, it should be
			//   max(shorter write * 2, longer read) + longer read
			// instead of it's self sleep time
			fmt.Printf("%s got lock after about %v\n", key, elapsed)
			time.Sleep(sleep)
		}(writeKeys[i], writeSleeps[i])
	}

	wg.Wait()
}
Output:

key1 got lock after about 150ms
key2 got lock after about 200ms
key1 got read lock after about 300ms
key1 got read lock after about 300ms
key2 got read lock after about 400ms
key2 got read lock after about 400ms
key1 got lock after about 550ms
key2 got lock after about 750ms

Types

type NewLocker

type NewLocker func() sync.Locker

NewLocker defines a type of function that can be used to create a new Locker.

type RWLocker

type RWLocker interface {
	sync.Locker

	RLocker() sync.Locker
}

RWLocker is the abstracted interface of sync.RWMutex.

type Row

type Row = defaultdict.Comparable

Row is the type of a row.

It must be comparable: https://golang.org/ref/spec#Comparison_operators.

type RowLock

type RowLock struct {
	// contains filtered or unexported fields
}

RowLock defines a set of locks.

When you do Lock/Unlock operations, you don't do them on a global scale. Instead, a Lock/Unlock operation is operated on a given row.

If NewLocker returns an implementation of RWLocker in NewRowLock, the RowLock can be locked separately for read in RLock and RUnlock functions. Otherwise, RLock is the same as Lock and RUnlock is the same as Unlock.

func NewRowLock

func NewRowLock(f NewLocker) *RowLock

NewRowLock creates a new RowLock with the given NewLocker.

func (*RowLock) Lock

func (rl *RowLock) Lock(row Row)

Lock locks a row.

If this is a new row, a new locker will be created using the NewLocker specified in NewRowLock.

func (*RowLock) RLock

func (rl *RowLock) RLock(row Row)

RLock locks a row for read.

It only works as expected when NewLocker specified in NewRowLock returns an implementation of RWLocker. Otherwise, it's the same as Lock.

func (*RowLock) RUnlock

func (rl *RowLock) RUnlock(row Row)

RUnlock unlocks a row for read.

It only works as expected when NewLocker specified in NewRowLock returns an implementation of RWLocker. Otherwise, it's the same as Unlock.

func (*RowLock) Unlock

func (rl *RowLock) Unlock(row Row)

Unlock unlocks a row.

Jump to

Keyboard shortcuts

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