-
Notifications
You must be signed in to change notification settings - Fork 166
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #1 from ecodeclub/dev
在list package中增加了skiplist
- Loading branch information
Showing
6 changed files
with
205 additions
and
60 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,80 @@ | ||
// Copyright 2021 ecodeclub | ||
// | ||
// Licensed under the Apache License, Version 2.0 (the "License"); | ||
// you may not use this file except in compliance with the License. | ||
// You may obtain a copy of the License at | ||
// | ||
// http://www.apache.org/licenses/LICENSE-2.0 | ||
// | ||
// Unless required by applicable law or agreed to in writing, software | ||
// distributed under the License is distributed on an "AS IS" BASIS, | ||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
// See the License for the specific language governing permissions and | ||
// limitations under the License. | ||
|
||
package syncx | ||
|
||
import ( | ||
"hash/fnv" | ||
"sync" | ||
) | ||
|
||
// SegmentKeysLock 部分key lock结构定义 | ||
type SegmentKeysLock struct { | ||
locks []*sync.RWMutex | ||
size uint32 | ||
} | ||
|
||
// NewSegmentKeysLock 创建 SegmentKeysLock 示例 | ||
func NewSegmentKeysLock(size uint32) *SegmentKeysLock { | ||
locks := make([]*sync.RWMutex, size) | ||
for i := range locks { | ||
locks[i] = &sync.RWMutex{} | ||
} | ||
return &SegmentKeysLock{ | ||
locks: locks, | ||
size: size, | ||
} | ||
} | ||
|
||
// hash 索引锁的hash函数 | ||
func (s *SegmentKeysLock) hash(key string) uint32 { | ||
h := fnv.New32a() | ||
_, _ = h.Write([]byte(key)) | ||
return h.Sum32() | ||
} | ||
|
||
// RLock 读锁加锁 | ||
func (s *SegmentKeysLock) RLock(key string) { | ||
s.getLock(key).RLock() | ||
} | ||
|
||
// TryRLock 试着加读锁,加锁成功会返回 | ||
func (s *SegmentKeysLock) TryRLock(key string) bool { | ||
return s.getLock(key).TryRLock() | ||
} | ||
|
||
// RUnlock 读锁解锁 | ||
func (s *SegmentKeysLock) RUnlock(key string) { | ||
s.getLock(key).RUnlock() | ||
} | ||
|
||
// Lock 写锁加锁 | ||
func (s *SegmentKeysLock) Lock(key string) { | ||
s.getLock(key).Lock() | ||
} | ||
|
||
// TryLock 试着加锁,加锁成功会返回 true | ||
func (s *SegmentKeysLock) TryLock(key string) bool { | ||
return s.getLock(key).TryLock() | ||
} | ||
|
||
// Unlock 写锁解锁 | ||
func (s *SegmentKeysLock) Unlock(key string) { | ||
s.getLock(key).Unlock() | ||
} | ||
|
||
func (s *SegmentKeysLock) getLock(key string) *sync.RWMutex { | ||
hash := s.hash(key) | ||
return s.locks[hash%s.size] | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,67 @@ | ||
// Copyright 2021 ecodeclub | ||
// | ||
// Licensed under the Apache License, Version 2.0 (the "License"); | ||
// you may not use this file except in compliance with the License. | ||
// You may obtain a copy of the License at | ||
// | ||
// http://www.apache.org/licenses/LICENSE-2.0 | ||
// | ||
// Unless required by applicable law or agreed to in writing, software | ||
// distributed under the License is distributed on an "AS IS" BASIS, | ||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
// See the License for the specific language governing permissions and | ||
// limitations under the License. | ||
|
||
package syncx | ||
|
||
import ( | ||
"testing" | ||
|
||
"github.com/stretchr/testify/assert" | ||
) | ||
|
||
// 通过 TryLock 和 TryRLock 来判定加锁问题 | ||
// 也就是只判定我们拿到了正确的锁,但是没有判定并发与互斥 | ||
|
||
// TestNewSegmentKeysLock_Lock 测试 Lock, UnLock 和 TryLock | ||
func TestNewSegmentKeysLock_Lock(t *testing.T) { | ||
l := NewSegmentKeysLock(8) | ||
key1 := "key1" | ||
l.Lock(key1) | ||
// 必然加锁失败 | ||
assert.False(t, l.TryLock(key1)) | ||
// 读锁也失败 | ||
assert.False(t, l.TryRLock(key1)) | ||
key2 := "key2" | ||
// 加锁成功 | ||
assert.True(t, l.TryLock(key2)) | ||
// 解锁不会触发 panic | ||
defer l.Unlock(key2) | ||
|
||
// 释放锁 | ||
l.Unlock(key1) | ||
// 此时应该预期自己可以再次加锁 | ||
assert.True(t, l.TryLock(key1)) | ||
} | ||
|
||
func TestNewSegmentKeysLock_RLock(t *testing.T) { | ||
l := NewSegmentKeysLock(8) | ||
key1, key2 := "key1", "key2" | ||
l.RLock(key1) | ||
// 必然加锁失败 | ||
assert.False(t, l.TryLock(key1)) | ||
// 读锁可以成功 | ||
assert.True(t, l.TryRLock(key1)) | ||
// 加锁成功 | ||
assert.True(t, l.TryRLock(key2)) | ||
// 解锁不会触发 panic | ||
defer l.RUnlock(key2) | ||
|
||
// 释放读锁 | ||
l.RUnlock(key1) | ||
// 此时还有一个读锁没有释放 | ||
assert.False(t, l.TryLock(key1)) | ||
// 再次释放读锁 | ||
l.RUnlock(key1) | ||
assert.True(t, l.TryLock(key1)) | ||
} |
Oops, something went wrong.