Fix a potential data race when reloading the permissions for a forum.

Log more things during start-up.
Save a few bytes here and there.

Add a couple of initial forum perms store tests.
Add an additional group.CanSee test.
This commit is contained in:
Azareal 2019-06-19 13:16:03 +10:00
parent 54abbe980f
commit 947306a0af
6 changed files with 96 additions and 21 deletions

View File

@ -100,6 +100,7 @@ func (s *MemoryForumPermsStore) Reload(fid int) error {
forumPerms[gid] = pperms forumPerms[gid] = pperms
} }
DebugLogf("forumPerms: %+v\n", forumPerms) DebugLogf("forumPerms: %+v\n", forumPerms)
if fid%2 == 0 { if fid%2 == 0 {
s.evenLock.Lock() s.evenLock.Lock()
s.evenForums[fid] = forumPerms s.evenForums[fid] = forumPerms
@ -119,9 +120,15 @@ func (s *MemoryForumPermsStore) Reload(fid int) error {
return err return err
} }
gcache, ok := Groups.(GroupCache)
if !ok {
TopicListThaw.Thaw()
return nil
}
for _, group := range groups { for _, group := range groups {
DebugLogf("Updating the forum permissions for Group #%d", group.ID) DebugLogf("Updating the forum permissions for Group #%d", group.ID)
group.CanSee = []int{} canSee := []int{}
for _, fid := range fids { for _, fid := range fids {
DebugDetailf("Forum #%+v\n", fid) DebugDetailf("Forum #%+v\n", fid)
var forumPerms map[int]*ForumPerms var forumPerms map[int]*ForumPerms
@ -143,23 +150,24 @@ func (s *MemoryForumPermsStore) Reload(fid int) error {
forumPerm, ok = forumPerms[group.ID] forumPerm, ok = forumPerms[group.ID]
if !ok { if !ok {
if group.Perms.ViewTopic { if group.Perms.ViewTopic {
group.CanSee = append(group.CanSee, fid) canSee = append(canSee, fid)
} }
continue continue
} }
if forumPerm.Overrides { if forumPerm.Overrides {
if forumPerm.ViewTopic { if forumPerm.ViewTopic {
group.CanSee = append(group.CanSee, fid) canSee = append(canSee, fid)
} }
} else if group.Perms.ViewTopic { } else if group.Perms.ViewTopic {
group.CanSee = append(group.CanSee, fid) canSee = append(canSee, fid)
} }
DebugDetail("group.ID: ", group.ID) DebugDetail("group.ID: ", group.ID)
DebugDetailf("forumPerm: %+v\n", forumPerm) DebugDetailf("forumPerm: %+v\n", forumPerm)
DebugDetail("group.CanSee: ", group.CanSee) DebugDetail("canSee: ", canSee)
} }
DebugDetailf("group.CanSee (length %d): %+v \n", len(group.CanSee), group.CanSee) DebugDetailf("canSee (length %d): %+v \n", len(canSee), canSee)
gcache.SetCanSee(group.ID, canSee)
} }
TopicListThaw.Thaw() TopicListThaw.Thaw()
return nil return nil

View File

@ -31,6 +31,7 @@ type GroupStore interface {
type GroupCache interface { type GroupCache interface {
CacheSet(group *Group) error CacheSet(group *Group) error
SetCanSee(gid int, canSee []int) error
Length() int Length() int
} }
@ -158,12 +159,6 @@ func (s *MemoryGroupStore) Reload(id int) error {
return nil return nil
} }
// TODO: Do we really need this?
/*err = RebuildGroupPermissions(group)
if err != nil {
LogError(err)
return nil
}*/
s.CacheSet(group) s.CacheSet(group)
TopicListThaw.Thaw() TopicListThaw.Thaw()
return nil return nil
@ -199,6 +194,21 @@ func (s *MemoryGroupStore) initGroup(group *Group) error {
return nil return nil
} }
func (s *MemoryGroupStore) SetCanSee(gid int, canSee []int) error {
s.Lock()
group, ok := s.groups[gid]
if !ok {
s.Unlock()
return nil
}
ngroup := &Group{}
*ngroup = *group
ngroup.CanSee = canSee
s.groups[group.ID] = ngroup
s.Unlock()
return nil
}
func (s *MemoryGroupStore) CacheSet(group *Group) error { func (s *MemoryGroupStore) CacheSet(group *Group) error {
s.Lock() s.Lock()
s.groups[group.ID] = group s.groups[group.ID] = group
@ -216,7 +226,7 @@ func (s *MemoryGroupStore) Exists(gid int) bool {
// ? Allow two groups with the same name? // ? Allow two groups with the same name?
// TODO: Refactor this // TODO: Refactor this
func (mgs *MemoryGroupStore) Create(name string, tag string, isAdmin bool, isMod bool, isBanned bool) (gid int, err error) { func (s *MemoryGroupStore) Create(name string, tag string, isAdmin bool, isMod bool, isBanned bool) (gid int, err error) {
var permstr = "{}" var permstr = "{}"
tx, err := qgen.Builder.Begin() tx, err := qgen.Builder.Begin()
if err != nil { if err != nil {
@ -278,7 +288,6 @@ func (mgs *MemoryGroupStore) Create(name string, tag string, isAdmin bool, isMod
if err != nil { if err != nil {
return 0, err return 0, err
} }
err = tx.Commit() err = tx.Commit()
if err != nil { if err != nil {
return 0, err return 0, err
@ -289,10 +298,10 @@ func (mgs *MemoryGroupStore) Create(name string, tag string, isAdmin bool, isMod
isBanned = false isBanned = false
} }
mgs.Lock() s.Lock()
mgs.groups[gid] = &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}
mgs.groupCount++ s.groupCount++
mgs.Unlock() s.Unlock()
TopicListThaw.Thaw() TopicListThaw.Thaw()
return gid, FPStore.ReloadAll() return gid, FPStore.ReloadAll()

View File

@ -4,6 +4,7 @@ import (
"encoding/json" "encoding/json"
"sync" "sync"
"time" "time"
"log"
"github.com/gorilla/websocket" "github.com/gorilla/websocket"
) )
@ -38,6 +39,7 @@ func init() {
} }
func (hub *WsHubImpl) Start() { func (hub *WsHubImpl) Start() {
log.Print("Setting up the WebSocket ticks")
ticker := time.NewTicker(time.Minute * 5) ticker := time.NewTicker(time.Minute * 5)
defer func() { defer func() {
ticker.Stop() ticker.Stop()

View File

@ -52,6 +52,7 @@ func afterDBInit() (err error) {
if err != nil { if err != nil {
return err return err
} }
log.Print("Exitted storeInit")
var uids []int var uids []int
tcache := c.Topics.GetCache() tcache := c.Topics.GetCache()
@ -109,6 +110,7 @@ func afterDBInit() (err error) {
} }
} }
log.Print("Exitted afterDBInit")
return nil return nil
} }
@ -299,6 +301,8 @@ func storeInit() (err error) {
if err != nil { if err != nil {
return errors.WithStack(err) return errors.WithStack(err)
} }
log.Print("Initialising the meta store")
c.Meta, err = c.NewDefaultMetaStore(acc) c.Meta, err = c.NewDefaultMetaStore(acc)
if err != nil { if err != nil {
return errors.WithStack(err) return errors.WithStack(err)
@ -514,6 +518,7 @@ func main() {
log.Print("Initialising the plugins") log.Print("Initialising the plugins")
c.InitPlugins() c.InitPlugins()
log.Print("Setting up the signal handler")
sigs := make(chan os.Signal, 1) sigs := make(chan os.Signal, 1)
signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM) signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM)
go func() { go func() {

View File

@ -731,6 +731,56 @@ func TestForumPermsStore(t *testing.T) {
if !c.PluginsInited { if !c.PluginsInited {
c.InitPlugins() c.InitPlugins()
} }
var initialState = func() {
fid := 1
gid := 1
fperms, err := c.FPStore.Get(fid,gid)
expectNilErr(t,err)
expect(t,fperms.ViewTopic,"admins should be able to see reports")
fid = 1
gid = 2
fperms, err = c.FPStore.Get(fid,gid)
expectNilErr(t,err)
expect(t,fperms.ViewTopic,"mods should be able to see reports")
fid = 1
gid = 3
fperms, err = c.FPStore.Get(fid,gid)
expectNilErr(t,err)
expect(t,!fperms.ViewTopic,"members should not be able to see reports")
fid = 1
gid = 4
fperms, err = c.FPStore.Get(fid,gid)
expectNilErr(t,err)
expect(t,!fperms.ViewTopic,"banned users should not be able to see reports")
fid = 2
gid = 1
fperms, err = c.FPStore.Get(fid,gid)
expectNilErr(t,err)
expect(t,fperms.ViewTopic,"admins should be able to see general")
fid = 2
gid = 3
fperms, err = c.FPStore.Get(fid,gid)
expectNilErr(t,err)
expect(t,fperms.ViewTopic,"members should be able to see general")
fid = 2
gid = 6
fperms, err = c.FPStore.Get(fid,gid)
expectNilErr(t,err)
expect(t,fperms.ViewTopic,"guests should be able to see general")
}
initialState()
expectNilErr(t, c.FPStore.Reload(1))
initialState()
expectNilErr(t, c.FPStore.Reload(2))
initialState()
} }
// TODO: Test the group permissions // TODO: Test the group permissions
@ -833,8 +883,9 @@ func TestGroupStore(t *testing.T) {
expect(t, !group.IsAdmin, "This shouldn't be an admin group") expect(t, !group.IsAdmin, "This shouldn't be an admin group")
expect(t, group.IsMod, "This should be a mod group") expect(t, group.IsMod, "This should be a mod group")
expect(t, !group.IsBanned, "This shouldn't be a ban group") expect(t, !group.IsBanned, "This shouldn't be a ban group")
expect(t, group.CanSee!=nil, "group.CanSee must not be nil") expect(t, group.CanSee != nil, "group.CanSee must not be nil")
expect(t, len(group.CanSee) > 0, "group.CanSee should not be zero") expect(t, len(group.CanSee) == 1, "len(group.CanSee) should not be one")
expect(t, group.CanSee[0] == 2, "group.CanSee[0] should be 2")
canSee := group.CanSee canSee := group.CanSee
// Make sure the data is static // Make sure the data is static

View File

@ -9,7 +9,7 @@
<div class="rowblock topic_reply_form quick_create_form" aria-label="{{lang "topic.reply_aria"}}"> <div class="rowblock topic_reply_form quick_create_form" aria-label="{{lang "topic.reply_aria"}}">
<form id="quick_post_form" enctype="multipart/form-data" action="/reply/create/?session={{.CurrentUser.Session}}" method="post"></form> <form id="quick_post_form" enctype="multipart/form-data" action="/reply/create/?session={{.CurrentUser.Session}}" method="post"></form>
<input form="quick_post_form" name="tid" value='{{.Topic.ID}}' type="hidden" /> <input form="quick_post_form" name="tid" value='{{.Topic.ID}}' type="hidden" />
<input form="quick_post_form" id="has_poll_input" name="has_poll" value="0" type="hidden" /> <input form="quick_post_form" id="has_poll_input" name="has_poll" value=0 type="hidden" />
<div class="formrow real_first_child"> <div class="formrow real_first_child">
<div class="formitem"> <div class="formitem">
<textarea id="input_content" form="quick_post_form" name="reply-content" placeholder="{{lang "topic.reply_content_alt"}}" required></textarea> <textarea id="input_content" form="quick_post_form" name="reply-content" placeholder="{{lang "topic.reply_content_alt"}}" required></textarea>