Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor: move striplock to libs/utils package #4089

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
64 changes: 64 additions & 0 deletions libs/utils/striplock.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
package utils

import (
"sync"

"github.com/celestiaorg/celestia-node/share"
)

// StripLock provides a mechanism for locking access to data strips by height and hash.
// It uses a fixed number of mutexes to avoid excessive memory allocation while still
// providing sufficient granularity for concurrent access.
type StripLock struct {
heights []*sync.RWMutex
datahashes []*sync.RWMutex
}

// MultiLock represents multiple locks that need to be acquired together.
type MultiLock struct {
mu []*sync.RWMutex
}

// NewStripLock creates a new StripLock with the specified number of mutexes.
func NewStripLock(size int) *StripLock {
heights := make([]*sync.RWMutex, size)
datahashes := make([]*sync.RWMutex, size)
for i := 0; i < size; i++ {
heights[i] = &sync.RWMutex{}
datahashes[i] = &sync.RWMutex{}
}
return &StripLock{heights, datahashes}
}

// ByHeight returns a mutex for the given height.
func (l *StripLock) ByHeight(height uint64) *sync.RWMutex {
lkIdx := height % uint64(len(l.heights))
return l.heights[lkIdx]
}

// ByHash returns a mutex for the given data hash.
func (l *StripLock) ByHash(datahash share.DataHash) *sync.RWMutex {
// Use the last 2 bytes of the hash as key to distribute the locks
last := uint16(datahash[len(datahash)-1]) | uint16(datahash[len(datahash)-2])<<8
lkIdx := last % uint16(len(l.datahashes))
return l.datahashes[lkIdx]
}

// ByHashAndHeight returns a MultiLock for both the hash and height.
func (l *StripLock) ByHashAndHeight(datahash share.DataHash, height uint64) *MultiLock {
return &MultiLock{[]*sync.RWMutex{l.ByHash(datahash), l.ByHeight(height)}}
}

// Lock acquires all the contained locks.
func (m *MultiLock) Lock() {
for _, lk := range m.mu {
lk.Lock()
}
}

// Unlock releases all the contained locks.
func (m *MultiLock) Unlock() {
for _, lk := range m.mu {
lk.Unlock()
}
}
25 changes: 8 additions & 17 deletions store/striplock.go
Original file line number Diff line number Diff line change
@@ -1,29 +1,20 @@
package store

import (
"sync"

"github.com/celestiaorg/celestia-node/libs/utils"
"github.com/celestiaorg/celestia-node/share"
)

// TODO: move to utils
type striplock struct {
heights []*sync.RWMutex
datahashes []*sync.RWMutex
}
// stripLock is deprecated, use utils.StripLock instead
type striplock = utils.StripLock

type multiLock struct {
mu []*sync.RWMutex
}
// multiLock is deprecated, use utils.MultiLock instead
type multiLock = utils.MultiLock

// newStripLock creates a new StripLock with the specified number of mutexes.
// Deprecated: use utils.NewStripLock instead
func newStripLock(size int) *striplock {
heights := make([]*sync.RWMutex, size)
datahashes := make([]*sync.RWMutex, size)
for i := 0; i < size; i++ {
heights[i] = &sync.RWMutex{}
datahashes[i] = &sync.RWMutex{}
}
return &striplock{heights, datahashes}
return utils.NewStripLock(size)
}

func (l *striplock) byHeight(height uint64) *sync.RWMutex {
Expand Down