refactor: 移除分段锁map实现及 hash.Map、hash.ReadonlyMap 接口,移除 asynchronous 包,同步包更名为 concurrent
This commit is contained in:
parent
2cbffbf967
commit
d0d2087fee
|
@ -3,7 +3,7 @@ package components
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"github.com/kercylan98/minotaur/component"
|
"github.com/kercylan98/minotaur/component"
|
||||||
"github.com/kercylan98/minotaur/utils/synchronization"
|
"github.com/kercylan98/minotaur/utils/concurrent"
|
||||||
"github.com/kercylan98/minotaur/utils/timer"
|
"github.com/kercylan98/minotaur/utils/timer"
|
||||||
"sync"
|
"sync"
|
||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
|
@ -13,8 +13,8 @@ import (
|
||||||
// NewLockstep 创建一个锁步(帧)同步默认实现的组件(Lockstep)进行返回
|
// NewLockstep 创建一个锁步(帧)同步默认实现的组件(Lockstep)进行返回
|
||||||
func NewLockstep[ClientID comparable, Command any](options ...LockstepOption[ClientID, Command]) *Lockstep[ClientID, Command] {
|
func NewLockstep[ClientID comparable, Command any](options ...LockstepOption[ClientID, Command]) *Lockstep[ClientID, Command] {
|
||||||
lockstep := &Lockstep[ClientID, Command]{
|
lockstep := &Lockstep[ClientID, Command]{
|
||||||
clients: synchronization.NewMap[ClientID, component.LockstepClient[ClientID]](),
|
clients: concurrent.NewBalanceMap[ClientID, component.LockstepClient[ClientID]](),
|
||||||
frames: synchronization.NewMap[int, []Command](),
|
frames: concurrent.NewBalanceMap[int, []Command](),
|
||||||
ticker: timer.GetTicker(10),
|
ticker: timer.GetTicker(10),
|
||||||
frameRate: 15,
|
frameRate: 15,
|
||||||
serialization: func(frame int, commands []Command) []byte {
|
serialization: func(frame int, commands []Command) []byte {
|
||||||
|
@ -25,7 +25,7 @@ func NewLockstep[ClientID comparable, Command any](options ...LockstepOption[Cli
|
||||||
data, _ := json.Marshal(frameStruct)
|
data, _ := json.Marshal(frameStruct)
|
||||||
return data
|
return data
|
||||||
},
|
},
|
||||||
clientCurrentFrame: synchronization.NewMap[ClientID, int](),
|
clientCurrentFrame: concurrent.NewBalanceMap[ClientID, int](),
|
||||||
}
|
}
|
||||||
for _, option := range options {
|
for _, option := range options {
|
||||||
option(lockstep)
|
option(lockstep)
|
||||||
|
@ -40,12 +40,12 @@ func NewLockstep[ClientID comparable, Command any](options ...LockstepOption[Cli
|
||||||
// - 从特定帧开始追帧
|
// - 从特定帧开始追帧
|
||||||
// - 兼容各种基于TCP/UDP/Unix的网络类型,可通过客户端实现其他网络类型同步
|
// - 兼容各种基于TCP/UDP/Unix的网络类型,可通过客户端实现其他网络类型同步
|
||||||
type Lockstep[ClientID comparable, Command any] struct {
|
type Lockstep[ClientID comparable, Command any] struct {
|
||||||
clients *synchronization.Map[ClientID, component.LockstepClient[ClientID]] // 接受广播的客户端
|
clients *concurrent.BalanceMap[ClientID, component.LockstepClient[ClientID]] // 接受广播的客户端
|
||||||
frames *synchronization.Map[int, []Command] // 所有帧指令
|
frames *concurrent.BalanceMap[int, []Command] // 所有帧指令
|
||||||
ticker *timer.Ticker // 定时器
|
ticker *timer.Ticker // 定时器
|
||||||
frameMutex sync.Mutex // 帧锁
|
frameMutex sync.Mutex // 帧锁
|
||||||
currentFrame int // 当前帧
|
currentFrame int // 当前帧
|
||||||
clientCurrentFrame *synchronization.Map[ClientID, int] // 客户端当前帧数
|
clientCurrentFrame *concurrent.BalanceMap[ClientID, int] // 客户端当前帧数
|
||||||
running atomic.Bool
|
running atomic.Bool
|
||||||
|
|
||||||
frameRate int // 帧率(每秒N帧)
|
frameRate int // 帧率(每秒N帧)
|
||||||
|
@ -123,8 +123,8 @@ func (slf *Lockstep[ClientID, Command]) StopBroadcast() {
|
||||||
|
|
||||||
// AddCommand 添加命令到当前帧
|
// AddCommand 添加命令到当前帧
|
||||||
func (slf *Lockstep[ClientID, Command]) AddCommand(command Command) {
|
func (slf *Lockstep[ClientID, Command]) AddCommand(command Command) {
|
||||||
slf.frames.AtomGetSet(slf.currentFrame, func(value []Command, exist bool) (newValue []Command, isSet bool) {
|
slf.frames.Atom(func(m map[int][]Command) {
|
||||||
return append(value, command), true
|
m[slf.currentFrame] = append(m[slf.currentFrame], command)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,18 +2,18 @@ package builtin
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/kercylan98/minotaur/game"
|
"github.com/kercylan98/minotaur/game"
|
||||||
|
"github.com/kercylan98/minotaur/utils/concurrent"
|
||||||
"github.com/kercylan98/minotaur/utils/huge"
|
"github.com/kercylan98/minotaur/utils/huge"
|
||||||
"github.com/kercylan98/minotaur/utils/synchronization"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func NewAttrs() *Attrs {
|
func NewAttrs() *Attrs {
|
||||||
return &Attrs{
|
return &Attrs{
|
||||||
attrs: synchronization.NewMap[int, any](),
|
attrs: concurrent.NewBalanceMap[int, any](),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type Attrs struct {
|
type Attrs struct {
|
||||||
attrs *synchronization.Map[int, any]
|
attrs *concurrent.BalanceMap[int, any]
|
||||||
|
|
||||||
attrChangeEventHandles []game.AttrChangeEventHandle
|
attrChangeEventHandles []game.AttrChangeEventHandle
|
||||||
attrIdChangeEventHandles map[int][]game.AttrChangeEventHandle
|
attrIdChangeEventHandles map[int][]game.AttrChangeEventHandle
|
||||||
|
|
|
@ -3,15 +3,15 @@ package builtin
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"github.com/kercylan98/minotaur/game"
|
"github.com/kercylan98/minotaur/game"
|
||||||
|
"github.com/kercylan98/minotaur/utils/concurrent"
|
||||||
"github.com/kercylan98/minotaur/utils/generic"
|
"github.com/kercylan98/minotaur/utils/generic"
|
||||||
"github.com/kercylan98/minotaur/utils/synchronization"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// NewRankingList 创建一个排名从0开始的排行榜
|
// NewRankingList 创建一个排名从0开始的排行榜
|
||||||
func NewRankingList[CompetitorID comparable, Score generic.Ordered](options ...RankingListOption[CompetitorID, Score]) *RankingList[CompetitorID, Score] {
|
func NewRankingList[CompetitorID comparable, Score generic.Ordered](options ...RankingListOption[CompetitorID, Score]) *RankingList[CompetitorID, Score] {
|
||||||
rankingList := &RankingList[CompetitorID, Score]{
|
rankingList := &RankingList[CompetitorID, Score]{
|
||||||
rankCount: 100,
|
rankCount: 100,
|
||||||
competitors: synchronization.NewMap[CompetitorID, Score](),
|
competitors: concurrent.NewBalanceMap[CompetitorID, Score](),
|
||||||
}
|
}
|
||||||
for _, option := range options {
|
for _, option := range options {
|
||||||
option(rankingList)
|
option(rankingList)
|
||||||
|
@ -22,7 +22,7 @@ func NewRankingList[CompetitorID comparable, Score generic.Ordered](options ...R
|
||||||
type RankingList[CompetitorID comparable, Score generic.Ordered] struct {
|
type RankingList[CompetitorID comparable, Score generic.Ordered] struct {
|
||||||
asc bool
|
asc bool
|
||||||
rankCount int
|
rankCount int
|
||||||
competitors *synchronization.Map[CompetitorID, Score]
|
competitors *concurrent.BalanceMap[CompetitorID, Score]
|
||||||
scores []*scoreItem[CompetitorID, Score] // CompetitorID, Score
|
scores []*scoreItem[CompetitorID, Score] // CompetitorID, Score
|
||||||
|
|
||||||
rankChangeEventHandles []game.RankChangeEventHandle[CompetitorID, Score]
|
rankChangeEventHandles []game.RankChangeEventHandle[CompetitorID, Score]
|
||||||
|
@ -244,11 +244,11 @@ func (slf *RankingList[CompetitorID, Score]) competitor(competitorId CompetitorI
|
||||||
|
|
||||||
func (slf *RankingList[CompetitorID, Score]) UnmarshalJSON(bytes []byte) error {
|
func (slf *RankingList[CompetitorID, Score]) UnmarshalJSON(bytes []byte) error {
|
||||||
var t struct {
|
var t struct {
|
||||||
Competitors *synchronization.Map[CompetitorID, Score] `json:"competitors,omitempty"`
|
Competitors *concurrent.BalanceMap[CompetitorID, Score] `json:"competitors,omitempty"`
|
||||||
Scores []*scoreItem[CompetitorID, Score] `json:"scores,omitempty"`
|
Scores []*scoreItem[CompetitorID, Score] `json:"scores,omitempty"`
|
||||||
Asc bool `json:"asc,omitempty"`
|
Asc bool `json:"asc,omitempty"`
|
||||||
}
|
}
|
||||||
t.Competitors = synchronization.NewMap[CompetitorID, Score]()
|
t.Competitors = concurrent.NewBalanceMap[CompetitorID, Score]()
|
||||||
if err := json.Unmarshal(bytes, &t); err != nil {
|
if err := json.Unmarshal(bytes, &t); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -260,9 +260,9 @@ func (slf *RankingList[CompetitorID, Score]) UnmarshalJSON(bytes []byte) error {
|
||||||
|
|
||||||
func (slf *RankingList[CompetitorID, Score]) MarshalJSON() ([]byte, error) {
|
func (slf *RankingList[CompetitorID, Score]) MarshalJSON() ([]byte, error) {
|
||||||
var t struct {
|
var t struct {
|
||||||
Competitors *synchronization.Map[CompetitorID, Score] `json:"competitors,omitempty"`
|
Competitors *concurrent.BalanceMap[CompetitorID, Score] `json:"competitors,omitempty"`
|
||||||
Scores []*scoreItem[CompetitorID, Score] `json:"scores,omitempty"`
|
Scores []*scoreItem[CompetitorID, Score] `json:"scores,omitempty"`
|
||||||
Asc bool `json:"asc,omitempty"`
|
Asc bool `json:"asc,omitempty"`
|
||||||
}
|
}
|
||||||
t.Competitors = slf.competitors
|
t.Competitors = slf.competitors
|
||||||
t.Scores = slf.scores
|
t.Scores = slf.scores
|
||||||
|
|
|
@ -2,8 +2,7 @@ package builtin
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/kercylan98/minotaur/game"
|
"github.com/kercylan98/minotaur/game"
|
||||||
"github.com/kercylan98/minotaur/utils/asynchronous"
|
"github.com/kercylan98/minotaur/utils/concurrent"
|
||||||
"github.com/kercylan98/minotaur/utils/hash"
|
|
||||||
"github.com/kercylan98/minotaur/utils/log"
|
"github.com/kercylan98/minotaur/utils/log"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -11,7 +10,7 @@ import (
|
||||||
func NewRoom[PlayerID comparable, Player game.Player[PlayerID]](guid int64, options ...RoomOption[PlayerID, Player]) *Room[PlayerID, Player] {
|
func NewRoom[PlayerID comparable, Player game.Player[PlayerID]](guid int64, options ...RoomOption[PlayerID, Player]) *Room[PlayerID, Player] {
|
||||||
room := &Room[PlayerID, Player]{
|
room := &Room[PlayerID, Player]{
|
||||||
guid: guid,
|
guid: guid,
|
||||||
players: asynchronous.NewMap[PlayerID, Player](),
|
players: concurrent.NewBalanceMap[PlayerID, Player](),
|
||||||
}
|
}
|
||||||
for _, option := range options {
|
for _, option := range options {
|
||||||
option(room)
|
option(room)
|
||||||
|
@ -27,7 +26,7 @@ type Room[PlayerID comparable, Player game.Player[PlayerID]] struct {
|
||||||
owner PlayerID
|
owner PlayerID
|
||||||
noMaster bool
|
noMaster bool
|
||||||
playerLimit int
|
playerLimit int
|
||||||
players hash.Map[PlayerID, Player]
|
players *concurrent.BalanceMap[PlayerID, Player]
|
||||||
kickCheckHandle func(room *Room[PlayerID, Player], id, target PlayerID) error
|
kickCheckHandle func(room *Room[PlayerID, Player], id, target PlayerID) error
|
||||||
|
|
||||||
playerJoinRoomEventHandles []game.PlayerJoinRoomEventHandle[PlayerID, Player]
|
playerJoinRoomEventHandles []game.PlayerJoinRoomEventHandle[PlayerID, Player]
|
||||||
|
@ -51,8 +50,8 @@ func (slf *Room[PlayerID, Player]) GetPlayer(id PlayerID) Player {
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetPlayers 获取所有玩家
|
// GetPlayers 获取所有玩家
|
||||||
func (slf *Room[PlayerID, Player]) GetPlayers() hash.MapReadonly[PlayerID, Player] {
|
func (slf *Room[PlayerID, Player]) GetPlayers() map[PlayerID]Player {
|
||||||
return slf.players.(hash.MapReadonly[PlayerID, Player])
|
return slf.players.Map()
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetPlayerCount 获取玩家数量
|
// GetPlayerCount 获取玩家数量
|
||||||
|
|
|
@ -2,20 +2,20 @@ package builtin
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/kercylan98/minotaur/game"
|
"github.com/kercylan98/minotaur/game"
|
||||||
"github.com/kercylan98/minotaur/utils/synchronization"
|
"github.com/kercylan98/minotaur/utils/concurrent"
|
||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
)
|
)
|
||||||
|
|
||||||
func NewRoomManager[PlayerID comparable, Room game.Room[PlayerID, game.Player[PlayerID]]]() *RoomManager[PlayerID, Room] {
|
func NewRoomManager[PlayerID comparable, Room game.Room[PlayerID, game.Player[PlayerID]]]() *RoomManager[PlayerID, Room] {
|
||||||
return &RoomManager[PlayerID, Room]{
|
return &RoomManager[PlayerID, Room]{
|
||||||
rooms: synchronization.NewMap[int64, Room](),
|
rooms: concurrent.NewBalanceMap[int64, Room](),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// RoomManager 房间管理器
|
// RoomManager 房间管理器
|
||||||
type RoomManager[PlayerID comparable, Room game.Room[PlayerID, game.Player[PlayerID]]] struct {
|
type RoomManager[PlayerID comparable, Room game.Room[PlayerID, game.Player[PlayerID]]] struct {
|
||||||
guid atomic.Int64
|
guid atomic.Int64
|
||||||
rooms *synchronization.Map[int64, Room]
|
rooms *concurrent.BalanceMap[int64, Room]
|
||||||
}
|
}
|
||||||
|
|
||||||
// GenGuid 生成一个新的房间guid
|
// GenGuid 生成一个新的房间guid
|
||||||
|
|
|
@ -2,7 +2,7 @@ package builtin
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/kercylan98/minotaur/game"
|
"github.com/kercylan98/minotaur/game"
|
||||||
"github.com/kercylan98/minotaur/utils/synchronization"
|
"github.com/kercylan98/minotaur/utils/concurrent"
|
||||||
)
|
)
|
||||||
|
|
||||||
// RoomOption 房间构建可选项
|
// RoomOption 房间构建可选项
|
||||||
|
@ -11,7 +11,7 @@ type RoomOption[PlayerID comparable, Player game.Player[PlayerID]] func(room *Ro
|
||||||
// WithRoomSync 通过线程安全的方式创建房间
|
// WithRoomSync 通过线程安全的方式创建房间
|
||||||
func WithRoomSync[PlayerID comparable, Player game.Player[PlayerID]]() RoomOption[PlayerID, Player] {
|
func WithRoomSync[PlayerID comparable, Player game.Player[PlayerID]]() RoomOption[PlayerID, Player] {
|
||||||
return func(room *Room[PlayerID, Player]) {
|
return func(room *Room[PlayerID, Player]) {
|
||||||
room.players = synchronization.NewMap[PlayerID, Player]()
|
room.players = concurrent.NewBalanceMap[PlayerID, Player]()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,7 @@ package builtin
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/kercylan98/minotaur/game"
|
"github.com/kercylan98/minotaur/game"
|
||||||
"github.com/kercylan98/minotaur/utils/asynchronous"
|
"github.com/kercylan98/minotaur/utils/concurrent"
|
||||||
"github.com/kercylan98/minotaur/utils/hash"
|
"github.com/kercylan98/minotaur/utils/hash"
|
||||||
"github.com/kercylan98/minotaur/utils/slice"
|
"github.com/kercylan98/minotaur/utils/slice"
|
||||||
"sync"
|
"sync"
|
||||||
|
@ -12,7 +12,7 @@ import (
|
||||||
func NewRoomSeat[PlayerID comparable, Player game.Player[PlayerID]](room game.Room[PlayerID, Player], options ...RoomSeatOption[PlayerID, Player]) *RoomSeat[PlayerID, Player] {
|
func NewRoomSeat[PlayerID comparable, Player game.Player[PlayerID]](room game.Room[PlayerID, Player], options ...RoomSeatOption[PlayerID, Player]) *RoomSeat[PlayerID, Player] {
|
||||||
roomSeat := &RoomSeat[PlayerID, Player]{
|
roomSeat := &RoomSeat[PlayerID, Player]{
|
||||||
Room: room,
|
Room: room,
|
||||||
seatPS: asynchronous.NewMap[PlayerID, int](),
|
seatPS: concurrent.NewBalanceMap[PlayerID, int](),
|
||||||
}
|
}
|
||||||
for _, option := range options {
|
for _, option := range options {
|
||||||
option(roomSeat)
|
option(roomSeat)
|
||||||
|
@ -26,7 +26,7 @@ type RoomSeat[PlayerID comparable, Player game.Player[PlayerID]] struct {
|
||||||
game.Room[PlayerID, Player]
|
game.Room[PlayerID, Player]
|
||||||
mutex sync.RWMutex
|
mutex sync.RWMutex
|
||||||
vacancy []int
|
vacancy []int
|
||||||
seatPS hash.Map[PlayerID, int]
|
seatPS *concurrent.BalanceMap[PlayerID, int]
|
||||||
seatSP []*PlayerID
|
seatSP []*PlayerID
|
||||||
duplicateLock bool
|
duplicateLock bool
|
||||||
fillIn bool
|
fillIn bool
|
||||||
|
@ -240,6 +240,41 @@ func (slf *RoomSeat[PlayerID, Player]) GetNextSeatVacancy(seat int) int {
|
||||||
return seat
|
return seat
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetPrevSeat 获取特定座位号上一个未缺席的座位号
|
||||||
|
func (slf *RoomSeat[PlayerID, Player]) GetPrevSeat(seat int) int {
|
||||||
|
l := len(slf.seatSP)
|
||||||
|
if l == 0 || seat >= l || seat < 0 {
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
var target = seat
|
||||||
|
for {
|
||||||
|
target--
|
||||||
|
if target < 0 {
|
||||||
|
target = l - 1
|
||||||
|
}
|
||||||
|
if target == seat {
|
||||||
|
return seat
|
||||||
|
}
|
||||||
|
if slf.seatSP[target] != nil {
|
||||||
|
return target
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetPrevSeatVacancy 获取特定座位号上一个座位号
|
||||||
|
// - 缺席将不会被忽略
|
||||||
|
func (slf *RoomSeat[PlayerID, Player]) GetPrevSeatVacancy(seat int) int {
|
||||||
|
l := len(slf.seatSP)
|
||||||
|
if l == 0 || seat >= l || seat < 0 {
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
seat--
|
||||||
|
if seat < 0 {
|
||||||
|
seat = l - 1
|
||||||
|
}
|
||||||
|
return seat
|
||||||
|
}
|
||||||
|
|
||||||
func (slf *RoomSeat[PlayerID, Player]) onJoinRoom(room game.Room[PlayerID, Player], player Player) {
|
func (slf *RoomSeat[PlayerID, Player]) onJoinRoom(room game.Room[PlayerID, Player], player Player) {
|
||||||
slf.AddSeat(player.GetID())
|
slf.AddSeat(player.GetID())
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,9 +2,8 @@ package builtin
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/kercylan98/minotaur/game"
|
"github.com/kercylan98/minotaur/game"
|
||||||
"github.com/kercylan98/minotaur/utils/hash"
|
"github.com/kercylan98/minotaur/utils/concurrent"
|
||||||
"github.com/kercylan98/minotaur/utils/log"
|
"github.com/kercylan98/minotaur/utils/log"
|
||||||
"github.com/kercylan98/minotaur/utils/synchronization"
|
|
||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -12,10 +11,10 @@ import (
|
||||||
func NewWorld[PlayerID comparable, Player game.Player[PlayerID]](guid int64, options ...WorldOption[PlayerID, Player]) *World[PlayerID, Player] {
|
func NewWorld[PlayerID comparable, Player game.Player[PlayerID]](guid int64, options ...WorldOption[PlayerID, Player]) *World[PlayerID, Player] {
|
||||||
world := &World[PlayerID, Player]{
|
world := &World[PlayerID, Player]{
|
||||||
guid: guid,
|
guid: guid,
|
||||||
players: synchronization.NewMap[PlayerID, Player](),
|
players: concurrent.NewBalanceMap[PlayerID, Player](),
|
||||||
playerActors: synchronization.NewMap[PlayerID, hash.Map[int64, game.Actor]](),
|
playerActors: concurrent.NewBalanceMap[PlayerID, *concurrent.BalanceMap[int64, game.Actor]](),
|
||||||
owners: synchronization.NewMap[int64, PlayerID](),
|
owners: concurrent.NewBalanceMap[int64, PlayerID](),
|
||||||
actors: synchronization.NewMap[int64, game.Actor](),
|
actors: concurrent.NewBalanceMap[int64, game.Actor](),
|
||||||
}
|
}
|
||||||
for _, option := range options {
|
for _, option := range options {
|
||||||
option(world)
|
option(world)
|
||||||
|
@ -28,10 +27,10 @@ type World[PlayerID comparable, Player game.Player[PlayerID]] struct {
|
||||||
guid int64
|
guid int64
|
||||||
actorGuid atomic.Int64
|
actorGuid atomic.Int64
|
||||||
playerLimit int
|
playerLimit int
|
||||||
players hash.Map[PlayerID, Player]
|
players *concurrent.BalanceMap[PlayerID, Player]
|
||||||
playerActors hash.Map[PlayerID, hash.Map[int64, game.Actor]]
|
playerActors *concurrent.BalanceMap[PlayerID, *concurrent.BalanceMap[int64, game.Actor]]
|
||||||
owners hash.Map[int64, PlayerID]
|
owners *concurrent.BalanceMap[int64, PlayerID]
|
||||||
actors hash.Map[int64, game.Actor]
|
actors *concurrent.BalanceMap[int64, game.Actor]
|
||||||
|
|
||||||
playerJoinWorldEventHandles []game.PlayerJoinWorldEventHandle[PlayerID, Player]
|
playerJoinWorldEventHandles []game.PlayerJoinWorldEventHandle[PlayerID, Player]
|
||||||
playerLeaveWorldEventHandles []game.PlayerLeaveWorldEventHandle[PlayerID, Player]
|
playerLeaveWorldEventHandles []game.PlayerLeaveWorldEventHandle[PlayerID, Player]
|
||||||
|
@ -56,16 +55,16 @@ func (slf *World[PlayerID, Player]) GetPlayer(id PlayerID) Player {
|
||||||
return slf.players.Get(id)
|
return slf.players.Get(id)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (slf *World[PlayerID, Player]) GetPlayers() hash.MapReadonly[PlayerID, Player] {
|
func (slf *World[PlayerID, Player]) GetPlayers() map[PlayerID]Player {
|
||||||
return slf.players.(hash.MapReadonly[PlayerID, Player])
|
return slf.players.Map()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (slf *World[PlayerID, Player]) GetActor(guid int64) game.Actor {
|
func (slf *World[PlayerID, Player]) GetActor(guid int64) game.Actor {
|
||||||
return slf.actors.Get(guid)
|
return slf.actors.Get(guid)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (slf *World[PlayerID, Player]) GetActors() hash.MapReadonly[int64, game.Actor] {
|
func (slf *World[PlayerID, Player]) GetActors() map[int64]game.Actor {
|
||||||
return slf.actors.(hash.MapReadonly[int64, game.Actor])
|
return slf.actors.Map()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (slf *World[PlayerID, Player]) GetPlayerActor(id PlayerID, guid int64) game.Actor {
|
func (slf *World[PlayerID, Player]) GetPlayerActor(id PlayerID, guid int64) game.Actor {
|
||||||
|
@ -75,8 +74,8 @@ func (slf *World[PlayerID, Player]) GetPlayerActor(id PlayerID, guid int64) game
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (slf *World[PlayerID, Player]) GetPlayerActors(id PlayerID) hash.MapReadonly[int64, game.Actor] {
|
func (slf *World[PlayerID, Player]) GetPlayerActors(id PlayerID) map[int64]game.Actor {
|
||||||
return slf.playerActors.Get(id).(hash.MapReadonly[int64, game.Actor])
|
return slf.playerActors.Get(id).Map()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (slf *World[PlayerID, Player]) IsExistPlayer(id PlayerID) bool {
|
func (slf *World[PlayerID, Player]) IsExistPlayer(id PlayerID) bool {
|
||||||
|
@ -105,7 +104,7 @@ func (slf *World[PlayerID, Player]) Join(player Player) error {
|
||||||
log.Debug("World.Join", log.Int64("guid", slf.GetGuid()), log.Any("player", player.GetID()))
|
log.Debug("World.Join", log.Int64("guid", slf.GetGuid()), log.Any("player", player.GetID()))
|
||||||
slf.players.Set(player.GetID(), player)
|
slf.players.Set(player.GetID(), player)
|
||||||
if actors := slf.playerActors.Get(player.GetID()); actors == nil {
|
if actors := slf.playerActors.Get(player.GetID()); actors == nil {
|
||||||
actors = synchronization.NewMap[int64, game.Actor]()
|
actors = concurrent.NewBalanceMap[int64, game.Actor]()
|
||||||
slf.playerActors.Set(player.GetID(), actors)
|
slf.playerActors.Set(player.GetID(), actors)
|
||||||
}
|
}
|
||||||
slf.OnPlayerJoinWorldEvent(player)
|
slf.OnPlayerJoinWorldEvent(player)
|
||||||
|
@ -119,9 +118,10 @@ func (slf *World[PlayerID, Player]) Leave(id PlayerID) {
|
||||||
}
|
}
|
||||||
log.Debug("World.Leave", log.Int64("guid", slf.GetGuid()), log.Any("player", player.GetID()))
|
log.Debug("World.Leave", log.Int64("guid", slf.GetGuid()), log.Any("player", player.GetID()))
|
||||||
slf.OnPlayerLeaveWorldEvent(player)
|
slf.OnPlayerLeaveWorldEvent(player)
|
||||||
slf.playerActors.Get(player.GetID()).Range(func(guid int64, actor game.Actor) {
|
slf.playerActors.Get(player.GetID()).Range(func(guid int64, actor game.Actor) bool {
|
||||||
slf.OnActorAnnihilationEvent(actor)
|
slf.OnActorAnnihilationEvent(actor)
|
||||||
slf.owners.Delete(guid)
|
slf.owners.Delete(guid)
|
||||||
|
return false
|
||||||
})
|
})
|
||||||
slf.playerActors.Delete(player.GetID())
|
slf.playerActors.Delete(player.GetID())
|
||||||
slf.players.Delete(player.GetID())
|
slf.players.Delete(player.GetID())
|
||||||
|
@ -171,8 +171,9 @@ func (slf *World[PlayerID, Player]) RemoveActorOwner(guid int64) {
|
||||||
func (slf *World[PlayerID, Player]) Reset() {
|
func (slf *World[PlayerID, Player]) Reset() {
|
||||||
log.Debug("World", log.Int64("Reset", slf.guid))
|
log.Debug("World", log.Int64("Reset", slf.guid))
|
||||||
slf.players.Clear()
|
slf.players.Clear()
|
||||||
slf.playerActors.Range(func(id PlayerID, actors hash.Map[int64, game.Actor]) {
|
slf.playerActors.Range(func(id PlayerID, actors *concurrent.BalanceMap[int64, game.Actor]) bool {
|
||||||
actors.Clear()
|
actors.Clear()
|
||||||
|
return false
|
||||||
})
|
})
|
||||||
slf.playerActors.Clear()
|
slf.playerActors.Clear()
|
||||||
slf.owners.Clear()
|
slf.owners.Clear()
|
||||||
|
|
|
@ -68,3 +68,23 @@ func GetCardsColor(cards ...Card) []Color {
|
||||||
}
|
}
|
||||||
return colors
|
return colors
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// IsContain 一组扑克牌是否包含某张牌
|
||||||
|
func IsContain(cards []Card, card Card) bool {
|
||||||
|
for _, c := range cards {
|
||||||
|
if c.Equal(card) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsContainAll 一组扑克牌是否包含另一组扑克牌
|
||||||
|
func IsContainAll(cards []Card, cards2 []Card) bool {
|
||||||
|
for _, card := range cards2 {
|
||||||
|
if !IsContain(cards, card) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
|
@ -1,9 +1,5 @@
|
||||||
package game
|
package game
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/kercylan98/minotaur/utils/hash"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Room 房间类似于简版的游戏世界(World),不过没有游戏实体
|
// Room 房间类似于简版的游戏世界(World),不过没有游戏实体
|
||||||
type Room[PlayerID comparable, P Player[PlayerID]] interface {
|
type Room[PlayerID comparable, P Player[PlayerID]] interface {
|
||||||
// GetGuid 获取房间的唯一标识符
|
// GetGuid 获取房间的唯一标识符
|
||||||
|
@ -13,7 +9,7 @@ type Room[PlayerID comparable, P Player[PlayerID]] interface {
|
||||||
// GetPlayer 根据玩家id获取玩家
|
// GetPlayer 根据玩家id获取玩家
|
||||||
GetPlayer(id PlayerID) P
|
GetPlayer(id PlayerID) P
|
||||||
// GetPlayers 获取房间中的所有玩家
|
// GetPlayers 获取房间中的所有玩家
|
||||||
GetPlayers() hash.MapReadonly[PlayerID, P]
|
GetPlayers() map[PlayerID]P
|
||||||
// GetPlayerCount 获取玩家数量
|
// GetPlayerCount 获取玩家数量
|
||||||
GetPlayerCount() int
|
GetPlayerCount() int
|
||||||
// IsExistPlayer 检查房间中是否存在特定玩家
|
// IsExistPlayer 检查房间中是否存在特定玩家
|
||||||
|
|
|
@ -36,4 +36,12 @@ type RoomSeat[PlayerID comparable, P Player[PlayerID]] interface {
|
||||||
// - 超出范围将返回-1
|
// - 超出范围将返回-1
|
||||||
// - 当没有下一个座位号时将始终返回本身
|
// - 当没有下一个座位号时将始终返回本身
|
||||||
GetNextSeatVacancy(seat int) int
|
GetNextSeatVacancy(seat int) int
|
||||||
|
// GetPrevSeat 获取上一个座位号,空缺的位置将会被跳过
|
||||||
|
// - 超出范围将返回-1
|
||||||
|
// - 当没有上一个座位号时将始终返回本身
|
||||||
|
GetPrevSeat(seat int) int
|
||||||
|
// GetPrevSeatVacancy 获取上一个座位号,空缺的位置将被保留
|
||||||
|
// - 超出范围将返回-1
|
||||||
|
// - 当没有上一个座位号时将始终返回本身
|
||||||
|
GetPrevSeatVacancy(seat int) int
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,5 @@
|
||||||
package game
|
package game
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/kercylan98/minotaur/utils/hash"
|
|
||||||
)
|
|
||||||
|
|
||||||
// World 游戏世界接口定义
|
// World 游戏世界接口定义
|
||||||
type World[PlayerID comparable, P Player[PlayerID]] interface {
|
type World[PlayerID comparable, P Player[PlayerID]] interface {
|
||||||
// GetGuid 获取世界的唯一标识符
|
// GetGuid 获取世界的唯一标识符
|
||||||
|
@ -13,15 +9,15 @@ type World[PlayerID comparable, P Player[PlayerID]] interface {
|
||||||
// GetPlayer 根据玩家id获取玩家
|
// GetPlayer 根据玩家id获取玩家
|
||||||
GetPlayer(id PlayerID) P
|
GetPlayer(id PlayerID) P
|
||||||
// GetPlayers 获取世界中的所有玩家
|
// GetPlayers 获取世界中的所有玩家
|
||||||
GetPlayers() hash.MapReadonly[PlayerID, P]
|
GetPlayers() map[PlayerID]P
|
||||||
// GetActor 根据唯一标识符获取世界中的游戏对象
|
// GetActor 根据唯一标识符获取世界中的游戏对象
|
||||||
GetActor(guid int64) Actor
|
GetActor(guid int64) Actor
|
||||||
// GetActors 获取世界中的所有游戏对象
|
// GetActors 获取世界中的所有游戏对象
|
||||||
GetActors() hash.MapReadonly[int64, Actor]
|
GetActors() map[int64]Actor
|
||||||
// GetPlayerActor 获取游戏世界中归属特定玩家的特定游戏对象
|
// GetPlayerActor 获取游戏世界中归属特定玩家的特定游戏对象
|
||||||
GetPlayerActor(id PlayerID, guid int64) Actor
|
GetPlayerActor(id PlayerID, guid int64) Actor
|
||||||
// GetPlayerActors 获取游戏世界中归属特定玩家的所有游戏对象
|
// GetPlayerActors 获取游戏世界中归属特定玩家的所有游戏对象
|
||||||
GetPlayerActors(id PlayerID) hash.MapReadonly[int64, Actor]
|
GetPlayerActors(id PlayerID) map[int64]Actor
|
||||||
// IsExistPlayer 检查游戏世界中是否存在特定玩家
|
// IsExistPlayer 检查游戏世界中是否存在特定玩家
|
||||||
IsExistPlayer(id PlayerID) bool
|
IsExistPlayer(id PlayerID) bool
|
||||||
// IsExistActor 检查游戏世界中是否存在特定游戏对象
|
// IsExistActor 检查游戏世界中是否存在特定游戏对象
|
||||||
|
|
2
go.mod
2
go.mod
|
@ -23,6 +23,7 @@ require (
|
||||||
)
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
|
github.com/alphadose/haxmap v1.2.0 // indirect
|
||||||
github.com/bytedance/sonic v1.9.1 // indirect
|
github.com/bytedance/sonic v1.9.1 // indirect
|
||||||
github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 // indirect
|
github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 // indirect
|
||||||
github.com/gabriel-vasile/mimetype v1.4.2 // indirect
|
github.com/gabriel-vasile/mimetype v1.4.2 // indirect
|
||||||
|
@ -61,6 +62,7 @@ require (
|
||||||
go.uber.org/multierr v1.11.0 // indirect
|
go.uber.org/multierr v1.11.0 // indirect
|
||||||
golang.org/x/arch v0.3.0 // indirect
|
golang.org/x/arch v0.3.0 // indirect
|
||||||
golang.org/x/crypto v0.9.0 // indirect
|
golang.org/x/crypto v0.9.0 // indirect
|
||||||
|
golang.org/x/exp v0.0.0-20221031165847-c99f073a8326 // indirect
|
||||||
golang.org/x/net v0.10.0 // indirect
|
golang.org/x/net v0.10.0 // indirect
|
||||||
golang.org/x/sys v0.8.0 // indirect
|
golang.org/x/sys v0.8.0 // indirect
|
||||||
golang.org/x/text v0.9.0 // indirect
|
golang.org/x/text v0.9.0 // indirect
|
||||||
|
|
4
go.sum
4
go.sum
|
@ -2,6 +2,8 @@ cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMT
|
||||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||||
github.com/RussellLuo/timingwheel v0.0.0-20220218152713-54845bda3108 h1:iPugyBI7oFtbDZXC4dnY093M1kZx6k/95sen92gafbY=
|
github.com/RussellLuo/timingwheel v0.0.0-20220218152713-54845bda3108 h1:iPugyBI7oFtbDZXC4dnY093M1kZx6k/95sen92gafbY=
|
||||||
github.com/RussellLuo/timingwheel v0.0.0-20220218152713-54845bda3108/go.mod h1:WAMLHwunr1hi3u7OjGV6/VWG9QbdMhGpEKjROiSFd10=
|
github.com/RussellLuo/timingwheel v0.0.0-20220218152713-54845bda3108/go.mod h1:WAMLHwunr1hi3u7OjGV6/VWG9QbdMhGpEKjROiSFd10=
|
||||||
|
github.com/alphadose/haxmap v1.2.0 h1:noGrAmCE+gNheZ4KpW+sYj9W5uMcO1UAjbAq9XBOAfM=
|
||||||
|
github.com/alphadose/haxmap v1.2.0/go.mod h1:rjHw1IAqbxm0S3U5tD16GoKsiAd8FWx5BJ2IYqXwgmM=
|
||||||
github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8=
|
github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8=
|
||||||
github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=
|
github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=
|
||||||
github.com/bytedance/sonic v1.5.0/go.mod h1:ED5hyg4y6t3/9Ku1R6dU/4KyJ48DZ4jPhfY1O2AihPM=
|
github.com/bytedance/sonic v1.5.0/go.mod h1:ED5hyg4y6t3/9Ku1R6dU/4KyJ48DZ4jPhfY1O2AihPM=
|
||||||
|
@ -219,6 +221,8 @@ golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5y
|
||||||
golang.org/x/crypto v0.9.0 h1:LF6fAI+IutBocDJ2OT0Q1g8plpYljMZ4+lty+dsqw3g=
|
golang.org/x/crypto v0.9.0 h1:LF6fAI+IutBocDJ2OT0Q1g8plpYljMZ4+lty+dsqw3g=
|
||||||
golang.org/x/crypto v0.9.0/go.mod h1:yrmDGqONDYtNj3tH8X9dzUun2m2lzPa9ngI6/RUPGR0=
|
golang.org/x/crypto v0.9.0/go.mod h1:yrmDGqONDYtNj3tH8X9dzUun2m2lzPa9ngI6/RUPGR0=
|
||||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||||
|
golang.org/x/exp v0.0.0-20221031165847-c99f073a8326 h1:QfTh0HpN6hlw6D3vu8DAwC8pBIwikq0AI1evdm+FksE=
|
||||||
|
golang.org/x/exp v0.0.0-20221031165847-c99f073a8326/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc=
|
||||||
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||||
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
|
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
|
||||||
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||||
|
|
|
@ -2,7 +2,7 @@ package server
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/gorilla/websocket"
|
"github.com/gorilla/websocket"
|
||||||
"github.com/kercylan98/minotaur/utils/synchronization"
|
"github.com/kercylan98/minotaur/utils/concurrent"
|
||||||
"github.com/panjf2000/gnet"
|
"github.com/panjf2000/gnet"
|
||||||
"github.com/xtaci/kcp-go/v5"
|
"github.com/xtaci/kcp-go/v5"
|
||||||
"net"
|
"net"
|
||||||
|
@ -75,7 +75,7 @@ type Conn struct {
|
||||||
kcp *kcp.UDPSession
|
kcp *kcp.UDPSession
|
||||||
data map[any]any
|
data map[any]any
|
||||||
mutex sync.Mutex
|
mutex sync.Mutex
|
||||||
packetPool *synchronization.Pool[*connPacket]
|
packetPool *concurrent.Pool[*connPacket]
|
||||||
packets []*connPacket
|
packets []*connPacket
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -187,7 +187,7 @@ func (slf *Conn) WriteWithCallback(packet Packet, callback func(err error), mess
|
||||||
|
|
||||||
// writeLoop 写循环
|
// writeLoop 写循环
|
||||||
func (slf *Conn) writeLoop(wait *sync.WaitGroup) {
|
func (slf *Conn) writeLoop(wait *sync.WaitGroup) {
|
||||||
slf.packetPool = synchronization.NewPool[*connPacket](10*1024,
|
slf.packetPool = concurrent.NewPool[*connPacket](10*1024,
|
||||||
func() *connPacket {
|
func() *connPacket {
|
||||||
return &connPacket{}
|
return &connPacket{}
|
||||||
}, func(data *connPacket) {
|
}, func(data *connPacket) {
|
||||||
|
|
|
@ -4,8 +4,8 @@ import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/kercylan98/minotaur/server"
|
"github.com/kercylan98/minotaur/server"
|
||||||
|
"github.com/kercylan98/minotaur/utils/concurrent"
|
||||||
"github.com/kercylan98/minotaur/utils/log"
|
"github.com/kercylan98/minotaur/utils/log"
|
||||||
"github.com/kercylan98/minotaur/utils/synchronization"
|
|
||||||
"github.com/nats-io/nats.go"
|
"github.com/nats-io/nats.go"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
@ -18,7 +18,7 @@ func NewNats(url string, options ...NatsOption) *Nats {
|
||||||
n := &Nats{
|
n := &Nats{
|
||||||
url: url,
|
url: url,
|
||||||
subject: "MINOTAUR_CROSS",
|
subject: "MINOTAUR_CROSS",
|
||||||
messagePool: synchronization.NewPool[*Message](1024*100, func() *Message {
|
messagePool: concurrent.NewPool[*Message](1024*100, func() *Message {
|
||||||
return new(Message)
|
return new(Message)
|
||||||
}, func(data *Message) {
|
}, func(data *Message) {
|
||||||
data.ServerId = 0
|
data.ServerId = 0
|
||||||
|
@ -36,7 +36,7 @@ type Nats struct {
|
||||||
url string
|
url string
|
||||||
subject string
|
subject string
|
||||||
options []nats.Option
|
options []nats.Option
|
||||||
messagePool *synchronization.Pool[*Message]
|
messagePool *concurrent.Pool[*Message]
|
||||||
}
|
}
|
||||||
|
|
||||||
func (slf *Nats) Init(server *server.Server, packetHandle func(serverId int64, packet []byte)) (err error) {
|
func (slf *Nats) Init(server *server.Server, packetHandle func(serverId int64, packet []byte)) (err error) {
|
||||||
|
|
|
@ -5,9 +5,9 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
"github.com/gorilla/websocket"
|
"github.com/gorilla/websocket"
|
||||||
|
"github.com/kercylan98/minotaur/utils/concurrent"
|
||||||
"github.com/kercylan98/minotaur/utils/log"
|
"github.com/kercylan98/minotaur/utils/log"
|
||||||
"github.com/kercylan98/minotaur/utils/super"
|
"github.com/kercylan98/minotaur/utils/super"
|
||||||
"github.com/kercylan98/minotaur/utils/synchronization"
|
|
||||||
"github.com/kercylan98/minotaur/utils/timer"
|
"github.com/kercylan98/minotaur/utils/timer"
|
||||||
"github.com/kercylan98/minotaur/utils/times"
|
"github.com/kercylan98/minotaur/utils/times"
|
||||||
"github.com/panjf2000/ants/v2"
|
"github.com/panjf2000/ants/v2"
|
||||||
|
@ -33,7 +33,7 @@ func New(network Network, options ...Option) *Server {
|
||||||
runtime: &runtime{messagePoolSize: DefaultMessageBufferSize, messageChannelSize: DefaultMessageChannelSize},
|
runtime: &runtime{messagePoolSize: DefaultMessageBufferSize, messageChannelSize: DefaultMessageChannelSize},
|
||||||
option: &option{},
|
option: &option{},
|
||||||
network: network,
|
network: network,
|
||||||
online: synchronization.NewMap[string, *Conn](),
|
online: concurrent.NewBalanceMap[string, *Conn](),
|
||||||
closeChannel: make(chan struct{}, 1),
|
closeChannel: make(chan struct{}, 1),
|
||||||
systemSignal: make(chan os.Signal, 1),
|
systemSignal: make(chan os.Signal, 1),
|
||||||
}
|
}
|
||||||
|
@ -72,26 +72,26 @@ func New(network Network, options ...Option) *Server {
|
||||||
|
|
||||||
// Server 网络服务器
|
// Server 网络服务器
|
||||||
type Server struct {
|
type Server struct {
|
||||||
*event // 事件
|
*event // 事件
|
||||||
*runtime // 运行时
|
*runtime // 运行时
|
||||||
*option // 可选项
|
*option // 可选项
|
||||||
network Network // 网络类型
|
network Network // 网络类型
|
||||||
addr string // 侦听地址
|
addr string // 侦听地址
|
||||||
systemSignal chan os.Signal // 系统信号
|
systemSignal chan os.Signal // 系统信号
|
||||||
online *synchronization.Map[string, *Conn] // 在线连接
|
online *concurrent.BalanceMap[string, *Conn] // 在线连接
|
||||||
ginServer *gin.Engine // HTTP模式下的路由器
|
ginServer *gin.Engine // HTTP模式下的路由器
|
||||||
httpServer *http.Server // HTTP模式下的服务器
|
httpServer *http.Server // HTTP模式下的服务器
|
||||||
grpcServer *grpc.Server // GRPC模式下的服务器
|
grpcServer *grpc.Server // GRPC模式下的服务器
|
||||||
gServer *gNet // TCP或UDP模式下的服务器
|
gServer *gNet // TCP或UDP模式下的服务器
|
||||||
isRunning bool // 是否正在运行
|
isRunning bool // 是否正在运行
|
||||||
isShutdown atomic.Bool // 是否已关闭
|
isShutdown atomic.Bool // 是否已关闭
|
||||||
closeChannel chan struct{} // 关闭信号
|
closeChannel chan struct{} // 关闭信号
|
||||||
ants *ants.Pool // 协程池
|
ants *ants.Pool // 协程池
|
||||||
messagePool *synchronization.Pool[*Message] // 消息池
|
messagePool *concurrent.Pool[*Message] // 消息池
|
||||||
messageChannel chan *Message // 消息管道
|
messageChannel chan *Message // 消息管道
|
||||||
multiple *MultipleServer // 多服务器模式下的服务器
|
multiple *MultipleServer // 多服务器模式下的服务器
|
||||||
multipleRuntimeErrorChan chan error // 多服务器模式下的运行时错误
|
multipleRuntimeErrorChan chan error // 多服务器模式下的运行时错误
|
||||||
runMode RunMode // 运行模式
|
runMode RunMode // 运行模式
|
||||||
}
|
}
|
||||||
|
|
||||||
// Run 使用特定地址运行服务器
|
// Run 使用特定地址运行服务器
|
||||||
|
@ -115,7 +115,7 @@ func (slf *Server) Run(addr string) error {
|
||||||
var protoAddr = fmt.Sprintf("%s://%s", slf.network, slf.addr)
|
var protoAddr = fmt.Sprintf("%s://%s", slf.network, slf.addr)
|
||||||
var messageInitFinish = make(chan struct{}, 1)
|
var messageInitFinish = make(chan struct{}, 1)
|
||||||
var connectionInitHandle = func(callback func()) {
|
var connectionInitHandle = func(callback func()) {
|
||||||
slf.messagePool = synchronization.NewPool[*Message](slf.messagePoolSize,
|
slf.messagePool = concurrent.NewPool[*Message](slf.messagePoolSize,
|
||||||
func() *Message {
|
func() *Message {
|
||||||
return &Message{}
|
return &Message{}
|
||||||
},
|
},
|
||||||
|
|
|
@ -1,195 +0,0 @@
|
||||||
package asynchronous
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/json"
|
|
||||||
"github.com/kercylan98/minotaur/utils/hash"
|
|
||||||
)
|
|
||||||
|
|
||||||
func NewMap[Key comparable, Value any](options ...MapOption[Key, Value]) *Map[Key, Value] {
|
|
||||||
m := &Map[Key, Value]{
|
|
||||||
data: make(map[Key]Value),
|
|
||||||
}
|
|
||||||
for _, option := range options {
|
|
||||||
option(m)
|
|
||||||
}
|
|
||||||
return m
|
|
||||||
}
|
|
||||||
|
|
||||||
// Map 非并发安全的字典数据结构
|
|
||||||
// - 可用于对 synchronization.Map 的替代
|
|
||||||
type Map[Key comparable, Value any] struct {
|
|
||||||
data map[Key]Value
|
|
||||||
}
|
|
||||||
|
|
||||||
func (slf *Map[Key, Value]) Set(key Key, value Value) {
|
|
||||||
slf.data[key] = value
|
|
||||||
}
|
|
||||||
|
|
||||||
func (slf *Map[Key, Value]) Get(key Key) Value {
|
|
||||||
return slf.data[key]
|
|
||||||
}
|
|
||||||
|
|
||||||
// AtomGetSet 原子方式获取一个值并在之后进行赋值
|
|
||||||
func (slf *Map[Key, Value]) AtomGetSet(key Key, handle func(value Value, exist bool) (newValue Value, isSet bool)) {
|
|
||||||
value, exist := slf.data[key]
|
|
||||||
if newValue, isSet := handle(value, exist); isSet {
|
|
||||||
slf.data[key] = newValue
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Atom 原子操作
|
|
||||||
func (slf *Map[Key, Value]) Atom(handle func(m hash.Map[Key, Value])) {
|
|
||||||
handle(slf)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (slf *Map[Key, Value]) Exist(key Key) bool {
|
|
||||||
_, exist := slf.data[key]
|
|
||||||
return exist
|
|
||||||
}
|
|
||||||
|
|
||||||
func (slf *Map[Key, Value]) GetExist(key Key) (Value, bool) {
|
|
||||||
value, exist := slf.data[key]
|
|
||||||
return value, exist
|
|
||||||
}
|
|
||||||
|
|
||||||
func (slf *Map[Key, Value]) Delete(key Key) {
|
|
||||||
delete(slf.data, key)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (slf *Map[Key, Value]) DeleteGet(key Key) Value {
|
|
||||||
v := slf.data[key]
|
|
||||||
delete(slf.data, key)
|
|
||||||
return v
|
|
||||||
}
|
|
||||||
|
|
||||||
func (slf *Map[Key, Value]) DeleteGetExist(key Key) (Value, bool) {
|
|
||||||
v, exist := slf.data[key]
|
|
||||||
delete(slf.data, key)
|
|
||||||
return v, exist
|
|
||||||
}
|
|
||||||
|
|
||||||
func (slf *Map[Key, Value]) DeleteExist(key Key) bool {
|
|
||||||
if _, exist := slf.data[key]; !exist {
|
|
||||||
return exist
|
|
||||||
}
|
|
||||||
delete(slf.data, key)
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
func (slf *Map[Key, Value]) Clear() {
|
|
||||||
for k := range slf.data {
|
|
||||||
delete(slf.data, k)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (slf *Map[Key, Value]) ClearHandle(handle func(key Key, value Value)) {
|
|
||||||
for k, v := range slf.data {
|
|
||||||
handle(k, v)
|
|
||||||
delete(slf.data, k)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (slf *Map[Key, Value]) Range(handle func(key Key, value Value)) {
|
|
||||||
for k, v := range slf.data {
|
|
||||||
key, value := k, v
|
|
||||||
handle(key, value)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (slf *Map[Key, Value]) RangeSkip(handle func(key Key, value Value) bool) {
|
|
||||||
for k, v := range slf.data {
|
|
||||||
key, value := k, v
|
|
||||||
if !handle(key, value) {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (slf *Map[Key, Value]) RangeBreakout(handle func(key Key, value Value) bool) {
|
|
||||||
slf.rangeBreakout(handle)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (slf *Map[Key, Value]) rangeBreakout(handle func(key Key, value Value) bool) bool {
|
|
||||||
for k, v := range slf.data {
|
|
||||||
key, value := k, v
|
|
||||||
if !handle(key, value) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
func (slf *Map[Key, Value]) RangeFree(handle func(key Key, value Value, skip func(), breakout func())) {
|
|
||||||
slf.rangeFree(handle)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (slf *Map[Key, Value]) rangeFree(handle func(key Key, value Value, skip func(), breakout func())) bool {
|
|
||||||
var skipExec, breakoutExec bool
|
|
||||||
var skip = func() {
|
|
||||||
skipExec = true
|
|
||||||
}
|
|
||||||
var breakout = func() {
|
|
||||||
breakoutExec = true
|
|
||||||
}
|
|
||||||
for k, v := range slf.data {
|
|
||||||
key, value := k, v
|
|
||||||
handle(key, value, skip, breakout)
|
|
||||||
if skipExec {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if breakoutExec {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return breakoutExec
|
|
||||||
}
|
|
||||||
|
|
||||||
func (slf *Map[Key, Value]) Keys() []Key {
|
|
||||||
var s = make([]Key, 0, len(slf.data))
|
|
||||||
for k := range slf.data {
|
|
||||||
s = append(s, k)
|
|
||||||
}
|
|
||||||
return s
|
|
||||||
}
|
|
||||||
|
|
||||||
func (slf *Map[Key, Value]) Slice() []Value {
|
|
||||||
var s = make([]Value, 0, len(slf.data))
|
|
||||||
for _, v := range slf.data {
|
|
||||||
s = append(s, v)
|
|
||||||
}
|
|
||||||
return s
|
|
||||||
}
|
|
||||||
|
|
||||||
func (slf *Map[Key, Value]) Map() map[Key]Value {
|
|
||||||
var m = make(map[Key]Value)
|
|
||||||
for k, v := range slf.data {
|
|
||||||
m[k] = v
|
|
||||||
}
|
|
||||||
return m
|
|
||||||
}
|
|
||||||
|
|
||||||
func (slf *Map[Key, Value]) Size() int {
|
|
||||||
return len(slf.data)
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetOne 获取一个
|
|
||||||
func (slf *Map[Key, Value]) GetOne() (value Value) {
|
|
||||||
for _, v := range slf.data {
|
|
||||||
return v
|
|
||||||
}
|
|
||||||
return value
|
|
||||||
}
|
|
||||||
|
|
||||||
func (slf *Map[Key, Value]) MarshalJSON() ([]byte, error) {
|
|
||||||
m := slf.Map()
|
|
||||||
return json.Marshal(m)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (slf *Map[Key, Value]) UnmarshalJSON(bytes []byte) error {
|
|
||||||
var m = make(map[Key]Value)
|
|
||||||
if err := json.Unmarshal(bytes, &m); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
slf.data = m
|
|
||||||
return nil
|
|
||||||
}
|
|
|
@ -1,10 +0,0 @@
|
||||||
package asynchronous
|
|
||||||
|
|
||||||
type MapOption[Key comparable, Value any] func(m *Map[Key, Value])
|
|
||||||
|
|
||||||
// WithMapSource 通过传入的 map 初始化
|
|
||||||
func WithMapSource[Key comparable, Value any](source map[Key]Value) MapOption[Key, Value] {
|
|
||||||
return func(m *Map[Key, Value]) {
|
|
||||||
m.data = source
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,185 @@
|
||||||
|
package concurrent
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"sync"
|
||||||
|
)
|
||||||
|
|
||||||
|
// NewBalanceMap 创建一个并发安全且性能在普通读写和并发读写的情况下较为平衡的字典数据结构
|
||||||
|
func NewBalanceMap[Key comparable, value any](options ...BalanceMapOption[Key, value]) *BalanceMap[Key, value] {
|
||||||
|
m := &BalanceMap[Key, value]{
|
||||||
|
data: make(map[Key]value),
|
||||||
|
}
|
||||||
|
for _, option := range options {
|
||||||
|
option(m)
|
||||||
|
}
|
||||||
|
return m
|
||||||
|
}
|
||||||
|
|
||||||
|
// BalanceMap 并发安全且性能在普通读写和并发读写的情况下较为平衡的字典数据结构
|
||||||
|
// - 适用于要考虑并发读写但是并发读写的频率不高的情况
|
||||||
|
type BalanceMap[Key comparable, Value any] struct {
|
||||||
|
lock sync.RWMutex
|
||||||
|
data map[Key]Value
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set 设置一个值
|
||||||
|
func (slf *BalanceMap[Key, Value]) Set(key Key, value Value) {
|
||||||
|
slf.lock.Lock()
|
||||||
|
defer slf.lock.Unlock()
|
||||||
|
slf.data[key] = value
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get 获取一个值
|
||||||
|
func (slf *BalanceMap[Key, Value]) Get(key Key) Value {
|
||||||
|
slf.lock.RLock()
|
||||||
|
defer slf.lock.RUnlock()
|
||||||
|
return slf.data[key]
|
||||||
|
}
|
||||||
|
|
||||||
|
// Atom 原子操作
|
||||||
|
func (slf *BalanceMap[Key, Value]) Atom(handle func(m map[Key]Value)) {
|
||||||
|
slf.lock.Lock()
|
||||||
|
handle(slf.data)
|
||||||
|
slf.lock.Unlock()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Exist 判断是否存在
|
||||||
|
func (slf *BalanceMap[Key, Value]) Exist(key Key) bool {
|
||||||
|
slf.lock.RLock()
|
||||||
|
_, exist := slf.data[key]
|
||||||
|
slf.lock.RUnlock()
|
||||||
|
return exist
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetExist 获取一个值并判断是否存在
|
||||||
|
func (slf *BalanceMap[Key, Value]) GetExist(key Key) (Value, bool) {
|
||||||
|
slf.lock.RLock()
|
||||||
|
value, exist := slf.data[key]
|
||||||
|
slf.lock.RUnlock()
|
||||||
|
return value, exist
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete 删除一个值
|
||||||
|
func (slf *BalanceMap[Key, Value]) Delete(key Key) {
|
||||||
|
slf.lock.Lock()
|
||||||
|
delete(slf.data, key)
|
||||||
|
defer slf.lock.Unlock()
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteGet 删除一个值并返回
|
||||||
|
func (slf *BalanceMap[Key, Value]) DeleteGet(key Key) Value {
|
||||||
|
slf.lock.Lock()
|
||||||
|
v := slf.data[key]
|
||||||
|
delete(slf.data, key)
|
||||||
|
slf.lock.Unlock()
|
||||||
|
return v
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteGetExist 删除一个值并返回是否存在
|
||||||
|
func (slf *BalanceMap[Key, Value]) DeleteGetExist(key Key) (Value, bool) {
|
||||||
|
slf.lock.Lock()
|
||||||
|
v, exist := slf.data[key]
|
||||||
|
delete(slf.data, key)
|
||||||
|
defer slf.lock.Unlock()
|
||||||
|
return v, exist
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteExist 删除一个值并返回是否存在
|
||||||
|
func (slf *BalanceMap[Key, Value]) DeleteExist(key Key) bool {
|
||||||
|
slf.lock.Lock()
|
||||||
|
if _, exist := slf.data[key]; !exist {
|
||||||
|
slf.lock.Unlock()
|
||||||
|
return exist
|
||||||
|
}
|
||||||
|
delete(slf.data, key)
|
||||||
|
slf.lock.Unlock()
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clear 清空
|
||||||
|
func (slf *BalanceMap[Key, Value]) Clear() {
|
||||||
|
slf.lock.Lock()
|
||||||
|
for k := range slf.data {
|
||||||
|
delete(slf.data, k)
|
||||||
|
}
|
||||||
|
slf.lock.Unlock()
|
||||||
|
}
|
||||||
|
|
||||||
|
// ClearHandle 清空并处理
|
||||||
|
func (slf *BalanceMap[Key, Value]) ClearHandle(handle func(key Key, value Value)) {
|
||||||
|
slf.lock.Lock()
|
||||||
|
for k, v := range slf.data {
|
||||||
|
handle(k, v)
|
||||||
|
delete(slf.data, k)
|
||||||
|
}
|
||||||
|
slf.lock.Unlock()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Range 遍历所有值,如果 handle 返回 true 则停止遍历
|
||||||
|
func (slf *BalanceMap[Key, Value]) Range(handle func(key Key, value Value) bool) {
|
||||||
|
slf.lock.Lock()
|
||||||
|
for k, v := range slf.data {
|
||||||
|
key, value := k, v
|
||||||
|
if handle(key, value) {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
slf.lock.Unlock()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Keys 获取所有的键
|
||||||
|
func (slf *BalanceMap[Key, Value]) Keys() []Key {
|
||||||
|
slf.lock.RLock()
|
||||||
|
var s = make([]Key, 0, len(slf.data))
|
||||||
|
for k := range slf.data {
|
||||||
|
s = append(s, k)
|
||||||
|
}
|
||||||
|
slf.lock.RUnlock()
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
// Slice 获取所有的值
|
||||||
|
func (slf *BalanceMap[Key, Value]) Slice() []Value {
|
||||||
|
slf.lock.RLock()
|
||||||
|
var s = make([]Value, 0, len(slf.data))
|
||||||
|
for _, v := range slf.data {
|
||||||
|
s = append(s, v)
|
||||||
|
}
|
||||||
|
slf.lock.RUnlock()
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
// Map 转换为普通 map
|
||||||
|
func (slf *BalanceMap[Key, Value]) Map() map[Key]Value {
|
||||||
|
slf.lock.RLock()
|
||||||
|
var m = make(map[Key]Value)
|
||||||
|
for k, v := range slf.data {
|
||||||
|
m[k] = v
|
||||||
|
}
|
||||||
|
slf.lock.RUnlock()
|
||||||
|
return m
|
||||||
|
}
|
||||||
|
|
||||||
|
// Size 获取数量
|
||||||
|
func (slf *BalanceMap[Key, Value]) Size() int {
|
||||||
|
slf.lock.RLock()
|
||||||
|
defer slf.lock.RUnlock()
|
||||||
|
return len(slf.data)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (slf *BalanceMap[Key, Value]) MarshalJSON() ([]byte, error) {
|
||||||
|
m := slf.Map()
|
||||||
|
return json.Marshal(m)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (slf *BalanceMap[Key, Value]) UnmarshalJSON(bytes []byte) error {
|
||||||
|
var m = make(map[Key]Value)
|
||||||
|
if err := json.Unmarshal(bytes, &m); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
slf.lock.Lock()
|
||||||
|
slf.data = m
|
||||||
|
slf.lock.Unlock()
|
||||||
|
return nil
|
||||||
|
}
|
|
@ -0,0 +1,11 @@
|
||||||
|
package concurrent
|
||||||
|
|
||||||
|
// BalanceMapOption BalanceMap 的选项
|
||||||
|
type BalanceMapOption[Key comparable, Value any] func(m *BalanceMap[Key, Value])
|
||||||
|
|
||||||
|
// WithBalanceMapSource 通过传入的 map 初始化
|
||||||
|
func WithBalanceMapSource[Key comparable, Value any](source map[Key]Value) BalanceMapOption[Key, Value] {
|
||||||
|
return func(m *BalanceMap[Key, Value]) {
|
||||||
|
m.data = source
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,4 +1,4 @@
|
||||||
package synchronization
|
package concurrent
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/kercylan98/minotaur/utils/log"
|
"github.com/kercylan98/minotaur/utils/log"
|
|
@ -1,4 +1,4 @@
|
||||||
package synchronization
|
package concurrent
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/kercylan98/minotaur/utils/slice"
|
"github.com/kercylan98/minotaur/utils/slice"
|
|
@ -1,4 +1,4 @@
|
||||||
package synchronization
|
package concurrent
|
||||||
|
|
||||||
type SliceOption[T any] func(slice *Slice[T])
|
type SliceOption[T any] func(slice *Slice[T])
|
||||||
|
|
|
@ -1,29 +0,0 @@
|
||||||
package hash
|
|
||||||
|
|
||||||
// Map 提供了map集合接口
|
|
||||||
type Map[Key comparable, Value any] interface {
|
|
||||||
Set(key Key, value Value)
|
|
||||||
Get(key Key) Value
|
|
||||||
// AtomGetSet 原子方式获取一个值并在之后进行赋值
|
|
||||||
AtomGetSet(key Key, handle func(value Value, exist bool) (newValue Value, isSet bool))
|
|
||||||
// Atom 原子操作
|
|
||||||
Atom(handle func(m Map[Key, Value]))
|
|
||||||
Exist(key Key) bool
|
|
||||||
GetExist(key Key) (Value, bool)
|
|
||||||
Delete(key Key)
|
|
||||||
DeleteGet(key Key) Value
|
|
||||||
DeleteGetExist(key Key) (Value, bool)
|
|
||||||
DeleteExist(key Key) bool
|
|
||||||
Clear()
|
|
||||||
ClearHandle(handle func(key Key, value Value))
|
|
||||||
Range(handle func(key Key, value Value))
|
|
||||||
RangeSkip(handle func(key Key, value Value) bool)
|
|
||||||
RangeBreakout(handle func(key Key, value Value) bool)
|
|
||||||
RangeFree(handle func(key Key, value Value, skip func(), breakout func()))
|
|
||||||
Keys() []Key
|
|
||||||
Slice() []Value
|
|
||||||
Map() map[Key]Value
|
|
||||||
Size() int
|
|
||||||
// GetOne 获取一个
|
|
||||||
GetOne() (value Value)
|
|
||||||
}
|
|
|
@ -1,17 +0,0 @@
|
||||||
package hash
|
|
||||||
|
|
||||||
// MapReadonly 只读字典接口
|
|
||||||
type MapReadonly[Key comparable, Value any] interface {
|
|
||||||
Get(key Key) Value
|
|
||||||
Exist(key Key) bool
|
|
||||||
GetExist(key Key) (Value, bool)
|
|
||||||
Range(handle func(key Key, value Value))
|
|
||||||
RangeSkip(handle func(key Key, value Value) bool)
|
|
||||||
RangeBreakout(handle func(key Key, value Value) bool)
|
|
||||||
RangeFree(handle func(key Key, value Value, skip func(), breakout func()))
|
|
||||||
Keys() []Key
|
|
||||||
Slice() []Value
|
|
||||||
Map() map[Key]Value
|
|
||||||
Size() int
|
|
||||||
GetOne() (value Value)
|
|
||||||
}
|
|
|
@ -1,9 +1,8 @@
|
||||||
package stream
|
package stream
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/kercylan98/minotaur/utils/asynchronous"
|
"github.com/kercylan98/minotaur/utils/concurrent"
|
||||||
"github.com/kercylan98/minotaur/utils/hash"
|
"github.com/kercylan98/minotaur/utils/hash"
|
||||||
"github.com/kercylan98/minotaur/utils/synchronization"
|
|
||||||
"reflect"
|
"reflect"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -19,11 +18,6 @@ func WithMapCopy[K comparable, V any](m map[K]V) Map[K, V] {
|
||||||
return hash.Copy(m)
|
return hash.Copy(m)
|
||||||
}
|
}
|
||||||
|
|
||||||
// WithHashMap 使用传入的 map 执行链式操作
|
|
||||||
func WithHashMap[K comparable, V any](m hash.Map[K, V]) Map[K, V] {
|
|
||||||
return m.Map()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Map 提供了 map 的链式操作
|
// Map 提供了 map 的链式操作
|
||||||
type Map[K comparable, V any] map[K]V
|
type Map[K comparable, V any] map[K]V
|
||||||
|
|
||||||
|
@ -180,14 +174,9 @@ func (slf Map[K, V]) ToSliceStreamWithKey() Slice[K] {
|
||||||
return hash.KeyToSlice(slf)
|
return hash.KeyToSlice(slf)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ToSyncMap 将当前 Map 转换为 synchronization.Map
|
// ToSyncMap 将当前 Map 转换为 concurrent.BalanceMap
|
||||||
func (slf Map[K, V]) ToSyncMap() *synchronization.Map[K, V] {
|
func (slf Map[K, V]) ToSyncMap() *concurrent.BalanceMap[K, V] {
|
||||||
return synchronization.NewMap[K, V](synchronization.WithMapSource(slf))
|
return concurrent.NewBalanceMap[K, V](concurrent.WithBalanceMapSource(slf))
|
||||||
}
|
|
||||||
|
|
||||||
// ToAsyncMap 将当前 Map 转换为 asynchronous.Map
|
|
||||||
func (slf Map[K, V]) ToAsyncMap() *asynchronous.Map[K, V] {
|
|
||||||
return asynchronous.NewMap[K, V](asynchronous.WithMapSource(slf))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ToMap 将当前 Map 转换为 map
|
// ToMap 将当前 Map 转换为 map
|
||||||
|
|
|
@ -1,285 +0,0 @@
|
||||||
package synchronization
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/json"
|
|
||||||
"github.com/kercylan98/minotaur/utils/hash"
|
|
||||||
"sync"
|
|
||||||
)
|
|
||||||
|
|
||||||
func NewMap[Key comparable, value any](options ...MapOption[Key, value]) *Map[Key, value] {
|
|
||||||
m := &Map[Key, value]{
|
|
||||||
data: make(map[Key]value),
|
|
||||||
}
|
|
||||||
for _, option := range options {
|
|
||||||
option(m)
|
|
||||||
}
|
|
||||||
return m
|
|
||||||
}
|
|
||||||
|
|
||||||
// Map 并发安全的字典数据结构
|
|
||||||
type Map[Key comparable, Value any] struct {
|
|
||||||
lock sync.RWMutex
|
|
||||||
data map[Key]Value
|
|
||||||
atom bool
|
|
||||||
}
|
|
||||||
|
|
||||||
func (slf *Map[Key, Value]) Set(key Key, value Value) {
|
|
||||||
if !slf.atom {
|
|
||||||
slf.lock.Lock()
|
|
||||||
defer slf.lock.Unlock()
|
|
||||||
}
|
|
||||||
slf.data[key] = value
|
|
||||||
}
|
|
||||||
|
|
||||||
func (slf *Map[Key, Value]) Get(key Key) Value {
|
|
||||||
if !slf.atom {
|
|
||||||
slf.lock.RLock()
|
|
||||||
defer slf.lock.RUnlock()
|
|
||||||
}
|
|
||||||
return slf.data[key]
|
|
||||||
}
|
|
||||||
|
|
||||||
// AtomGetSet 原子方式获取一个值并在之后进行赋值
|
|
||||||
func (slf *Map[Key, Value]) AtomGetSet(key Key, handle func(value Value, exist bool) (newValue Value, isSet bool)) {
|
|
||||||
if !slf.atom {
|
|
||||||
slf.lock.Lock()
|
|
||||||
defer slf.lock.Unlock()
|
|
||||||
}
|
|
||||||
value, exist := slf.data[key]
|
|
||||||
if newValue, isSet := handle(value, exist); isSet {
|
|
||||||
slf.data[key] = newValue
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Atom 原子操作
|
|
||||||
func (slf *Map[Key, Value]) Atom(handle func(m hash.Map[Key, Value])) {
|
|
||||||
slf.lock.Lock()
|
|
||||||
slf.atom = true
|
|
||||||
handle(slf)
|
|
||||||
slf.atom = false
|
|
||||||
slf.lock.Unlock()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (slf *Map[Key, Value]) Exist(key Key) bool {
|
|
||||||
if !slf.atom {
|
|
||||||
slf.lock.RLock()
|
|
||||||
defer slf.lock.RUnlock()
|
|
||||||
}
|
|
||||||
_, exist := slf.data[key]
|
|
||||||
return exist
|
|
||||||
}
|
|
||||||
|
|
||||||
func (slf *Map[Key, Value]) GetExist(key Key) (Value, bool) {
|
|
||||||
if !slf.atom {
|
|
||||||
slf.lock.RLock()
|
|
||||||
defer slf.lock.RUnlock()
|
|
||||||
}
|
|
||||||
value, exist := slf.data[key]
|
|
||||||
return value, exist
|
|
||||||
}
|
|
||||||
|
|
||||||
func (slf *Map[Key, Value]) Delete(key Key) {
|
|
||||||
if !slf.atom {
|
|
||||||
slf.lock.Lock()
|
|
||||||
defer slf.lock.Unlock()
|
|
||||||
}
|
|
||||||
delete(slf.data, key)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (slf *Map[Key, Value]) DeleteGet(key Key) Value {
|
|
||||||
if !slf.atom {
|
|
||||||
slf.lock.Lock()
|
|
||||||
defer slf.lock.Unlock()
|
|
||||||
}
|
|
||||||
v := slf.data[key]
|
|
||||||
delete(slf.data, key)
|
|
||||||
return v
|
|
||||||
}
|
|
||||||
|
|
||||||
func (slf *Map[Key, Value]) DeleteGetExist(key Key) (Value, bool) {
|
|
||||||
if !slf.atom {
|
|
||||||
slf.lock.Lock()
|
|
||||||
defer slf.lock.Unlock()
|
|
||||||
}
|
|
||||||
v, exist := slf.data[key]
|
|
||||||
delete(slf.data, key)
|
|
||||||
return v, exist
|
|
||||||
}
|
|
||||||
|
|
||||||
func (slf *Map[Key, Value]) DeleteExist(key Key) bool {
|
|
||||||
if !slf.atom {
|
|
||||||
slf.lock.Lock()
|
|
||||||
defer slf.lock.Unlock()
|
|
||||||
}
|
|
||||||
if _, exist := slf.data[key]; !exist {
|
|
||||||
return exist
|
|
||||||
}
|
|
||||||
delete(slf.data, key)
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
func (slf *Map[Key, Value]) Clear() {
|
|
||||||
if !slf.atom {
|
|
||||||
slf.lock.Lock()
|
|
||||||
defer slf.lock.Unlock()
|
|
||||||
}
|
|
||||||
for k := range slf.data {
|
|
||||||
delete(slf.data, k)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (slf *Map[Key, Value]) ClearHandle(handle func(key Key, value Value)) {
|
|
||||||
if !slf.atom {
|
|
||||||
slf.lock.Lock()
|
|
||||||
defer slf.lock.Unlock()
|
|
||||||
}
|
|
||||||
for k, v := range slf.data {
|
|
||||||
handle(k, v)
|
|
||||||
delete(slf.data, k)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (slf *Map[Key, Value]) Range(handle func(key Key, value Value)) {
|
|
||||||
if !slf.atom {
|
|
||||||
slf.lock.RLock()
|
|
||||||
defer slf.lock.RUnlock()
|
|
||||||
}
|
|
||||||
for k, v := range slf.data {
|
|
||||||
key, value := k, v
|
|
||||||
handle(key, value)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (slf *Map[Key, Value]) RangeSkip(handle func(key Key, value Value) bool) {
|
|
||||||
if !slf.atom {
|
|
||||||
slf.lock.RLock()
|
|
||||||
defer slf.lock.RUnlock()
|
|
||||||
}
|
|
||||||
for k, v := range slf.data {
|
|
||||||
key, value := k, v
|
|
||||||
if !handle(key, value) {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (slf *Map[Key, Value]) RangeBreakout(handle func(key Key, value Value) bool) {
|
|
||||||
slf.rangeBreakout(handle)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (slf *Map[Key, Value]) rangeBreakout(handle func(key Key, value Value) bool) bool {
|
|
||||||
if !slf.atom {
|
|
||||||
slf.lock.RLock()
|
|
||||||
defer slf.lock.RUnlock()
|
|
||||||
}
|
|
||||||
for k, v := range slf.data {
|
|
||||||
key, value := k, v
|
|
||||||
if !handle(key, value) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
func (slf *Map[Key, Value]) RangeFree(handle func(key Key, value Value, skip func(), breakout func())) {
|
|
||||||
slf.rangeFree(handle)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (slf *Map[Key, Value]) rangeFree(handle func(key Key, value Value, skip func(), breakout func())) bool {
|
|
||||||
var skipExec, breakoutExec bool
|
|
||||||
var skip = func() {
|
|
||||||
skipExec = true
|
|
||||||
}
|
|
||||||
var breakout = func() {
|
|
||||||
breakoutExec = true
|
|
||||||
}
|
|
||||||
if !slf.atom {
|
|
||||||
slf.lock.RLock()
|
|
||||||
defer slf.lock.RUnlock()
|
|
||||||
}
|
|
||||||
for k, v := range slf.data {
|
|
||||||
key, value := k, v
|
|
||||||
handle(key, value, skip, breakout)
|
|
||||||
if skipExec {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if breakoutExec {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return breakoutExec
|
|
||||||
}
|
|
||||||
|
|
||||||
func (slf *Map[Key, Value]) Keys() []Key {
|
|
||||||
if !slf.atom {
|
|
||||||
slf.lock.RLock()
|
|
||||||
defer slf.lock.RUnlock()
|
|
||||||
}
|
|
||||||
var s = make([]Key, 0, len(slf.data))
|
|
||||||
for k := range slf.data {
|
|
||||||
s = append(s, k)
|
|
||||||
}
|
|
||||||
return s
|
|
||||||
}
|
|
||||||
|
|
||||||
func (slf *Map[Key, Value]) Slice() []Value {
|
|
||||||
if !slf.atom {
|
|
||||||
slf.lock.RLock()
|
|
||||||
defer slf.lock.RUnlock()
|
|
||||||
}
|
|
||||||
var s = make([]Value, 0, len(slf.data))
|
|
||||||
for _, v := range slf.data {
|
|
||||||
s = append(s, v)
|
|
||||||
}
|
|
||||||
return s
|
|
||||||
}
|
|
||||||
|
|
||||||
func (slf *Map[Key, Value]) Map() map[Key]Value {
|
|
||||||
var m = make(map[Key]Value)
|
|
||||||
if !slf.atom {
|
|
||||||
slf.lock.RLock()
|
|
||||||
defer slf.lock.RUnlock()
|
|
||||||
}
|
|
||||||
for k, v := range slf.data {
|
|
||||||
m[k] = v
|
|
||||||
}
|
|
||||||
return m
|
|
||||||
}
|
|
||||||
|
|
||||||
func (slf *Map[Key, Value]) Size() int {
|
|
||||||
if !slf.atom {
|
|
||||||
slf.lock.RLock()
|
|
||||||
defer slf.lock.RUnlock()
|
|
||||||
}
|
|
||||||
return len(slf.data)
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetOne 获取一个
|
|
||||||
func (slf *Map[Key, Value]) GetOne() (value Value) {
|
|
||||||
if !slf.atom {
|
|
||||||
slf.lock.RLock()
|
|
||||||
defer slf.lock.RUnlock()
|
|
||||||
}
|
|
||||||
for _, v := range slf.data {
|
|
||||||
return v
|
|
||||||
}
|
|
||||||
return value
|
|
||||||
}
|
|
||||||
|
|
||||||
func (slf *Map[Key, Value]) MarshalJSON() ([]byte, error) {
|
|
||||||
m := slf.Map()
|
|
||||||
return json.Marshal(m)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (slf *Map[Key, Value]) UnmarshalJSON(bytes []byte) error {
|
|
||||||
var m = make(map[Key]Value)
|
|
||||||
if err := json.Unmarshal(bytes, &m); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if !slf.atom {
|
|
||||||
slf.lock.Lock()
|
|
||||||
defer slf.lock.Unlock()
|
|
||||||
}
|
|
||||||
slf.data = m
|
|
||||||
return nil
|
|
||||||
}
|
|
|
@ -1,10 +0,0 @@
|
||||||
package synchronization
|
|
||||||
|
|
||||||
type MapOption[Key comparable, Value any] func(m *Map[Key, Value])
|
|
||||||
|
|
||||||
// WithMapSource 通过传入的 map 初始化
|
|
||||||
func WithMapSource[Key comparable, Value any](source map[Key]Value) MapOption[Key, Value] {
|
|
||||||
return func(m *Map[Key, Value]) {
|
|
||||||
m.data = source
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,259 +0,0 @@
|
||||||
package synchronization
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/json"
|
|
||||||
"github.com/kercylan98/minotaur/utils/hash"
|
|
||||||
"sync"
|
|
||||||
)
|
|
||||||
|
|
||||||
func NewMapSegment[Key comparable, value any](segmentCount int) *MapSegment[Key, value] {
|
|
||||||
ms := &MapSegment[Key, value]{
|
|
||||||
segments: map[int]*Map[Key, value]{},
|
|
||||||
cache: map[Key]int{},
|
|
||||||
consistency: hash.NewConsistency(segmentCount),
|
|
||||||
}
|
|
||||||
for i := 0; i < segmentCount; i++ {
|
|
||||||
ms.consistency.AddNode(i)
|
|
||||||
ms.segments[i] = NewMap[Key, value]()
|
|
||||||
}
|
|
||||||
|
|
||||||
return ms
|
|
||||||
}
|
|
||||||
|
|
||||||
// MapSegment 基于分段锁实现的并发安全的字典数据结构map
|
|
||||||
type MapSegment[Key comparable, Value any] struct {
|
|
||||||
segments map[int]*Map[Key, Value]
|
|
||||||
cache map[Key]int
|
|
||||||
consistency *hash.Consistency
|
|
||||||
lock sync.RWMutex
|
|
||||||
}
|
|
||||||
|
|
||||||
func (slf *MapSegment[Key, Value]) Atom(handle func(m hash.Map[Key, Value])) {
|
|
||||||
panic("this function is currently not supported")
|
|
||||||
}
|
|
||||||
|
|
||||||
func (slf *MapSegment[Key, Value]) Set(key Key, value Value) {
|
|
||||||
slf.lock.RLock()
|
|
||||||
s, exist := slf.cache[key]
|
|
||||||
slf.lock.RUnlock()
|
|
||||||
if !exist {
|
|
||||||
s = slf.consistency.PickNode(key)
|
|
||||||
slf.lock.Lock()
|
|
||||||
slf.cache[key] = s
|
|
||||||
slf.lock.Unlock()
|
|
||||||
}
|
|
||||||
slf.segments[s].Set(key, value)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (slf *MapSegment[Key, Value]) Get(key Key) (value Value) {
|
|
||||||
slf.lock.RLock()
|
|
||||||
s, exist := slf.cache[key]
|
|
||||||
slf.lock.RUnlock()
|
|
||||||
if !exist {
|
|
||||||
return value
|
|
||||||
}
|
|
||||||
return slf.segments[s].Get(key)
|
|
||||||
}
|
|
||||||
|
|
||||||
// AtomGetSet 原子方式获取一个值并在之后进行赋值
|
|
||||||
func (slf *MapSegment[Key, Value]) AtomGetSet(key Key, handle func(value Value, exist bool) (newValue Value, isSet bool)) {
|
|
||||||
var value Value
|
|
||||||
slf.lock.RLock()
|
|
||||||
s, exist := slf.cache[key]
|
|
||||||
slf.lock.RUnlock()
|
|
||||||
if !exist {
|
|
||||||
if newValue, isSet := handle(value, exist); isSet {
|
|
||||||
slf.Set(key, newValue)
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
slf.segments[s].AtomGetSet(key, handle)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (slf *MapSegment[Key, Value]) Exist(key Key) bool {
|
|
||||||
slf.lock.RLock()
|
|
||||||
_, exist := slf.cache[key]
|
|
||||||
slf.lock.RUnlock()
|
|
||||||
return exist
|
|
||||||
}
|
|
||||||
|
|
||||||
func (slf *MapSegment[Key, Value]) GetExist(key Key) (value Value, exist bool) {
|
|
||||||
slf.lock.RLock()
|
|
||||||
s, exist := slf.cache[key]
|
|
||||||
slf.lock.RUnlock()
|
|
||||||
if !exist {
|
|
||||||
return value, false
|
|
||||||
}
|
|
||||||
return slf.segments[s].GetExist(key)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (slf *MapSegment[Key, Value]) Delete(key Key) {
|
|
||||||
slf.lock.Lock()
|
|
||||||
s, exist := slf.cache[key]
|
|
||||||
delete(slf.cache, key)
|
|
||||||
slf.lock.Unlock()
|
|
||||||
if exist {
|
|
||||||
slf.segments[s].Delete(key)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (slf *MapSegment[Key, Value]) DeleteGet(key Key) (value Value) {
|
|
||||||
slf.lock.Lock()
|
|
||||||
s, exist := slf.cache[key]
|
|
||||||
delete(slf.cache, key)
|
|
||||||
slf.lock.Unlock()
|
|
||||||
if exist {
|
|
||||||
return slf.segments[s].DeleteGet(key)
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func (slf *MapSegment[Key, Value]) DeleteGetExist(key Key) (value Value, exist bool) {
|
|
||||||
slf.lock.Lock()
|
|
||||||
s, exist := slf.cache[key]
|
|
||||||
delete(slf.cache, key)
|
|
||||||
slf.lock.Unlock()
|
|
||||||
if exist {
|
|
||||||
return slf.segments[s].DeleteGetExist(key)
|
|
||||||
}
|
|
||||||
return value, exist
|
|
||||||
}
|
|
||||||
|
|
||||||
func (slf *MapSegment[Key, Value]) DeleteExist(key Key) bool {
|
|
||||||
slf.lock.Lock()
|
|
||||||
s, exist := slf.cache[key]
|
|
||||||
delete(slf.cache, key)
|
|
||||||
slf.lock.Unlock()
|
|
||||||
if exist {
|
|
||||||
return slf.segments[s].DeleteExist(key)
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
func (slf *MapSegment[Key, Value]) Clear() {
|
|
||||||
slf.lock.Lock()
|
|
||||||
for k := range slf.cache {
|
|
||||||
delete(slf.cache, k)
|
|
||||||
}
|
|
||||||
for _, m := range slf.segments {
|
|
||||||
m.Clear()
|
|
||||||
}
|
|
||||||
slf.lock.Unlock()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (slf *MapSegment[Key, Value]) ClearHandle(handle func(key Key, value Value)) {
|
|
||||||
slf.lock.Lock()
|
|
||||||
for k := range slf.cache {
|
|
||||||
delete(slf.cache, k)
|
|
||||||
}
|
|
||||||
for _, m := range slf.segments {
|
|
||||||
m.ClearHandle(handle)
|
|
||||||
}
|
|
||||||
slf.lock.Unlock()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (slf *MapSegment[Key, Value]) Range(handle func(key Key, value Value)) {
|
|
||||||
for _, m := range slf.segments {
|
|
||||||
m.Range(handle)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (slf *MapSegment[Key, Value]) RangeSkip(handle func(key Key, value Value) bool) {
|
|
||||||
for _, m := range slf.segments {
|
|
||||||
m.RangeSkip(handle)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (slf *MapSegment[Key, Value]) RangeBreakout(handle func(key Key, value Value) bool) {
|
|
||||||
for _, m := range slf.segments {
|
|
||||||
if m.rangeBreakout(handle) {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (slf *MapSegment[Key, Value]) RangeFree(handle func(key Key, value Value, skip func(), breakout func())) {
|
|
||||||
for _, m := range slf.segments {
|
|
||||||
if m.rangeFree(handle) {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (slf *MapSegment[Key, Value]) Keys() []Key {
|
|
||||||
var s = make([]Key, 0, len(slf.cache))
|
|
||||||
slf.lock.RLock()
|
|
||||||
for k := range slf.cache {
|
|
||||||
s = append(s, k)
|
|
||||||
}
|
|
||||||
defer slf.lock.RUnlock()
|
|
||||||
return s
|
|
||||||
}
|
|
||||||
|
|
||||||
func (slf *MapSegment[Key, Value]) Slice() []Value {
|
|
||||||
slf.lock.RLock()
|
|
||||||
var s = make([]Value, 0, len(slf.cache))
|
|
||||||
slf.lock.RUnlock()
|
|
||||||
for _, m := range slf.segments {
|
|
||||||
s = append(s, m.Slice()...)
|
|
||||||
}
|
|
||||||
return s
|
|
||||||
}
|
|
||||||
|
|
||||||
func (slf *MapSegment[Key, Value]) Map() map[Key]Value {
|
|
||||||
slf.lock.RLock()
|
|
||||||
var s = map[Key]Value{}
|
|
||||||
slf.lock.RUnlock()
|
|
||||||
for _, m := range slf.segments {
|
|
||||||
for k, v := range m.Map() {
|
|
||||||
s[k] = v
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return s
|
|
||||||
}
|
|
||||||
|
|
||||||
func (slf *MapSegment[Key, Value]) Size() int {
|
|
||||||
slf.lock.RLock()
|
|
||||||
defer slf.lock.RUnlock()
|
|
||||||
return len(slf.cache)
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetOne 获取一个
|
|
||||||
func (slf *MapSegment[Key, Value]) GetOne() (value Value) {
|
|
||||||
for k, s := range slf.cache {
|
|
||||||
return slf.segments[s].Get(k)
|
|
||||||
}
|
|
||||||
return value
|
|
||||||
}
|
|
||||||
|
|
||||||
func (slf *MapSegment[Key, Value]) MarshalJSON() ([]byte, error) {
|
|
||||||
var ms struct {
|
|
||||||
Segments map[int]*Map[Key, Value]
|
|
||||||
Cache map[Key]int
|
|
||||||
SegmentCount int
|
|
||||||
}
|
|
||||||
ms.Segments = slf.segments
|
|
||||||
ms.Cache = slf.cache
|
|
||||||
ms.SegmentCount = len(slf.segments)
|
|
||||||
return json.Marshal(ms)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (slf *MapSegment[Key, Value]) UnmarshalJSON(bytes []byte) error {
|
|
||||||
var ms struct {
|
|
||||||
Segments map[int]*Map[Key, Value]
|
|
||||||
Cache map[Key]int
|
|
||||||
SegmentCount int
|
|
||||||
}
|
|
||||||
if err := json.Unmarshal(bytes, &ms); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
slf.lock.Lock()
|
|
||||||
slf.consistency = hash.NewConsistency(ms.SegmentCount)
|
|
||||||
for i := 0; i < ms.SegmentCount; i++ {
|
|
||||||
slf.consistency.AddNode(i)
|
|
||||||
}
|
|
||||||
slf.segments = ms.Segments
|
|
||||||
slf.cache = ms.Cache
|
|
||||||
slf.lock.Unlock()
|
|
||||||
return nil
|
|
||||||
}
|
|
Loading…
Reference in New Issue