c60118e7c4
Add Http Conn Count tracking. Move more panel phrases into the panel namespace. Use a string builder in hookgen. Use Countf() in a couple of places to eliminate boilerplate. Reduce prepared stmt boilerplate in forum store with a lambda. Reduce prepared stmt boilerplate in topic.go with a lambda. Reduce prepared stmt boilerplate in group.go with a lambda. Add TestSetCreatedAt method to *Topic. Add DateOlderThanQ method to *accDeleteBuilder and *accUpdateBuilder. Add Stmt method to *accUpdateBuilder and *AccSelectBuilder. Add AccBuilder interface. Shorten variable names. Shorten extractPerm name to ep. Add avatar_visibility setting stub. Implementation coming in a later commit. Don't set an IP for installer generated posts. Add counters_perf_tick_row hook. Add avatar_visibility phrase. Add avatar_visibility_label phrase. Rename forums_no_description to forums_no_desc. Rename panel.forums_create_description_label to panel.forums_create_desc_label. Rename panel.forums_create_description to panel.forums_create_desc. Rename panel_forum_description to panel.forum_desc. Rename panel_forum_description_placeholder to panel.forum_desc_placeholder. Add panel_debug_http_conns_label phrase. Add panel.forum_actions_head phrase. Add panel.forum_actions_create_head phrase. Add panel.forum_action_run_on_topic_creation phrase. Add panel.forum_action_run_days_after_topic_creation phrase. Add panel.forum_action_run_days_after_topic_last_reply phrase. Add panel.forum_action_action phrase. Add panel.forum_action_action_delete phrase. Add panel.forum_action_action_lock phrase. Add panel.forum_action_action_unlock phrase. Add panel.forum_action_action_move phrase. Add panel.forum_action_extra phrase. Add panel.forum_action_create_button phrase. You will need to run the patcher / updater for this commit.
118 lines
2.5 KiB
Go
118 lines
2.5 KiB
Go
package counters
|
|
|
|
import (
|
|
"database/sql"
|
|
"math"
|
|
"time"
|
|
|
|
c "github.com/Azareal/Gosora/common"
|
|
qgen "github.com/Azareal/Gosora/query_gen"
|
|
"github.com/pkg/errors"
|
|
)
|
|
|
|
var PerfCounter *DefaultPerfCounter
|
|
|
|
type PerfCounterBucket struct {
|
|
low *MutexCounter64Bucket
|
|
high *MutexCounter64Bucket
|
|
avg *MutexCounter64Bucket
|
|
}
|
|
|
|
// TODO: Track perf on a per route basis
|
|
type DefaultPerfCounter struct {
|
|
buckets []*PerfCounterBucket
|
|
|
|
insert *sql.Stmt
|
|
}
|
|
|
|
func NewDefaultPerfCounter(acc *qgen.Accumulator) (*DefaultPerfCounter, error) {
|
|
co := &DefaultPerfCounter{
|
|
buckets: []*PerfCounterBucket{
|
|
{
|
|
low: &MutexCounter64Bucket{counter: math.MaxInt64},
|
|
high: &MutexCounter64Bucket{counter: 0},
|
|
avg: &MutexCounter64Bucket{counter: 0},
|
|
},
|
|
},
|
|
insert: acc.Insert("perfchunks").Columns("low,high,avg,createdAt").Fields("?,?,?,UTC_TIMESTAMP()").Prepare(),
|
|
}
|
|
|
|
c.AddScheduledFifteenMinuteTask(co.Tick)
|
|
//c.AddScheduledSecondTask(co.Tick)
|
|
c.AddShutdownTask(co.Tick)
|
|
return co, acc.FirstError()
|
|
}
|
|
|
|
func (co *DefaultPerfCounter) Tick() error {
|
|
getCounter := func(b *MutexCounter64Bucket) (c int64) {
|
|
b.Lock()
|
|
c = b.counter
|
|
b.counter = 0
|
|
b.Unlock()
|
|
return c
|
|
}
|
|
var low int64
|
|
hTbl := c.GetHookTable()
|
|
for _, b := range co.buckets {
|
|
b.low.Lock()
|
|
low, b.low.counter = b.low.counter, math.MaxInt64
|
|
b.low.Unlock()
|
|
if low == math.MaxInt64 {
|
|
low = 0
|
|
}
|
|
high := getCounter(b.high)
|
|
avg := getCounter(b.avg)
|
|
c.H_counters_perf_tick_row_hook(hTbl, low, high, avg)
|
|
|
|
e := co.insertChunk(low, high, avg) // TODO: Bulk insert for speed?
|
|
if e != nil {
|
|
return errors.Wrap(errors.WithStack(e), "perf counter")
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (co *DefaultPerfCounter) insertChunk(low, high, avg int64) error {
|
|
if low == 0 && high == 0 && avg == 0 {
|
|
return nil
|
|
}
|
|
c.DebugLogf("Inserting a pchunk with low %d, high %d, avg %d", low, high, avg)
|
|
_, e := co.insert.Exec(low, high, avg)
|
|
return e
|
|
}
|
|
|
|
func (co *DefaultPerfCounter) Push(dur time.Duration /*,_ bool*/) {
|
|
id := 0
|
|
b := co.buckets[id]
|
|
//c.DebugDetail("buckets[", id, "]: ", b)
|
|
micro := dur.Microseconds()
|
|
if micro >= math.MaxInt32 {
|
|
c.LogWarning(errors.New("dur should not be int32 max or higher"))
|
|
}
|
|
|
|
low := b.low
|
|
low.Lock()
|
|
if micro < low.counter {
|
|
low.counter = micro
|
|
}
|
|
low.Unlock()
|
|
|
|
high := b.high
|
|
high.Lock()
|
|
if micro > high.counter {
|
|
high.counter = micro
|
|
}
|
|
high.Unlock()
|
|
|
|
avg := b.avg
|
|
avg.Lock()
|
|
if micro != avg.counter {
|
|
if avg.counter == 0 {
|
|
avg.counter = micro
|
|
} else {
|
|
avg.counter = (micro + avg.counter) / 2
|
|
}
|
|
}
|
|
avg.Unlock()
|
|
}
|