forked from External/ergo
tweak member caching
This commit is contained in:
parent
780116b0c2
commit
a6664459f6
2 changed files with 31 additions and 25 deletions
|
|
@ -55,7 +55,7 @@ type Channel struct {
|
||||||
uuid utils.UUID
|
uuid utils.UUID
|
||||||
// these caches are paired to allow iteration over channel members without holding the lock
|
// these caches are paired to allow iteration over channel members without holding the lock
|
||||||
membersCache []*Client
|
membersCache []*Client
|
||||||
memberModesCache []*modes.ModeSet
|
memberDataCache []*memberData
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewChannel creates a new channel from a `Server` and a `name`
|
// NewChannel creates a new channel from a `Server` and a `name`
|
||||||
|
|
@ -424,18 +424,18 @@ func (channel *Channel) AcceptTransfer(client *Client) (err error) {
|
||||||
func (channel *Channel) regenerateMembersCache() {
|
func (channel *Channel) regenerateMembersCache() {
|
||||||
channel.stateMutex.RLock()
|
channel.stateMutex.RLock()
|
||||||
membersCache := make([]*Client, len(channel.members))
|
membersCache := make([]*Client, len(channel.members))
|
||||||
modesCache := make([]*modes.ModeSet, len(channel.members))
|
dataCache := make([]*memberData, len(channel.members))
|
||||||
i := 0
|
i := 0
|
||||||
for client, info := range channel.members {
|
for client, info := range channel.members {
|
||||||
membersCache[i] = client
|
membersCache[i] = client
|
||||||
modesCache[i] = info.modes
|
dataCache[i] = info
|
||||||
i++
|
i++
|
||||||
}
|
}
|
||||||
channel.stateMutex.RUnlock()
|
channel.stateMutex.RUnlock()
|
||||||
|
|
||||||
channel.stateMutex.Lock()
|
channel.stateMutex.Lock()
|
||||||
channel.membersCache = membersCache
|
channel.membersCache = membersCache
|
||||||
channel.memberModesCache = modesCache
|
channel.memberDataCache = dataCache
|
||||||
channel.stateMutex.Unlock()
|
channel.stateMutex.Unlock()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -444,7 +444,7 @@ func (channel *Channel) Names(client *Client, rb *ResponseBuffer) {
|
||||||
channel.stateMutex.RLock()
|
channel.stateMutex.RLock()
|
||||||
clientData, isJoined := channel.members[client]
|
clientData, isJoined := channel.members[client]
|
||||||
chname := channel.name
|
chname := channel.name
|
||||||
membersCache, memberModesCache := channel.membersCache, channel.memberModesCache
|
membersCache, memberDataCache := channel.membersCache, channel.memberDataCache
|
||||||
channel.stateMutex.RUnlock()
|
channel.stateMutex.RUnlock()
|
||||||
isOper := client.HasRoleCapabs("sajoin")
|
isOper := client.HasRoleCapabs("sajoin")
|
||||||
respectAuditorium := channel.flags.HasMode(modes.Auditorium) && !isOper &&
|
respectAuditorium := channel.flags.HasMode(modes.Auditorium) && !isOper &&
|
||||||
|
|
@ -457,27 +457,27 @@ func (channel *Channel) Names(client *Client, rb *ResponseBuffer) {
|
||||||
tl.Initialize(maxNamLen, " ")
|
tl.Initialize(maxNamLen, " ")
|
||||||
if isJoined || !channel.flags.HasMode(modes.Secret) || isOper {
|
if isJoined || !channel.flags.HasMode(modes.Secret) || isOper {
|
||||||
for i, target := range membersCache {
|
for i, target := range membersCache {
|
||||||
|
if !isJoined && target.HasMode(modes.Invisible) && !isOper {
|
||||||
|
continue
|
||||||
|
}
|
||||||
var nick string
|
var nick string
|
||||||
if isUserhostInNames {
|
if isUserhostInNames {
|
||||||
nick = target.NickMaskString()
|
nick = target.NickMaskString()
|
||||||
} else {
|
} else {
|
||||||
nick = target.Nick()
|
nick = target.Nick()
|
||||||
}
|
}
|
||||||
modeSet := memberModesCache[i]
|
memberData := memberDataCache[i]
|
||||||
if !isJoined && target.HasMode(modes.Invisible) && !isOper {
|
if respectAuditorium && memberData.modes.HighestChannelUserMode() == modes.Mode(0) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if respectAuditorium && modeSet.HighestChannelUserMode() == modes.Mode(0) {
|
tl.AddParts(memberData.modes.Prefixes(isMultiPrefix), nick)
|
||||||
continue
|
|
||||||
}
|
|
||||||
tl.AddParts(modeSet.Prefixes(isMultiPrefix), nick)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, line := range tl.Lines() {
|
for _, line := range tl.Lines() {
|
||||||
rb.Add(nil, client.server.name, RPL_NAMREPLY, client.nick, "=", chname, line)
|
rb.Add(nil, client.server.name, RPL_NAMREPLY, client.nick, "=", chname, line)
|
||||||
}
|
}
|
||||||
rb.Add(nil, client.server.name, RPL_ENDOFNAMES, client.nick, channel.name, client.t("End of NAMES list"))
|
rb.Add(nil, client.server.name, RPL_ENDOFNAMES, client.nick, chname, client.t("End of NAMES list"))
|
||||||
}
|
}
|
||||||
|
|
||||||
// does `clientMode` give you privileges to grant/remove `targetMode` to/from people,
|
// does `clientMode` give you privileges to grant/remove `targetMode` to/from people,
|
||||||
|
|
@ -501,7 +501,7 @@ func channelUserModeHasPrivsOver(clientMode modes.Mode, targetMode modes.Mode) b
|
||||||
// ClientIsAtLeast returns whether the client has at least the given channel privilege.
|
// ClientIsAtLeast returns whether the client has at least the given channel privilege.
|
||||||
func (channel *Channel) ClientIsAtLeast(client *Client, permission modes.Mode) bool {
|
func (channel *Channel) ClientIsAtLeast(client *Client, permission modes.Mode) bool {
|
||||||
channel.stateMutex.RLock()
|
channel.stateMutex.RLock()
|
||||||
memberData := channel.members[client]
|
memberData, present := channel.members[client]
|
||||||
founder := channel.registeredFounder
|
founder := channel.registeredFounder
|
||||||
channel.stateMutex.RUnlock()
|
channel.stateMutex.RUnlock()
|
||||||
|
|
||||||
|
|
@ -509,6 +509,10 @@ func (channel *Channel) ClientIsAtLeast(client *Client, permission modes.Mode) b
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if !present {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
for _, mode := range modes.ChannelUserModes {
|
for _, mode := range modes.ChannelUserModes {
|
||||||
if memberData.modes.HasMode(mode) {
|
if memberData.modes.HasMode(mode) {
|
||||||
return true
|
return true
|
||||||
|
|
@ -564,15 +568,14 @@ func (channel *Channel) setMemberStatus(client *Client, status alwaysOnChannelSt
|
||||||
mData.modes.SetMode(modes.Mode(mode), true)
|
mData.modes.SetMode(modes.Mode(mode), true)
|
||||||
}
|
}
|
||||||
mData.joinTime = status.JoinTime
|
mData.joinTime = status.JoinTime
|
||||||
channel.members[client] = mData
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (channel *Channel) ClientHasPrivsOver(client *Client, target *Client) bool {
|
func (channel *Channel) ClientHasPrivsOver(client *Client, target *Client) bool {
|
||||||
channel.stateMutex.RLock()
|
channel.stateMutex.RLock()
|
||||||
founder := channel.registeredFounder
|
founder := channel.registeredFounder
|
||||||
clientModes := channel.members[client].modes
|
clientData, clientOK := channel.members[client]
|
||||||
targetModes := channel.members[target].modes
|
targetData, targetOK := channel.members[target]
|
||||||
channel.stateMutex.RUnlock()
|
channel.stateMutex.RUnlock()
|
||||||
|
|
||||||
if founder != "" {
|
if founder != "" {
|
||||||
|
|
@ -583,7 +586,11 @@ func (channel *Channel) ClientHasPrivsOver(client *Client, target *Client) bool
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return channelUserModeHasPrivsOver(clientModes.HighestChannelUserMode(), targetModes.HighestChannelUserMode())
|
return clientOK && targetOK &&
|
||||||
|
channelUserModeHasPrivsOver(
|
||||||
|
clientData.modes.HighestChannelUserMode(),
|
||||||
|
targetData.modes.HighestChannelUserMode(),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (channel *Channel) hasClient(client *Client) bool {
|
func (channel *Channel) hasClient(client *Client) bool {
|
||||||
|
|
@ -1307,9 +1314,9 @@ func (channel *Channel) SendSplitMessage(command string, minPrefixMode modes.Mod
|
||||||
|
|
||||||
if channel.flags.HasMode(modes.OpModerated) {
|
if channel.flags.HasMode(modes.OpModerated) {
|
||||||
channel.stateMutex.RLock()
|
channel.stateMutex.RLock()
|
||||||
cuData := channel.members[client]
|
cuData, ok := channel.members[client]
|
||||||
channel.stateMutex.RUnlock()
|
channel.stateMutex.RUnlock()
|
||||||
if cuData.modes.HighestChannelUserMode() == modes.Mode(0) {
|
if !ok || cuData.modes.HighestChannelUserMode() == modes.Mode(0) {
|
||||||
// max(statusmsg_minmode, halfop)
|
// max(statusmsg_minmode, halfop)
|
||||||
if minPrefixMode == modes.Mode(0) || minPrefixMode == modes.Voice {
|
if minPrefixMode == modes.Mode(0) || minPrefixMode == modes.Voice {
|
||||||
minPrefixMode = modes.Halfop
|
minPrefixMode = modes.Halfop
|
||||||
|
|
@ -1478,7 +1485,7 @@ func (channel *Channel) Purge(source string) {
|
||||||
chname := channel.name
|
chname := channel.name
|
||||||
members := channel.membersCache
|
members := channel.membersCache
|
||||||
channel.membersCache = nil
|
channel.membersCache = nil
|
||||||
channel.memberModesCache = nil
|
channel.memberDataCache = nil
|
||||||
channel.members = make(MemberSet)
|
channel.members = make(MemberSet)
|
||||||
// TODO try to prevent Purge racing against (pending) Join?
|
// TODO try to prevent Purge racing against (pending) Join?
|
||||||
channel.stateMutex.Unlock()
|
channel.stateMutex.Unlock()
|
||||||
|
|
|
||||||
|
|
@ -16,17 +16,16 @@ import (
|
||||||
type ClientSet = utils.HashSet[*Client]
|
type ClientSet = utils.HashSet[*Client]
|
||||||
|
|
||||||
type memberData struct {
|
type memberData struct {
|
||||||
modes *modes.ModeSet
|
modes modes.ModeSet
|
||||||
joinTime int64
|
joinTime int64
|
||||||
}
|
}
|
||||||
|
|
||||||
// MemberSet is a set of members with modes.
|
// MemberSet is a set of members with modes.
|
||||||
type MemberSet map[*Client]memberData
|
type MemberSet map[*Client]*memberData
|
||||||
|
|
||||||
// Add adds the given client to this set.
|
// Add adds the given client to this set.
|
||||||
func (members MemberSet) Add(member *Client) {
|
func (members MemberSet) Add(member *Client) {
|
||||||
members[member] = memberData{
|
members[member] = &memberData{
|
||||||
modes: modes.NewModeSet(),
|
|
||||||
joinTime: time.Now().UnixNano(),
|
joinTime: time.Now().UnixNano(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue