gosora/common/counters/langs.go

175 lines
2.9 KiB
Go

package counters
import (
"database/sql"
c "github.com/Azareal/Gosora/common"
qgen "github.com/Azareal/Gosora/query_gen"
"github.com/pkg/errors"
)
var LangViewCounter *DefaultLangViewCounter
var langCodes = []string{
"unknown",
"none",
"af",
"ar",
"az",
"be",
"bg",
"bs",
"ca",
"cs",
"cy",
"da",
"de",
"dv",
"el",
"en",
"eo",
"es",
"et",
"eu",
"fa",
"fi",
"fo",
"fr",
"gl",
"gu",
"he",
"hi",
"hr",
"hu",
"hy",
"id",
"is",
"it",
"ja",
"ka",
"kk",
"kn",
"ko",
"kok",
"ky",
"lt",
"lv",
"mi",
"mk",
"mn",
"mr",
"ms",
"mt",
"nb",
"nl",
"nn",
"ns",
"pa",
"pl",
"ps",
"pt",
"qu",
"ro",
"ru",
"sa",
"se",
"sk",
"sl",
"sq",
"sr",
"sv",
"sw",
"syr",
"ta",
"te",
"th",
"tl",
"tn",
"tr",
"tt",
"ts",
"uk",
"ur",
"uz",
"vi",
"xh",
"zh",
"zu",
}
type DefaultLangViewCounter struct {
buckets []*RWMutexCounterBucket //[OSID]count
codesToIndices map[string]int
insert *sql.Stmt
}
func NewDefaultLangViewCounter(acc *qgen.Accumulator) (*DefaultLangViewCounter, error) {
langBuckets := make([]*RWMutexCounterBucket, len(langCodes))
for bucketID, _ := range langBuckets {
langBuckets[bucketID] = &RWMutexCounterBucket{counter: 0}
}
codesToIndices := make(map[string]int, len(langCodes))
for index, code := range langCodes {
codesToIndices[code] = index
}
co := &DefaultLangViewCounter{
buckets: langBuckets,
codesToIndices: codesToIndices,
insert: acc.Insert("viewchunks_langs").Columns("count, createdAt, lang").Fields("?,UTC_TIMESTAMP(),?").Prepare(),
}
c.AddScheduledFifteenMinuteTask(co.Tick)
//c.AddScheduledSecondTask(co.Tick)
c.AddShutdownTask(co.Tick)
return co, acc.FirstError()
}
func (co *DefaultLangViewCounter) Tick() error {
for id, bucket := range co.buckets {
var count int
bucket.RLock()
count = bucket.counter
bucket.counter = 0 // TODO: Add a SetZero method to reduce the amount of duplicate code between the OS and agent counters?
bucket.RUnlock()
err := co.insertChunk(count, id) // TODO: Bulk insert for speed?
if err != nil {
return errors.Wrap(errors.WithStack(err), "langview counter")
}
}
return nil
}
func (co *DefaultLangViewCounter) insertChunk(count int, id int) error {
if count == 0 {
return nil
}
langCode := langCodes[id]
c.DebugLogf("Inserting a vchunk with a count of %d for lang %s (%d)", count, langCode, id)
_, err := co.insert.Exec(count, langCode)
return err
}
func (co *DefaultLangViewCounter) Bump(langCode string) (validCode bool) {
validCode = true
id, ok := co.codesToIndices[langCode]
if !ok {
// TODO: Tell the caller that the code's invalid
id = 0 // Unknown
validCode = false
}
// TODO: Test this check
c.DebugDetail("co.buckets[", id, "]: ", co.buckets[id])
if len(co.buckets) <= id || id < 0 {
return validCode
}
co.buckets[id].Lock()
co.buckets[id].counter++
co.buckets[id].Unlock()
return validCode
}