Use Rstore.Exists() instead of Rstore.Get() in ReplyEditSubmit.

Reduce allocs in WsHubImpl.getUsers()
Reduce allocs in wolContextRender()
Use b.String() instead of string(b.Bytes()) in preparseWidget()
Reduce boilerplate.
This commit is contained in:
Azareal 2021-04-28 19:29:15 +10:00
parent 0c1f5cac94
commit ea4da062c3
5 changed files with 109 additions and 107 deletions

View File

@ -14,13 +14,16 @@ func wolContextRender(widget *Widget, hvars interface{}) (string, error) {
if ok { if ok {
ucount = len(topic) ucount = len(topic)
if ucount < 30 { if ucount < 30 {
users = make([]*User, len(topic))
i := 0
for wsUser, _ := range topic { for wsUser, _ := range topic {
users = append(users, wsUser.User) users[i] = wsUser.User
i++
} }
} }
} }
topicMutex.RUnlock() topicMutex.RUnlock()
wol := &wolUsers{header, phrases.GetTmplPhrase("widget.online_view_topic_name"), users, ucount} wol := &wolUsers{header, phrases.GetTmplPhrase("widget.online_view_topic_name"), users, ucount}
err := header.Theme.RunTmpl("widget_online", wol, header.Writer) e := header.Theme.RunTmpl("widget_online", wol, header.Writer)
return "", err return "", e
} }

View File

@ -49,15 +49,15 @@ type NameTextPair struct {
Text template.HTML Text template.HTML
} }
func preparseWidget(w *Widget, wdata string) (err error) { func preparseWidget(w *Widget, wdata string) (e error) {
prebuildWidget := func(name string, data interface{}) (string, error) { prebuildWidget := func(name string, data interface{}) (string, error) {
var b bytes.Buffer var b bytes.Buffer
err := DefaultTemplates.ExecuteTemplate(&b, name+".html", data) e := DefaultTemplates.ExecuteTemplate(&b, name+".html", data)
content := string(b.Bytes()) content := b.String()
if Config.MinifyTemplates { if Config.MinifyTemplates {
content = min.Minify(content) content = min.Minify(content)
} }
return content, err return content, e
} }
sbytes := []byte(wdata) sbytes := []byte(wdata)
@ -66,11 +66,11 @@ func preparseWidget(w *Widget, wdata string) (err error) {
switch w.Type { switch w.Type {
case "simple", "about": case "simple", "about":
var tmp NameTextPair var tmp NameTextPair
err = json.Unmarshal(sbytes, &tmp) e = json.Unmarshal(sbytes, &tmp)
if err != nil { if e != nil {
return err return e
} }
w.Body, err = prebuildWidget("widget_"+w.Type, tmp) w.Body, e = prebuildWidget("widget_"+w.Type, tmp)
case "search_and_filter": case "search_and_filter":
w.Literal = false w.Literal = false
w.BuildFunc = widgetSearchAndFilter w.BuildFunc = widgetSearchAndFilter
@ -88,9 +88,12 @@ func preparseWidget(w *Widget, wdata string) (err error) {
// TODO: Test this // TODO: Test this
// TODO: Should we toss this through a proper parser rather than crudely replacing it? // TODO: Should we toss this through a proper parser rather than crudely replacing it?
w.Location = strings.Replace(w.Location, " ", "", -1) rep := func(from, to string) {
w.Location = strings.Replace(w.Location, "frontend", "!panel", -1) w.Location = strings.Replace(w.Location, from, to, -1)
w.Location = strings.Replace(w.Location, "!!", "", -1) }
rep(" ", "")
rep("frontend", "!panel")
rep("!!", "")
// Skip blank zones // Skip blank zones
locs := strings.Split(w.Location, "|") locs := strings.Split(w.Location, "|")
@ -105,7 +108,7 @@ func preparseWidget(w *Widget, wdata string) (err error) {
w.Location = w.Location[:len(w.Location)-1] w.Location = w.Location[:len(w.Location)-1]
} }
return err return e
} }
func GetDockList() []string { func GetDockList() []string {
@ -193,11 +196,11 @@ func BuildWidget(dock string, h *Header) (sbody string) {
widgets = Docks.RightOfNav widgets = Docks.RightOfNav
case "topMenu": case "topMenu":
// 1 = id for the default menu // 1 = id for the default menu
mhold, err := Menus.Get(1) mhold, e := Menus.Get(1)
if err == nil { if e == nil {
err := mhold.Build(h.Writer, h.CurrentUser, h.Path) e := mhold.Build(h.Writer, h.CurrentUser, h.Path)
if err != nil { if e != nil {
LogError(err) LogError(e)
} }
} }
return "" return ""
@ -212,9 +215,9 @@ func BuildWidget(dock string, h *Header) (sbody string) {
continue continue
} }
if widget.Allowed(h.Zone, h.ZoneID) { if widget.Allowed(h.Zone, h.ZoneID) {
item, err := widget.Build(h) item, e := widget.Build(h)
if err != nil { if e != nil {
LogError(err) LogError(e)
} }
sbody += item sbody += item
} }
@ -248,11 +251,11 @@ func BuildWidget2(dock int, h *Header) (sbody string) {
widgets = Docks.RightOfNav widgets = Docks.RightOfNav
case 2: case 2:
// 1 = id for the default menu // 1 = id for the default menu
mhold, err := Menus.Get(1) mhold, e := Menus.Get(1)
if err == nil { if e == nil {
err := mhold.Build(h.Writer, h.CurrentUser, h.Path) e := mhold.Build(h.Writer, h.CurrentUser, h.Path)
if err != nil { if e != nil {
LogError(err) LogError(e)
} }
} }
return "" return ""
@ -267,9 +270,9 @@ func BuildWidget2(dock int, h *Header) (sbody string) {
continue continue
} }
if w.Allowed(h.Zone, h.ZoneID) { if w.Allowed(h.Zone, h.ZoneID) {
item, err := w.Build(h) item, e := w.Build(h)
if err != nil { if e != nil {
LogError(err) LogError(e)
} }
sbody += item sbody += item
} }
@ -314,9 +317,9 @@ func BuildWidget3(dock int, h *Header) {
continue continue
} }
if w.Allowed(h.Zone, h.ZoneID) { if w.Allowed(h.Zone, h.ZoneID) {
item, err := w.Build(h) item, e := w.Build(h)
if err != nil { if e != nil {
LogError(err) LogError(e)
} }
if item != "" { if item != "" {
h.Writer.Write(uutils.StringToBytes(item)) h.Writer.Write(uutils.StringToBytes(item))
@ -362,23 +365,22 @@ func HasWidgets2(dock int, h *Header) bool {
return wcount > 0 return wcount > 0
} }
func getDockWidgets(dock string) (widgets []*Widget, err error) { func getDockWidgets(dock string) (widgets []*Widget, e error) {
rows, err := widgetStmts.getDockList.Query(dock) rows, e := widgetStmts.getDockList.Query(dock)
if err != nil { if e != nil {
return nil, err return nil, e
} }
defer rows.Close() defer rows.Close()
for rows.Next() { for rows.Next() {
w := &Widget{Position: 0, Side: dock} w := &Widget{Position: 0, Side: dock}
err = rows.Scan(&w.ID, &w.Position, &w.Type, &w.Enabled, &w.Location, &w.RawBody) e = rows.Scan(&w.ID, &w.Position, &w.Type, &w.Enabled, &w.Location, &w.RawBody)
if err != nil { if e != nil {
return nil, err return nil, e
} }
e = preparseWidget(w, w.RawBody)
err = preparseWidget(w, w.RawBody) if e != nil {
if err != nil { return nil, e
return nil, err
} }
Widgets.set(w) Widgets.set(w)
widgets = append(widgets, w) widgets = append(widgets, w)
@ -393,9 +395,9 @@ func InitWidgets() (fi error) {
if fi != nil { if fi != nil {
return return
} }
dock, err := getDockWidgets(name) dock, e := getDockWidgets(name)
if err != nil { if e != nil {
fi = err fi = e
return return
} }
setDock(name, dock) setDock(name, dock)
@ -484,9 +486,9 @@ func (s *WidgetScheduler) Tick() error {
if widget.TickFunc == nil { if widget.TickFunc == nil {
continue continue
} }
err := widget.TickFunc(widget) e := widget.TickFunc(widget)
if err != nil { if e != nil {
return errors.WithStack(err) return errors.WithStack(e)
} }
} }
return nil return nil

View File

@ -51,8 +51,8 @@ func (h *WsHubImpl) Start() {
l.RLock() l.RLock()
defer l.RUnlock() defer l.RUnlock()
// TODO: Copy to temporary slice for less contention? // TODO: Copy to temporary slice for less contention?
for _, user := range userMap { for _, u := range userMap {
user.Ping() u.Ping()
} }
} }
select { select {
@ -135,19 +135,19 @@ func wsTopicListTick(h *WsHubImpl) error {
groups := make(map[int]*Group) groups := make(map[int]*Group)
canSeeMap := make(map[string][]int) canSeeMap := make(map[string][]int)
for groupID, _ := range groupIDs { for gid, _ := range groupIDs {
group, err := Groups.Get(groupID) g, err := Groups.Get(gid)
if err != nil { if err != nil {
// TODO: Do we really want to halt all pushes for what is possibly just one user? // TODO: Do we really want to halt all pushes for what is possibly just one user?
return err return err
} }
groups[group.ID] = group groups[g.ID] = g
canSee := make([]byte, len(group.CanSee)) canSee := make([]byte, len(g.CanSee))
for i, item := range group.CanSee { for i, item := range g.CanSee {
canSee[i] = byte(item) canSee[i] = byte(item)
} }
canSeeMap[string(canSee)] = group.CanSee canSeeMap[string(canSee)] = g.CanSee
} }
canSeeRenders := make(map[string][]byte) canSeeRenders := make(map[string][]byte)
@ -213,11 +213,11 @@ func wsTopicListTick(h *WsHubImpl) error {
modSet = make(map[int]int, len(l)) modSet = make(map[int]int, len(l))
for i, t := range l { for i, t := range l {
// TODO: Abstract this? // TODO: Abstract this?
fp, err := FPStore.Get(t.ParentID, u.Group) fp, e := FPStore.Get(t.ParentID, u.Group)
if err == ErrNoRows { if e == ErrNoRows {
fp = BlankForumPerms() fp = BlankForumPerms()
} else if err != nil { } else if e != nil {
return err return e
} }
var ccanMod, ccanLock, ccanMove bool var ccanMod, ccanLock, ccanMove bool
if fp.Overrides { if fp.Overrides {
@ -329,17 +329,17 @@ func (h *WsHubImpl) broadcastMessage(msg string) error {
m.RLock() m.RLock()
defer m.RUnlock() defer m.RUnlock()
for _, wsUser := range users { for _, wsUser := range users {
err := wsUser.WriteAll(msg) e := wsUser.WriteAll(msg)
if err != nil { if e != nil {
return err return e
} }
} }
return nil return nil
} }
// TODO: Can we move this RLock inside the closure safely? // TODO: Can we move this RLock inside the closure safely?
err := userLoop(h.evenOnlineUsers, &h.evenUserLock) e := userLoop(h.evenOnlineUsers, &h.evenUserLock)
if err != nil { if e != nil {
return err return e
} }
return userLoop(h.oddOnlineUsers, &h.oddUserLock) return userLoop(h.oddOnlineUsers, &h.oddUserLock)
} }
@ -366,12 +366,15 @@ func (h *WsHubImpl) getUsers(uids []int) (wsUsers []*WSUser, err error) {
if len(uids) == 0 { if len(uids) == 0 {
return nil, errWsNouser return nil, errWsNouser
} }
wsUsers = make([]*WSUser, len(uids))
i := 0
appender := func(l *sync.RWMutex, users map[int]*WSUser) { appender := func(l *sync.RWMutex, users map[int]*WSUser) {
l.RLock() l.RLock()
defer l.RUnlock() defer l.RUnlock()
// We don't want to keep a lock on this for too long, so we'll accept some nil pointers // We don't want to keep a lock on this for too long, so we'll accept some nil pointers
for _, uid := range uids { for _, uid := range uids {
wsUsers = append(wsUsers, users[uid]) wsUsers[i] = users[uid]
i++
} }
} }
appender(&h.evenUserLock, h.evenOnlineUsers) appender(&h.evenUserLock, h.evenOnlineUsers)
@ -387,8 +390,8 @@ func (h *WsHubImpl) AllUsers() (users []*User) {
appender := func(l *sync.RWMutex, userMap map[int]*WSUser) { appender := func(l *sync.RWMutex, userMap map[int]*WSUser) {
l.RLock() l.RLock()
defer l.RUnlock() defer l.RUnlock()
for _, user := range userMap { for _, u := range userMap {
users = append(users, user.User) users = append(users, u.User)
} }
} }
appender(&h.evenUserLock, h.evenOnlineUsers) appender(&h.evenUserLock, h.evenOnlineUsers)
@ -461,26 +464,26 @@ func (h *WsHubImpl) RemoveConn(wsUser *WSUser, conn *websocket.Conn) {
} }
func (h *WsHubImpl) PushMessage(targetUser int, msg string) error { func (h *WsHubImpl) PushMessage(targetUser int, msg string) error {
wsUser, err := h.getUser(targetUser) wsUser, e := h.getUser(targetUser)
if err != nil { if e != nil {
return err return e
} }
return wsUser.WriteAll(msg) return wsUser.WriteAll(msg)
} }
func (h *WsHubImpl) pushAlert(targetUser int, alert Alert) error { func (h *WsHubImpl) pushAlert(targetUser int, a Alert) error {
wsUser, err := h.getUser(targetUser) wsUser, e := h.getUser(targetUser)
if err != nil { if e != nil {
return err return e
} }
astr, err := BuildAlert(alert, *wsUser.User) astr, e := BuildAlert(a, *wsUser.User)
if err != nil { if e != nil {
return err return e
} }
return wsUser.WriteAll(astr) return wsUser.WriteAll(astr)
} }
func (h *WsHubImpl) pushAlerts(users []int, alert Alert) error { func (h *WsHubImpl) pushAlerts(users []int, a Alert) error {
wsUsers, err := h.getUsers(users) wsUsers, err := h.getUsers(users)
if err != nil { if err != nil {
return err return err
@ -491,7 +494,7 @@ func (h *WsHubImpl) pushAlerts(users []int, alert Alert) error {
if wsUser == nil { if wsUser == nil {
continue continue
} }
alert, err := BuildAlert(alert, *wsUser.User) alert, err := BuildAlert(a, *wsUser.User)
if err != nil { if err != nil {
errs = append(errs, err) errs = append(errs, err)
} }
@ -503,8 +506,8 @@ func (h *WsHubImpl) pushAlerts(users []int, alert Alert) error {
// Return the first error // Return the first error
if len(errs) != 0 { if len(errs) != 0 {
for _, err := range errs { for _, e := range errs {
return err return e
} }
} }
return nil return nil

View File

@ -88,9 +88,8 @@ func PollResults(w http.ResponseWriter, r *http.Request, u *c.User, sPollID stri
optList := "" optList := ""
var votes int var votes int
for rows.Next() { for rows.Next() {
err := rows.Scan(&votes) if e := rows.Scan(&votes); e != nil {
if err != nil { return c.InternalError(e, w, r)
return c.InternalError(err, w, r)
} }
optList += strconv.Itoa(votes) + "," optList += strconv.Itoa(votes) + ","
} }

View File

@ -225,13 +225,8 @@ func ReplyEditSubmit(w http.ResponseWriter, r *http.Request, u *c.User, srid str
} else if err != nil { } else if err != nil {
return c.InternalErrorJSQ(err, w, r, js) return c.InternalErrorJSQ(err, w, r, js)
} }
if !c.Rstore.Exists(reply.ID) {
// TODO: Avoid the load to get this faster?
reply, err = c.Rstore.Get(reply.ID)
if err == sql.ErrNoRows {
return c.PreErrorJSQ("The updated reply doesn't exist.", w, r, js) return c.PreErrorJSQ("The updated reply doesn't exist.", w, r, js)
} else if err != nil {
return c.InternalErrorJSQ(err, w, r, js)
} }
skip, rerr := lite.Hooks.VhookSkippable("action_end_edit_reply", reply.ID, u) skip, rerr := lite.Hooks.VhookSkippable("action_end_edit_reply", reply.ID, u)
@ -265,8 +260,8 @@ func ReplyDeleteSubmit(w http.ResponseWriter, r *http.Request, u *c.User, srid s
return c.NoPermissionsJSQ(w, r, u, js) return c.NoPermissionsJSQ(w, r, u, js)
} }
} }
if err := reply.Delete(); err != nil { if e := reply.Delete(); e != nil {
return c.InternalErrorJSQ(err, w, r, js) return c.InternalErrorJSQ(e, w, r, js)
} }
skip, rerr := lite.Hooks.VhookSkippable("action_end_delete_reply", reply.ID, u) skip, rerr := lite.Hooks.VhookSkippable("action_end_delete_reply", reply.ID, u)
@ -282,19 +277,19 @@ func ReplyDeleteSubmit(w http.ResponseWriter, r *http.Request, u *c.User, srid s
} }
// ? - What happens if an error fires after a redirect...? // ? - What happens if an error fires after a redirect...?
/*creator, err := c.Users.Get(reply.CreatedBy) /*creator, e := c.Users.Get(reply.CreatedBy)
if err == nil { if e == nil {
err = creator.DecreasePostStats(c.WordCount(reply.Content), false) e = creator.DecreasePostStats(c.WordCount(reply.Content), false)
if err != nil { if e != nil {
return c.InternalErrorJSQ(err, w, r, js) return c.InternalErrorJSQ(e, w, r, js)
} }
} else if err != sql.ErrNoRows { } else if e != sql.ErrNoRows {
return c.InternalErrorJSQ(err, w, r, js) return c.InternalErrorJSQ(e, w, r, js)
}*/ }*/
err := c.ModLogs.Create("delete", reply.ParentID, "reply", u.GetIP(), u.ID) e := c.ModLogs.Create("delete", reply.ParentID, "reply", u.GetIP(), u.ID)
if err != nil { if e != nil {
return c.InternalErrorJSQ(err, w, r, js) return c.InternalErrorJSQ(e, w, r, js)
} }
return nil return nil
} }