You can now filter the active memory pane by type.

Add excludes for the analytics language pane too.
Try to avoid rid queries when we already have the rids.
Use GetListByCanSee instead of GetList for preloads to increase the chances of getting something useful.
Provisionally extend topic preloading to the first three topic list pages.

Add the panel_statistics_memory_type_total phrase.
Add the panel_statistics_memory_type_stack phrase.
Add the panel_statistics_memory_type_heap phrase.
This commit is contained in:
Azareal 2019-05-19 11:01:11 +10:00
parent 8a719bd13d
commit a56ed113dd
13 changed files with 122 additions and 35 deletions

View File

@ -307,6 +307,14 @@ type PanelAnalyticsStdUnit struct {
Unit string Unit string
TimeType string TimeType string
} }
type PanelAnalyticsActiveMemory struct {
Graph PanelTimeGraph
ViewItems []PanelAnalyticsItemUnit
TimeRange string
Unit string
TimeType string
MemType int
}
type PanelStats struct { type PanelStats struct {
Users int Users int

View File

@ -252,7 +252,7 @@ func compileCommons(c *tmpl.CTemplateSet, header *Header, header2 *Header, out T
var replyList []*ReplyUser var replyList []*ReplyUser
reply := Reply{1, 1, "Yo!", 1, Config.DefaultGroup, now, 0, 0, 1, "::1", true, 1, 1, ""} reply := Reply{1, 1, "Yo!", 1, Config.DefaultGroup, now, 0, 0, 1, "::1", true, 1, 1, ""}
ru := &ReplyUser{ClassName: "", Reply: reply, CreatedByName: "Alice", Avatar: avatar, URLPrefix: "", URLName: "", Level: 0, Attachments: miniAttach} ru := &ReplyUser{ClassName: "", Reply: reply, CreatedByName: "Alice", Avatar: avatar, URLPrefix: "", URLName: "", Level: 0, Attachments: miniAttach}
ru.Init(topic.ID) ru.Init()
replyList = append(replyList, ru) replyList = append(replyList, ru)
tpage := TopicPage{htitle("Topic Name"), replyList, topic, &Forum{ID: 1, Name: "Hahaha"}, poll, Paginator{[]int{1}, 1, 1}} tpage := TopicPage{htitle("Topic Name"), replyList, topic, &Forum{ID: 1, Name: "Hahaha"}, poll, Paginator{[]int{1}, 1, 1}}
tpage.Forum.Link = BuildForumURL(NameToSlug(tpage.Forum.Name), tpage.Forum.ID) tpage.Forum.Link = BuildForumURL(NameToSlug(tpage.Forum.Name), tpage.Forum.ID)
@ -268,19 +268,19 @@ func compileTemplates(wg *sync.WaitGroup, c *tmpl.CTemplateSet, themeName string
header, header2, _ := tmplInitHeaders(user, user2, user3) header, header2, _ := tmplInitHeaders(user, user2, user3)
now := time.Now() now := time.Now()
poll := Poll{ID: 1, Type: 0, Options: map[int]string{0: "Nothing", 1: "Something"}, Results: map[int]int{0: 5, 1: 2}, QuickOptions: []PollOption{ /*poll := Poll{ID: 1, Type: 0, Options: map[int]string{0: "Nothing", 1: "Something"}, Results: map[int]int{0: 5, 1: 2}, QuickOptions: []PollOption{
PollOption{0, "Nothing"}, PollOption{0, "Nothing"},
PollOption{1, "Something"}, PollOption{1, "Something"},
}, VoteCount: 7} }, VoteCount: 7}*/
avatar, microAvatar := BuildAvatar(62, "") //avatar, microAvatar := BuildAvatar(62, "")
miniAttach := []*MiniAttachment{&MiniAttachment{Path: "/"}} miniAttach := []*MiniAttachment{&MiniAttachment{Path: "/"}}
var replyList []*ReplyUser var replyList []*ReplyUser
topic := TopicUser{1, "blah", "Blah", "Hey there!", 0, false, false, now, now, 1, 1, 0, "", "127.0.0.1", 1, 0, 1, 0, "classname", poll.ID, "weird-data", BuildProfileURL("fake-user", 62), "Fake User", Config.DefaultGroup, avatar, microAvatar, 0, "", "", "", "", "", 58, false, miniAttach, nil} //topic := TopicUser{1, "blah", "Blah", "Hey there!", 0, false, false, now, now, 1, 1, 0, "", "127.0.0.1", 1, 0, 1, 0, "classname", poll.ID, "weird-data", BuildProfileURL("fake-user", 62), "Fake User", Config.DefaultGroup, avatar, microAvatar, 0, "", "", "", "", "", 58, false, miniAttach, nil}
// TODO: Do we want the UID on this to be 0? // TODO: Do we want the UID on this to be 0?
avatar, microAvatar = BuildAvatar(0, "") //avatar, microAvatar = BuildAvatar(0, "")
reply := Reply{1, 1, "Yo!", 1, Config.DefaultGroup, now, 0, 0, 1, "::1", true, 1, 1, ""} reply := Reply{1, 1, "Yo!", 1, Config.DefaultGroup, now, 0, 0, 1, "::1", true, 1, 1, ""}
ru := &ReplyUser{ClassName: "", Reply: reply, CreatedByName: "Alice", Avatar: avatar, URLPrefix: "", URLName: "", Level: 0, Attachments: miniAttach} ru := &ReplyUser{ClassName: "", Reply: reply, CreatedByName: "Alice", Avatar: "", URLPrefix: "", URLName: "", Level: 0, Attachments: miniAttach}
ru.Init(topic.ID) ru.Init()
replyList = append(replyList, ru) replyList = append(replyList, ru)
// Convienience function to save a line here and there // Convienience function to save a line here and there
@ -477,7 +477,7 @@ func compileJSTemplates(wg *sync.WaitGroup, c *tmpl.CTemplateSet, themeName stri
avatar, microAvatar = BuildAvatar(0, "") avatar, microAvatar = BuildAvatar(0, "")
reply := Reply{1, 1, "Yo!", 1, Config.DefaultGroup, now, 0, 0, 1, "::1", true, 1, 1, ""} reply := Reply{1, 1, "Yo!", 1, Config.DefaultGroup, now, 0, 0, 1, "::1", true, 1, 1, ""}
ru := &ReplyUser{ClassName: "", Reply: reply, CreatedByName: "Alice", Avatar: avatar, URLPrefix: "", URLName: "", Level: 0, Attachments: miniAttach} ru := &ReplyUser{ClassName: "", Reply: reply, CreatedByName: "Alice", Avatar: avatar, URLPrefix: "", URLName: "", Level: 0, Attachments: miniAttach}
ru.Init(topic.ID) ru.Init()
replyList = append(replyList, ru) replyList = append(replyList, ru)
varList = make(map[string]tmpl.VarItem) varList = make(map[string]tmpl.VarItem)

View File

@ -422,9 +422,8 @@ func GetRidsForTopic(tid int, offset int) (rids []int, err error) {
return rids, rows.Err() return rids, rows.Err()
} }
func (ru *ReplyUser) Init(parentID int) error { func (ru *ReplyUser) Init() error {
ru.UserLink = BuildProfileURL(NameToSlug(ru.CreatedByName), ru.CreatedBy) ru.UserLink = BuildProfileURL(NameToSlug(ru.CreatedByName), ru.CreatedBy)
ru.ParentID = parentID
ru.ContentLines = strings.Count(ru.Content, "\n") ru.ContentLines = strings.Count(ru.Content, "\n")
postGroup, err := Groups.Get(ru.Group) postGroup, err := Groups.Get(ru.Group)
@ -516,7 +515,7 @@ func (topic *TopicUser) Replies(offset int, pFrag int, user *User) (rlist []*Rep
//log.Print("reply cached serve") //log.Print("reply cached serve")
reply = &ReplyUser{ClassName: "", Reply: *re, CreatedByName: ruser.Name, Avatar: ruser.Avatar, URLPrefix: ruser.URLPrefix, URLName: ruser.URLName, Level: ruser.Level} reply = &ReplyUser{ClassName: "", Reply: *re, CreatedByName: ruser.Name, Avatar: ruser.Avatar, URLPrefix: ruser.URLPrefix, URLName: ruser.URLName, Level: ruser.Level}
err := reply.Init(topic.ID) err := reply.Init()
if err != nil { if err != nil {
return nil, "", err return nil, "", err
} }
@ -554,7 +553,7 @@ func (topic *TopicUser) Replies(offset int, pFrag int, user *User) (rlist []*Rep
return nil, "", err return nil, "", err
} }
err = reply.Init(topic.ID) err = reply.Init()
if err != nil { if err != nil {
return nil, "", err return nil, "", err
} }
@ -596,8 +595,8 @@ func (topic *TopicUser) Replies(offset int, pFrag int, user *User) (rlist []*Rep
} }
defer rows.Close() defer rows.Close()
for rows.Next() {
var likeRid int var likeRid int
for rows.Next() {
err := rows.Scan(&likeRid) err := rows.Scan(&likeRid)
if err != nil { if err != nil {
return nil, "", err return nil, "", err

View File

@ -2,6 +2,7 @@ package common
import ( import (
//"log" //"log"
"database/sql"
"strconv" "strconv"
"sync" "sync"
@ -308,7 +309,16 @@ func (tList *DefaultTopicList) getList(page int, orderby string, argList []inter
//log.Print("rcap: ", rcap) //log.Print("rcap: ", rcap)
//log.Print("topic.PostCount: ", topic.PostCount) //log.Print("topic.PostCount: ", topic.PostCount)
//log.Print("topic.PostCount == 2 && rlen < rcap: ", topic.PostCount == 2 && rlen < rcap) //log.Print("topic.PostCount == 2 && rlen < rcap: ", topic.PostCount == 2 && rlen < rcap)
if topic.PostCount == 2 && rlen < rcap {
// Avoid the extra queries on topic list pages, if we already have what we want...
var hRids = false
if tcache != nil {
if t, err := tcache.Get(topic.ID); err == nil {
hRids = len(t.Rids) != 0
}
}
if topic.PostCount == 2 && rlen < rcap && !hRids && page < 5 {
rids, err := GetRidsForTopic(topic.ID, 0) rids, err := GetRidsForTopic(topic.ID, 0)
if err != nil { if err != nil {
return nil, Paginator{nil, 1, 1}, err return nil, Paginator{nil, 1, 1}, err
@ -324,9 +334,11 @@ func (tList *DefaultTopicList) getList(page int, orderby string, argList []inter
} }
if tcache != nil { if tcache != nil {
if _, err := tcache.Get(topic.ID); err == sql.ErrNoRows {
_ = tcache.Set(topic.Topic()) _ = tcache.Set(topic.Topic())
} }
} }
}
err = rows.Err() err = rows.Err()
if err != nil { if err != nil {
return nil, Paginator{nil, 1, 1}, err return nil, Paginator{nil, 1, 1}, err

View File

@ -889,6 +889,9 @@
"panel_statistics_spam_hide":"Hide Spam", "panel_statistics_spam_hide":"Hide Spam",
"panel_statistics_spam_show":"Show Spam", "panel_statistics_spam_show":"Show Spam",
"panel_statistics_memory_type_total":"Total",
"panel_statistics_memory_type_stack":"Stack",
"panel_statistics_memory_type_heap":"Heap",
"panel_statistics_time_range_one_year":"1 year", "panel_statistics_time_range_one_year":"1 year",
"panel_statistics_time_range_three_months":"3 months", "panel_statistics_time_range_three_months":"3 months",

35
main.go
View File

@ -64,17 +64,40 @@ func afterDBInit() (err error) {
count = 0 count = 0
} }
} }
group, err := c.Groups.Get(c.GuestUser.Group)
// TODO: Use the same cached data for both the topic list and the topic fetches...
tList, _, _, err := c.TopicList.GetList(1, "", nil)
if err != nil { if err != nil {
return err return err
} }
if count > len(tList) {
count = len(tList) // TODO: Use the same cached data for both the topic list and the topic fetches...
tList, _, _, err := c.TopicList.GetListByCanSee(group.CanSee, 1, "", nil)
if err != nil {
return err
}
ctList := make([]*c.TopicsRow, len(tList))
copy(ctList, tList)
tList, _, _, err = c.TopicList.GetListByCanSee(group.CanSee, 2, "", nil)
if err != nil {
return err
}
for _, tItem := range tList {
ctList = append(ctList, tItem)
}
tList, _, _, err = c.TopicList.GetListByCanSee(group.CanSee, 3, "", nil)
if err != nil {
return err
}
for _, tItem := range tList {
ctList = append(ctList, tItem)
}
if count > len(ctList) {
count = len(ctList)
} }
for i := 0; i < count; i++ { for i := 0; i < count; i++ {
_, _ = c.Topics.Get(tList[i].ID) _, _ = c.Topics.Get(ctList[i].ID)
} }
} }

View File

@ -158,7 +158,7 @@ func analyticsRowsToAverageMap(rows *sql.Rows, labelList []int64, avgMap map[int
return avgMap, rows.Err() return avgMap, rows.Err()
} }
func analyticsRowsToAverageMap2(rows *sql.Rows, labelList []int64, avgMap map[int64]int64) (map[int64]int64, error) { func analyticsRowsToAverageMap2(rows *sql.Rows, labelList []int64, avgMap map[int64]int64, typ int) (map[int64]int64, error) {
defer rows.Close() defer rows.Close()
for rows.Next() { for rows.Next() {
var stack, heap int64 var stack, heap int64
@ -175,6 +175,11 @@ func analyticsRowsToAverageMap2(rows *sql.Rows, labelList []int64, avgMap map[in
log.Print("createdAt: ", createdAt) log.Print("createdAt: ", createdAt)
log.Print("unixCreatedAt: ", unixCreatedAt) log.Print("unixCreatedAt: ", unixCreatedAt)
} }
if typ == 1 {
heap = 0
} else if typ == 2 {
stack = 0
}
var pAvgMap = make(map[int64]pAvg) var pAvgMap = make(map[int64]pAvg)
for _, value := range labelList { for _, value := range labelList {
if unixCreatedAt > value { if unixCreatedAt > value {
@ -589,7 +594,17 @@ func AnalyticsActiveMemory(w http.ResponseWriter, r *http.Request, user c.User)
if err != nil && err != sql.ErrNoRows { if err != nil && err != sql.ErrNoRows {
return c.InternalError(err, w, r) return c.InternalError(err, w, r)
} }
avgMap, err = analyticsRowsToAverageMap2(rows, labelList, avgMap)
var typ int
switch r.FormValue("mtype") {
case "1":
typ = 1
case "2":
typ = 2
default:
typ = 0
}
avgMap, err = analyticsRowsToAverageMap2(rows, labelList, avgMap, typ)
if err != nil { if err != nil {
return c.InternalError(err, w, r) return c.InternalError(err, w, r)
} }
@ -604,7 +619,7 @@ func AnalyticsActiveMemory(w http.ResponseWriter, r *http.Request, user c.User)
} }
graph := c.PanelTimeGraph{Series: [][]int64{avgList}, Labels: labelList} graph := c.PanelTimeGraph{Series: [][]int64{avgList}, Labels: labelList}
c.DebugLogf("graph: %+v\n", graph) c.DebugLogf("graph: %+v\n", graph)
pi := c.PanelAnalyticsStdUnit{graph, avgItems, timeRange.Range, timeRange.Unit, "time"} pi := c.PanelAnalyticsActiveMemory{graph, avgItems, timeRange.Range, timeRange.Unit, "time", typ}
return renderTemplate("panel", w, r, basePage.Header, c.Panel{basePage, "panel_analytics_right", "analytics", "panel_analytics_active_memory", pi}) return renderTemplate("panel", w, r, basePage.Header, c.Panel{basePage, "panel_analytics_right", "analytics", "panel_analytics_active_memory", pi})
} }
@ -1012,19 +1027,35 @@ func AnalyticsLanguages(w http.ResponseWriter, r *http.Request, user c.User) c.R
} }
ovList := analyticsVMapToOVList(vMap) ovList := analyticsVMapToOVList(vMap)
ex := strings.Split(r.FormValue("ex"), ",")
var inEx = func(name string) bool {
for _, e := range ex {
if e == name {
return true
}
}
return false
}
var vList [][]int64 var vList [][]int64
var legendList []string var legendList []string
var i int var i int
for _, ovitem := range ovList { for _, ovitem := range ovList {
if inEx(ovitem.name) {
continue
}
lName, ok := phrases.GetHumanLangPhrase(ovitem.name)
if !ok {
lName = ovitem.name
}
if inEx(lName) {
continue
}
var viewList []int64 var viewList []int64
for _, value := range revLabelList { for _, value := range revLabelList {
viewList = append(viewList, ovitem.viewMap[value]) viewList = append(viewList, ovitem.viewMap[value])
} }
vList = append(vList, viewList) vList = append(vList, viewList)
lName, ok := phrases.GetHumanLangPhrase(ovitem.name)
if !ok {
lName = ovitem.name
}
legendList = append(legendList, lName) legendList = append(legendList, lName)
if i >= 6 { if i >= 6 {
break break
@ -1038,10 +1069,16 @@ func AnalyticsLanguages(w http.ResponseWriter, r *http.Request, user c.User) c.R
// TODO: Sort this slice // TODO: Sort this slice
var langItems []c.PanelAnalyticsAgentsItem var langItems []c.PanelAnalyticsAgentsItem
for lang, count := range langMap { for lang, count := range langMap {
if inEx(lang) {
continue
}
lLang, ok := phrases.GetHumanLangPhrase(lang) lLang, ok := phrases.GetHumanLangPhrase(lang)
if !ok { if !ok {
lLang = lang lLang = lang
} }
if inEx(lLang) {
continue
}
langItems = append(langItems, c.PanelAnalyticsAgentsItem{ langItems = append(langItems, c.PanelAnalyticsAgentsItem{
Agent: lang, Agent: lang,
FriendlyAgent: lLang, FriendlyAgent: lLang,

View File

@ -79,8 +79,8 @@ func ViewProfile(w http.ResponseWriter, r *http.Request, user c.User, header *c.
replyLiked := false replyLiked := false
replyLikeCount := 0 replyLikeCount := 0
ru := &c.ReplyUser{Reply: c.Reply{rid, 0, replyContent, replyCreatedBy, replyGroup, replyCreatedAt, replyLastEdit, replyLastEditBy, 0, "", replyLiked, replyLikeCount, 0, ""}, ContentHtml: c.ParseMessage(replyContent, 0, ""), CreatedByName: replyCreatedByName, Avatar: replyAvatar, Level: 0} ru := &c.ReplyUser{Reply: c.Reply{rid, puser.ID, replyContent, replyCreatedBy, replyGroup, replyCreatedAt, replyLastEdit, replyLastEditBy, 0, "", replyLiked, replyLikeCount, 0, ""}, ContentHtml: c.ParseMessage(replyContent, 0, ""), CreatedByName: replyCreatedByName, Avatar: replyAvatar, Level: 0}
ru.Init(puser.ID) ru.Init()
group, err := c.Groups.Get(ru.Group) group, err := c.Groups.Get(ru.Group)
if err != nil { if err != nil {

View File

@ -1,6 +1,11 @@
<div class="colstack_item colstack_head"> <div class="colstack_item colstack_head">
<div class="rowitem"> <div class="rowitem">
<h1>{{lang "panel_statistics_active_memory_head"}}</h1> <h1>{{lang "panel_statistics_active_memory_head"}}</h1>
<select form="timeRangeForm" class="typeSelector to_right autoSubmitRedirect" name="mtype">
<option val="0"{{if eq .MemType 0}} selected{{end}}>{{lang "panel_statistics_memory_type_total"}}</option>
<option val="1"{{if eq .MemType 1}} selected{{end}}>{{lang "panel_statistics_memory_type_stack"}}</option>
<option val="2"{{if eq .MemType 2}} selected{{end}}>{{lang "panel_statistics_memory_type_heap"}}</option>
</select>
{{template "panel_analytics_time_range_month.html" . }} {{template "panel_analytics_time_range_month.html" . }}
</div> </div>
</div> </div>

View File

@ -357,7 +357,7 @@
.analytics .colstack_head h1 { .analytics .colstack_head h1 {
margin-top: 2px; margin-top: 2px;
} }
.spamSelector + .timeRangeSelector { select + .timeRangeSelector {
margin-left: 8px; margin-left: 8px;
} }

View File

@ -172,7 +172,7 @@ button, .formbutton, .panel_right_button:not(.has_inner_button), #panel_users .p
color: rgb(200,200,200); color: rgb(200,200,200);
}*/ }*/
.spamSelector + .timeRangeSelector { select + .timeRangeSelector {
margin-left: 8px; margin-left: 8px;
} }

View File

@ -133,7 +133,7 @@
margin-top: 0px; margin-top: 0px;
margin-bottom: 0px; margin-bottom: 0px;
} }
.spamSelector + .timeRangeSelector { select + .timeRangeSelector {
margin-left: 8px; margin-left: 8px;
} }

View File

@ -177,7 +177,7 @@
margin-top: 0px; margin-top: 0px;
margin-bottom: 0px; margin-bottom: 0px;
} }
.spamSelector + .timeRangeSelector { select + .timeRangeSelector {
margin-left: 8px; margin-left: 8px;
} }