Skip to content

Commit

Permalink
添加了中文注释方便初学者学习
Browse files Browse the repository at this point in the history
  • Loading branch information
wangxiao1024 committed Jul 24, 2024
1 parent b9ba5db commit 90f6ddf
Show file tree
Hide file tree
Showing 3 changed files with 51 additions and 28 deletions.
8 changes: 8 additions & 0 deletions datastruct/dict/concurrent.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ type shard struct {
}

// computeCapacity 计算哈希表容量,确保为2的次幂,这有助于更快的计算索引
// 这个函数的目的是确定一个接近于给定参数 param 但不小于它的2的次幂的数。这样做的好处主要有两点:
func computeCapacity(param int) (size int) {
// 以下代码是经典的位操作技巧,用于找到大于等于param的最小2的次幂
if param <= 16 {
Expand Down Expand Up @@ -82,6 +83,9 @@ func (dict *ConcurrentDict) spread(hashCode uint32) uint32 {
panic("dict is nil")
}
tableSize := uint32(len(dict.table))

//因为表的大小是2的次幂,这个按位与操作等同于对表大小取模,但运算速度更快。
//当表大小是2的次幂时,tableSize - 1 的二进制表示中所有低位都是1,这使得按位与操作只保留 hashCode 的最低的几位。
return (tableSize - 1) & hashCode
}

Expand Down Expand Up @@ -459,6 +463,10 @@ func (dict *ConcurrentDict) RWUnLocks(writeKeys []string, readKeys []string) {
}
}
}

// stringsToBytes 将字符串切片转换为字节切片的切片。
// 输入:strSlice - 字符串切片
// 输出:每个字符串转换为字节切片后的切片
func stringsToBytes(strSlice []string) [][]byte {
byteSlice := make([][]byte, len(strSlice))
for i, str := range strSlice {
Expand Down
24 changes: 12 additions & 12 deletions datastruct/dict/dict.go
Original file line number Diff line number Diff line change
@@ -1,20 +1,20 @@
package dict

// Consumer is used to traversal dict, if it returns false the traversal will be break
// Consumer 是一个遍历字典时使用的函数类型,如果返回false,则终止遍历
type Consumer func(key string, val interface{}) bool

// Dict is interface of a key-value data structure
// Dict key-value 数据结构的接口定义
type Dict interface {
Get(key string) (val interface{}, exists bool)
Len() int
Put(key string, val interface{}) (result int)
PutIfAbsent(key string, val interface{}) (result int)
PutIfExists(key string, val interface{}) (result int)
Remove(key string) (val interface{}, result int)
ForEach(consumer Consumer)
Keys() []string
RandomKeys(limit int) []string
Get(key string) (val interface{}, exists bool) // 获取键的值
Len() int // 返回字典的长度
Put(key string, val interface{}) (result int) // 插入键值对
PutIfAbsent(key string, val interface{}) (result int) // 如果键不存在,则插入
PutIfExists(key string, val interface{}) (result int) // 如果键存在,则插入
Remove(key string) (val interface{}, result int) // 移除键
ForEach(consumer Consumer) // 遍历字典
Keys() []string // 返回所有键的列表
RandomKeys(limit int) []string // 随机返回一定数量的键
RandomDistinctKeys(limit int) []string
Clear()
Clear() // 清除字典中的所有元素
DictScan(cursor int, count int, pattern string) ([][]byte, int)
}
47 changes: 31 additions & 16 deletions datastruct/lock/lock_map.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,29 @@ import (
"sync"
)

/*
即使使用了 ConcurrentMap 保证了对单个 key 的并发安全性,但在某些情况下这还不够。
例如,Incr 命令需要完成从读取到修改再到写入的一系列操作,而 MSETNX 命令需要在所有给定键都不存在的情况下才设置值。
这些操作需要更复杂的并发控制,即锁定多个键直到操作完成。
*/

/*
锁定哈希槽而非单个键:通常,每个键都需要独立锁定来确保并发访问的安全性。
但这在键数量很大时会造成大量内存的使用。通过锁定哈希槽,可以大大减少所需的锁的数量,因为多个键会映射到同一个哈希槽。
避免内存泄漏:如果为每个键分配一个锁,随着键的增加和删除,锁的数量也会不断增加,可能会造成内存泄漏。
锁定哈希槽可以固定锁的数量,即使在键的数量动态变化时也不会增加额外的内存负担。
*/
// 使用固定素数,用于FNV哈希函数
const (
prime32 = uint32(16777619)
)

// Locks provides rw locks for key
// Locks结构体包含了一个用于读写锁定的锁表
type Locks struct {
table []*sync.RWMutex
}

// Make creates a new lock map
// Make 初始化并返回一个具有指定数量哈希槽的Locks实例
func Make(tableSize int) *Locks {
table := make([]*sync.RWMutex, tableSize)
for i := 0; i < tableSize; i++ {
Expand All @@ -25,6 +38,7 @@ func Make(tableSize int) *Locks {
}
}

// fnv32 实现了FNV哈希算法,用于生成键的哈希值
func fnv32(key string) uint32 {
hash := uint32(2166136261)
for i := 0; i < len(key); i++ {
Expand All @@ -34,6 +48,7 @@ func fnv32(key string) uint32 {
return hash
}

// spread 计算给定哈希码的哈希槽索引
func (locks *Locks) spread(hashCode uint32) uint32 {
if locks == nil {
panic("dict is nil")
Expand All @@ -42,36 +57,37 @@ func (locks *Locks) spread(hashCode uint32) uint32 {
return (tableSize - 1) & hashCode
}

// Lock obtains exclusive lock for writing
// Lock 为给定键获取独占写锁
func (locks *Locks) Lock(key string) {
index := locks.spread(fnv32(key))
mu := locks.table[index]
mu.Lock()
}

// RLock obtains shared lock for reading
// RLock 为给定键获取共享读锁
func (locks *Locks) RLock(key string) {
index := locks.spread(fnv32(key))
mu := locks.table[index]
mu.RLock()
}

// UnLock release exclusive lock
// UnLock 释放给定键的独占写锁
func (locks *Locks) UnLock(key string) {
index := locks.spread(fnv32(key))
mu := locks.table[index]
mu.Unlock()
}

// RUnLock release shared lock
// RUnLock 释放给定键的共享读锁
func (locks *Locks) RUnLock(key string) {
index := locks.spread(fnv32(key))
mu := locks.table[index]
mu.RUnlock()
}

// toLockIndices 计算一组键的哈希槽索引,并进行排序(可选逆序)
func (locks *Locks) toLockIndices(keys []string, reverse bool) []uint32 {
indexMap := make(map[uint32]struct{})
indexMap := make(map[uint32]struct{}) // 使用集合去重
for _, key := range keys {
index := locks.spread(fnv32(key))
indexMap[index] = struct{}{}
Expand All @@ -89,18 +105,17 @@ func (locks *Locks) toLockIndices(keys []string, reverse bool) []uint32 {
return indices
}

// Locks obtains multiple exclusive locks for writing
// invoking Lock in loop may cause deadlock, please use Locks
// Locks 获取多个键的独占写锁,避免死锁
func (locks *Locks) Locks(keys ...string) {
indices := locks.toLockIndices(keys, false)
for _, index := range indices {
mu := locks.table[index]
mu.Lock()
mu.Lock() // 锁定每个索引对应的哈希槽
}
}

// RLocks obtains multiple shared locks for reading
// invoking RLock in loop may cause deadlock, please use RLocks
// RLocks 获取多个键的共享读锁,避免死锁

func (locks *Locks) RLocks(keys ...string) {
indices := locks.toLockIndices(keys, false)
for _, index := range indices {
Expand All @@ -109,7 +124,7 @@ func (locks *Locks) RLocks(keys ...string) {
}
}

// UnLocks releases multiple exclusive locks
// UnLocks 释放多个键的独占写锁
func (locks *Locks) UnLocks(keys ...string) {
indices := locks.toLockIndices(keys, true)
for _, index := range indices {
Expand All @@ -118,7 +133,7 @@ func (locks *Locks) UnLocks(keys ...string) {
}
}

// RUnLocks releases multiple shared locks
// RUnLocks 释放多个键的共享读锁
func (locks *Locks) RUnLocks(keys ...string) {
indices := locks.toLockIndices(keys, true)
for _, index := range indices {
Expand All @@ -127,7 +142,7 @@ func (locks *Locks) RUnLocks(keys ...string) {
}
}

// RWLocks locks write keys and read keys together. allow duplicate keys
// RWLocks 同时获取写锁和读锁,允许键重复
func (locks *Locks) RWLocks(writeKeys []string, readKeys []string) {
keys := append(writeKeys, readKeys...)
indices := locks.toLockIndices(keys, false)
Expand All @@ -147,7 +162,7 @@ func (locks *Locks) RWLocks(writeKeys []string, readKeys []string) {
}
}

// RWUnLocks unlocks write keys and read keys together. allow duplicate keys
// RWUnLocks 同时释放写锁和读锁,允许键重复
func (locks *Locks) RWUnLocks(writeKeys []string, readKeys []string) {
keys := append(writeKeys, readKeys...)
indices := locks.toLockIndices(keys, true)
Expand Down

0 comments on commit 90f6ddf

Please sign in to comment.