Optimise MemoryForumPermsStore by splitting recalcCanSeeAll out of Reload and only calling it once.
Reduce the amount of lock contention in recalcCanSeeAll by only loading each forum once. Stop logging the group ID twice in recalcCanSeeAll. Add the CacheAdd method to GroupCache and use it. Reduce the amount of boilerplate.
This commit is contained in:
parent
69f6b9c9c5
commit
1fa6b3ff26
|
@ -49,6 +49,7 @@ func (s *MemoryForumPermsStore) Init() error {
|
||||||
return s.ReloadAll()
|
return s.ReloadAll()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: Optimise this?
|
||||||
func (s *MemoryForumPermsStore) ReloadAll() error {
|
func (s *MemoryForumPermsStore) ReloadAll() error {
|
||||||
DebugLog("Reloading the forum perms")
|
DebugLog("Reloading the forum perms")
|
||||||
fids, err := Forums.GetAllIDs()
|
fids, err := Forums.GetAllIDs()
|
||||||
|
@ -56,11 +57,14 @@ func (s *MemoryForumPermsStore) ReloadAll() error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
for _, fid := range fids {
|
for _, fid := range fids {
|
||||||
err := s.Reload(fid)
|
if e := s.reload(fid); e != nil {
|
||||||
if err != nil {
|
return e
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if e := s.recalcCanSeeAll(); e != nil {
|
||||||
|
return e
|
||||||
|
}
|
||||||
|
TopicListThaw.Thaw()
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -73,8 +77,20 @@ func (s *MemoryForumPermsStore) parseForumPerm(perms []byte) (pperms *ForumPerms
|
||||||
return pperms, err
|
return pperms, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Need a more thread-safe way of doing this. Possibly with sync.Map?
|
|
||||||
func (s *MemoryForumPermsStore) Reload(fid int) error {
|
func (s *MemoryForumPermsStore) Reload(fid int) error {
|
||||||
|
e := s.reload(fid)
|
||||||
|
if e != nil {
|
||||||
|
return e
|
||||||
|
}
|
||||||
|
if e = s.recalcCanSeeAll(); e != nil {
|
||||||
|
return e
|
||||||
|
}
|
||||||
|
TopicListThaw.Thaw()
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Need a more thread-safe way of doing this. Possibly with sync.Map?
|
||||||
|
func (s *MemoryForumPermsStore) reload(fid int) error {
|
||||||
DebugLogf("Reloading the forum permissions for forum #%d", fid)
|
DebugLogf("Reloading the forum permissions for forum #%d", fid)
|
||||||
rows, err := s.getByForum.Query(fid)
|
rows, err := s.getByForum.Query(fid)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -111,7 +127,10 @@ func (s *MemoryForumPermsStore) Reload(fid int) error {
|
||||||
s.oddForums[fid] = forumPerms
|
s.oddForums[fid] = forumPerms
|
||||||
s.oddLock.Unlock()
|
s.oddLock.Unlock()
|
||||||
}
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *MemoryForumPermsStore) recalcCanSeeAll() error {
|
||||||
groups, err := Groups.GetAll()
|
groups, err := Groups.GetAll()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -121,17 +140,15 @@ func (s *MemoryForumPermsStore) Reload(fid int) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
gcache, ok := Groups.(GroupCache)
|
gc, ok := Groups.(GroupCache)
|
||||||
if !ok {
|
if !ok {
|
||||||
TopicListThaw.Thaw()
|
TopicListThaw.Thaw()
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, group := range groups {
|
// A separate loop to avoid contending on the odd-even locks as much
|
||||||
DebugLogf("Updating the forum permissions for Group #%d", group.ID)
|
fForumPerms := make(map[int]map[int]*ForumPerms)
|
||||||
canSee := []int{}
|
|
||||||
for _, fid := range fids {
|
for _, fid := range fids {
|
||||||
DebugDetailf("Forum #%+v\n", fid)
|
|
||||||
var forumPerms map[int]*ForumPerms
|
var forumPerms map[int]*ForumPerms
|
||||||
var ok bool
|
var ok bool
|
||||||
if fid%2 == 0 {
|
if fid%2 == 0 {
|
||||||
|
@ -143,34 +160,44 @@ func (s *MemoryForumPermsStore) Reload(fid int) error {
|
||||||
forumPerms, ok = s.oddForums[fid]
|
forumPerms, ok = s.oddForums[fid]
|
||||||
s.oddLock.RUnlock()
|
s.oddLock.RUnlock()
|
||||||
}
|
}
|
||||||
|
if ok {
|
||||||
|
fForumPerms[fid] = forumPerms
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var forumPerm *ForumPerms
|
// TODO: Can we recalculate CanSee without calculating every other forum?
|
||||||
|
for _, g := range groups {
|
||||||
|
DebugLogf("Updating the forum permissions for Group #%d", g.ID)
|
||||||
|
canSee := []int{}
|
||||||
|
for _, fid := range fids {
|
||||||
|
DebugDetailf("Forum #%+v\n", fid)
|
||||||
|
forumPerms, ok := fForumPerms[fid]
|
||||||
if !ok {
|
if !ok {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
forumPerm, ok = forumPerms[group.ID]
|
fp, ok := forumPerms[g.ID]
|
||||||
if !ok {
|
if !ok {
|
||||||
if group.Perms.ViewTopic {
|
if g.Perms.ViewTopic {
|
||||||
canSee = append(canSee, fid)
|
canSee = append(canSee, fid)
|
||||||
}
|
}
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
if forumPerm.Overrides {
|
if fp.Overrides {
|
||||||
if forumPerm.ViewTopic {
|
if fp.ViewTopic {
|
||||||
canSee = append(canSee, fid)
|
canSee = append(canSee, fid)
|
||||||
}
|
}
|
||||||
} else if group.Perms.ViewTopic {
|
} else if g.Perms.ViewTopic {
|
||||||
canSee = append(canSee, fid)
|
canSee = append(canSee, fid)
|
||||||
}
|
}
|
||||||
DebugDetail("group.ID: ", group.ID)
|
//DebugDetail("g.ID: ", g.ID)
|
||||||
DebugDetailf("forumPerm: %+v\n", forumPerm)
|
DebugDetailf("forumPerm: %+v\n", fp)
|
||||||
DebugDetail("canSee: ", canSee)
|
DebugDetail("canSee: ", canSee)
|
||||||
}
|
}
|
||||||
DebugDetailf("canSee (length %d): %+v \n", len(canSee), canSee)
|
DebugDetailf("canSee (length %d): %+v \n", len(canSee), canSee)
|
||||||
gcache.SetCanSee(group.ID, canSee)
|
gc.SetCanSee(g.ID, canSee)
|
||||||
}
|
}
|
||||||
TopicListThaw.Thaw()
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -193,6 +220,7 @@ func (s *MemoryForumPermsStore) GetAllMap() (bigMap map[int]map[int]*ForumPerms)
|
||||||
// TODO: Add a hook here and have plugin_guilds use it
|
// TODO: Add a hook here and have plugin_guilds use it
|
||||||
// TODO: Check if the forum exists?
|
// TODO: Check if the forum exists?
|
||||||
// TODO: Fix the races
|
// TODO: Fix the races
|
||||||
|
// TODO: Return BlankForumPerms() when the forum permission set doesn't exist?
|
||||||
func (s *MemoryForumPermsStore) Get(fid, gid int) (fp *ForumPerms, err error) {
|
func (s *MemoryForumPermsStore) Get(fid, gid int) (fp *ForumPerms, err error) {
|
||||||
var fmap map[int]*ForumPerms
|
var fmap map[int]*ForumPerms
|
||||||
var ok bool
|
var ok bool
|
||||||
|
|
|
@ -32,6 +32,7 @@ type GroupStore interface {
|
||||||
type GroupCache interface {
|
type GroupCache interface {
|
||||||
CacheSet(g *Group) error
|
CacheSet(g *Group) error
|
||||||
SetCanSee(gid int, canSee []int) error
|
SetCanSee(gid int, canSee []int) error
|
||||||
|
CacheAdd(g *Group) error
|
||||||
Length() int
|
Length() int
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -85,8 +86,7 @@ func (s *MemoryGroupStore) LoadGroups() error {
|
||||||
}
|
}
|
||||||
s.groups[g.ID] = g
|
s.groups[g.ID] = g
|
||||||
}
|
}
|
||||||
err = rows.Err()
|
if err = rows.Err(); err != nil {
|
||||||
if err != nil {
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
s.groupCount = i
|
s.groupCount = i
|
||||||
|
@ -256,14 +256,14 @@ func (s *MemoryGroupStore) Create(name, tag string, isAdmin, isMod, isBanned boo
|
||||||
GetHookTable().Vhook("create_group_preappend", &pluginPerms, &pluginPermsBytes)
|
GetHookTable().Vhook("create_group_preappend", &pluginPerms, &pluginPermsBytes)
|
||||||
|
|
||||||
// Generate the forum permissions based on the presets...
|
// Generate the forum permissions based on the presets...
|
||||||
fdata, err := Forums.GetAll()
|
forums, err := Forums.GetAll()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
|
|
||||||
presetSet := make(map[int]string)
|
presetSet := make(map[int]string)
|
||||||
permSet := make(map[int]*ForumPerms)
|
permSet := make(map[int]*ForumPerms)
|
||||||
for _, forum := range fdata {
|
for _, f := range forums {
|
||||||
var thePreset string
|
var thePreset string
|
||||||
switch {
|
switch {
|
||||||
case isAdmin:
|
case isAdmin:
|
||||||
|
@ -276,12 +276,12 @@ func (s *MemoryGroupStore) Create(name, tag string, isAdmin, isMod, isBanned boo
|
||||||
thePreset = "members"
|
thePreset = "members"
|
||||||
}
|
}
|
||||||
|
|
||||||
permmap := PresetToPermmap(forum.Preset)
|
permmap := PresetToPermmap(f.Preset)
|
||||||
permItem := permmap[thePreset]
|
permItem := permmap[thePreset]
|
||||||
permItem.Overrides = true
|
permItem.Overrides = true
|
||||||
|
|
||||||
permSet[forum.ID] = permItem
|
permSet[f.ID] = permItem
|
||||||
presetSet[forum.ID] = forum.Preset
|
presetSet[f.ID] = f.Preset
|
||||||
}
|
}
|
||||||
|
|
||||||
err = ReplaceForumPermsForGroupTx(tx, gid, presetSet, permSet)
|
err = ReplaceForumPermsForGroupTx(tx, gid, presetSet, permSet)
|
||||||
|
@ -298,16 +298,21 @@ func (s *MemoryGroupStore) Create(name, tag string, isAdmin, isMod, isBanned boo
|
||||||
isBanned = false
|
isBanned = false
|
||||||
}
|
}
|
||||||
|
|
||||||
s.Lock()
|
s.CacheAdd(&Group{gid, name, isMod, isAdmin, isBanned, tag, perms, []byte(permstr), pluginPerms, pluginPermsBytes, blankIntList, 0})
|
||||||
s.groups[gid] = &Group{gid, name, isMod, isAdmin, isBanned, tag, perms, []byte(permstr), pluginPerms, pluginPermsBytes, blankIntList, 0}
|
|
||||||
s.groupCount++
|
|
||||||
s.Unlock()
|
|
||||||
|
|
||||||
TopicListThaw.Thaw()
|
TopicListThaw.Thaw()
|
||||||
return gid, FPStore.ReloadAll()
|
return gid, FPStore.ReloadAll()
|
||||||
//return gid, TopicList.RebuildPermTree()
|
//return gid, TopicList.RebuildPermTree()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *MemoryGroupStore) CacheAdd(g *Group) error {
|
||||||
|
s.Lock()
|
||||||
|
s.groups[g.ID] = g
|
||||||
|
s.groupCount++
|
||||||
|
s.Unlock()
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func (s *MemoryGroupStore) GetAll() (results []*Group, err error) {
|
func (s *MemoryGroupStore) GetAll() (results []*Group, err error) {
|
||||||
var i int
|
var i int
|
||||||
s.RLock()
|
s.RLock()
|
||||||
|
|
Loading…
Reference in New Issue