mirror of
https://github.com/matrix-org/dendrite
synced 2024-12-15 06:03:44 +01:00
Precompute values for userIDSet
in sync notifier (#2348)
* Precompute values for `userIDSet` in sync notifier * Mutexes * Fixes * Sensible initial value * Update syncapi/notifier/notifier.go Co-authored-by: Till <2353100+S7evinK@users.noreply.github.com> * Placate the almighty linter Co-authored-by: Till <2353100+S7evinK@users.noreply.github.com>
This commit is contained in:
parent
29f2168789
commit
1140f39993
1 changed files with 56 additions and 17 deletions
|
@ -36,7 +36,7 @@ import (
|
||||||
type Notifier struct {
|
type Notifier struct {
|
||||||
lock *sync.RWMutex
|
lock *sync.RWMutex
|
||||||
// A map of RoomID => Set<UserID> : Must only be accessed by the OnNewEvent goroutine
|
// A map of RoomID => Set<UserID> : Must only be accessed by the OnNewEvent goroutine
|
||||||
roomIDToJoinedUsers map[string]userIDSet
|
roomIDToJoinedUsers map[string]*userIDSet
|
||||||
// A map of RoomID => Set<UserID> : Must only be accessed by the OnNewEvent goroutine
|
// A map of RoomID => Set<UserID> : Must only be accessed by the OnNewEvent goroutine
|
||||||
roomIDToPeekingDevices map[string]peekingDeviceSet
|
roomIDToPeekingDevices map[string]peekingDeviceSet
|
||||||
// The latest sync position
|
// The latest sync position
|
||||||
|
@ -54,7 +54,7 @@ type Notifier struct {
|
||||||
// the joined users within each of them by calling Notifier.Load(*storage.SyncServerDatabase).
|
// the joined users within each of them by calling Notifier.Load(*storage.SyncServerDatabase).
|
||||||
func NewNotifier() *Notifier {
|
func NewNotifier() *Notifier {
|
||||||
return &Notifier{
|
return &Notifier{
|
||||||
roomIDToJoinedUsers: make(map[string]userIDSet),
|
roomIDToJoinedUsers: make(map[string]*userIDSet),
|
||||||
roomIDToPeekingDevices: make(map[string]peekingDeviceSet),
|
roomIDToPeekingDevices: make(map[string]peekingDeviceSet),
|
||||||
userDeviceStreams: make(map[string]map[string]*UserDeviceStream),
|
userDeviceStreams: make(map[string]map[string]*UserDeviceStream),
|
||||||
lock: &sync.RWMutex{},
|
lock: &sync.RWMutex{},
|
||||||
|
@ -262,7 +262,7 @@ func (n *Notifier) SharedUsers(userID string) []string {
|
||||||
func (n *Notifier) _sharedUsers(userID string) []string {
|
func (n *Notifier) _sharedUsers(userID string) []string {
|
||||||
n._sharedUserMap[userID] = struct{}{}
|
n._sharedUserMap[userID] = struct{}{}
|
||||||
for roomID, users := range n.roomIDToJoinedUsers {
|
for roomID, users := range n.roomIDToJoinedUsers {
|
||||||
if _, ok := users[userID]; !ok {
|
if ok := users.isIn(userID); !ok {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
for _, userID := range n._joinedUsers(roomID) {
|
for _, userID := range n._joinedUsers(roomID) {
|
||||||
|
@ -282,8 +282,11 @@ func (n *Notifier) IsSharedUser(userA, userB string) bool {
|
||||||
defer n.lock.RUnlock()
|
defer n.lock.RUnlock()
|
||||||
var okA, okB bool
|
var okA, okB bool
|
||||||
for _, users := range n.roomIDToJoinedUsers {
|
for _, users := range n.roomIDToJoinedUsers {
|
||||||
_, okA = users[userA]
|
okA = users.isIn(userA)
|
||||||
_, okB = users[userB]
|
if !okA {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
okB = users.isIn(userB)
|
||||||
if okA && okB {
|
if okA && okB {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
@ -345,11 +348,12 @@ func (n *Notifier) setUsersJoinedToRooms(roomIDToUserIDs map[string][]string) {
|
||||||
// This is just the bulk form of addJoinedUser
|
// This is just the bulk form of addJoinedUser
|
||||||
for roomID, userIDs := range roomIDToUserIDs {
|
for roomID, userIDs := range roomIDToUserIDs {
|
||||||
if _, ok := n.roomIDToJoinedUsers[roomID]; !ok {
|
if _, ok := n.roomIDToJoinedUsers[roomID]; !ok {
|
||||||
n.roomIDToJoinedUsers[roomID] = make(userIDSet, len(userIDs))
|
n.roomIDToJoinedUsers[roomID] = newUserIDSet(len(userIDs))
|
||||||
}
|
}
|
||||||
for _, userID := range userIDs {
|
for _, userID := range userIDs {
|
||||||
n.roomIDToJoinedUsers[roomID].add(userID)
|
n.roomIDToJoinedUsers[roomID].add(userID)
|
||||||
}
|
}
|
||||||
|
n.roomIDToJoinedUsers[roomID].precompute()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -440,16 +444,18 @@ func (n *Notifier) _fetchUserStreams(userID string) []*UserDeviceStream {
|
||||||
|
|
||||||
func (n *Notifier) _addJoinedUser(roomID, userID string) {
|
func (n *Notifier) _addJoinedUser(roomID, userID string) {
|
||||||
if _, ok := n.roomIDToJoinedUsers[roomID]; !ok {
|
if _, ok := n.roomIDToJoinedUsers[roomID]; !ok {
|
||||||
n.roomIDToJoinedUsers[roomID] = make(userIDSet)
|
n.roomIDToJoinedUsers[roomID] = newUserIDSet(8)
|
||||||
}
|
}
|
||||||
n.roomIDToJoinedUsers[roomID].add(userID)
|
n.roomIDToJoinedUsers[roomID].add(userID)
|
||||||
|
n.roomIDToJoinedUsers[roomID].precompute()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n *Notifier) _removeJoinedUser(roomID, userID string) {
|
func (n *Notifier) _removeJoinedUser(roomID, userID string) {
|
||||||
if _, ok := n.roomIDToJoinedUsers[roomID]; !ok {
|
if _, ok := n.roomIDToJoinedUsers[roomID]; !ok {
|
||||||
n.roomIDToJoinedUsers[roomID] = make(userIDSet)
|
n.roomIDToJoinedUsers[roomID] = newUserIDSet(8)
|
||||||
}
|
}
|
||||||
n.roomIDToJoinedUsers[roomID].remove(userID)
|
n.roomIDToJoinedUsers[roomID].remove(userID)
|
||||||
|
n.roomIDToJoinedUsers[roomID].precompute()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n *Notifier) JoinedUsers(roomID string) (userIDs []string) {
|
func (n *Notifier) JoinedUsers(roomID string) (userIDs []string) {
|
||||||
|
@ -521,19 +527,52 @@ func (n *Notifier) _removeEmptyUserStreams() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// A string set, mainly existing for improving clarity of structs in this file.
|
// A string set, mainly existing for improving clarity of structs in this file.
|
||||||
type userIDSet map[string]struct{}
|
type userIDSet struct {
|
||||||
|
sync.Mutex
|
||||||
func (s userIDSet) add(str string) {
|
set map[string]struct{}
|
||||||
s[str] = struct{}{}
|
precomputed []string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s userIDSet) remove(str string) {
|
func newUserIDSet(cap int) *userIDSet {
|
||||||
delete(s, str)
|
return &userIDSet{
|
||||||
|
set: make(map[string]struct{}, cap),
|
||||||
|
precomputed: nil,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s userIDSet) values() (vals []string) {
|
func (s *userIDSet) add(str string) {
|
||||||
vals = make([]string, 0, len(s))
|
s.Lock()
|
||||||
for str := range s {
|
defer s.Unlock()
|
||||||
|
s.set[str] = struct{}{}
|
||||||
|
s.precomputed = s.precomputed[:0] // invalidate cache
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *userIDSet) remove(str string) {
|
||||||
|
s.Lock()
|
||||||
|
defer s.Unlock()
|
||||||
|
delete(s.set, str)
|
||||||
|
s.precomputed = s.precomputed[:0] // invalidate cache
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *userIDSet) precompute() {
|
||||||
|
s.Lock()
|
||||||
|
defer s.Unlock()
|
||||||
|
s.precomputed = s.values()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *userIDSet) isIn(str string) bool {
|
||||||
|
s.Lock()
|
||||||
|
defer s.Unlock()
|
||||||
|
_, ok := s.set[str]
|
||||||
|
return ok
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *userIDSet) values() (vals []string) {
|
||||||
|
if len(s.precomputed) > 0 {
|
||||||
|
return s.precomputed // only return if not invalidated
|
||||||
|
}
|
||||||
|
vals = make([]string, 0, len(s.set))
|
||||||
|
for str := range s.set {
|
||||||
vals = append(vals, str)
|
vals = append(vals, str)
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
|
|
Loading…
Reference in a new issue