From b4f355b4f681d535bc28820ad931c10b77b29d63 Mon Sep 17 00:00:00 2001 From: VolodymyrBg Date: Tue, 4 Feb 2025 21:05:45 +0200 Subject: [PATCH 1/3] refactor: move striplock to libs/utils package --- store/striplock.go | 25 ++++++++----------------- 1 file changed, 8 insertions(+), 17 deletions(-) diff --git a/store/striplock.go b/store/striplock.go index 4738453c77..5eb3dc625b 100644 --- a/store/striplock.go +++ b/store/striplock.go @@ -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 { From 07ae974df212a5f651a15311d4de41bb0ce7fd7f Mon Sep 17 00:00:00 2001 From: VolodymyrBg Date: Tue, 4 Feb 2025 21:06:15 +0200 Subject: [PATCH 2/3] Create striplock.go --- libs/utils/striplock.go | 1 + 1 file changed, 1 insertion(+) create mode 100644 libs/utils/striplock.go diff --git a/libs/utils/striplock.go b/libs/utils/striplock.go new file mode 100644 index 0000000000..8b13789179 --- /dev/null +++ b/libs/utils/striplock.go @@ -0,0 +1 @@ + From 933f99ece9afde4e61ed6cd57cd7cea0786e54e5 Mon Sep 17 00:00:00 2001 From: VolodymyrBg Date: Tue, 4 Feb 2025 21:06:31 +0200 Subject: [PATCH 3/3] refactor: move striplock to libs/utils package --- libs/utils/striplock.go | 63 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 63 insertions(+) diff --git a/libs/utils/striplock.go b/libs/utils/striplock.go index 8b13789179..ed7a1a5646 100644 --- a/libs/utils/striplock.go +++ b/libs/utils/striplock.go @@ -1 +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() + } +}