2018-02-19 04:26:01 +00:00
|
|
|
package counters
|
|
|
|
|
2019-07-26 23:29:42 +00:00
|
|
|
import (
|
|
|
|
"database/sql"
|
|
|
|
|
2019-07-28 03:46:19 +00:00
|
|
|
c "github.com/Azareal/Gosora/common"
|
2019-07-26 23:29:42 +00:00
|
|
|
qgen "github.com/Azareal/Gosora/query_gen"
|
2019-07-28 03:46:19 +00:00
|
|
|
"github.com/pkg/errors"
|
2019-07-26 23:29:42 +00:00
|
|
|
)
|
2018-02-19 04:26:01 +00:00
|
|
|
|
|
|
|
var RouteViewCounter *DefaultRouteViewCounter
|
|
|
|
|
|
|
|
// TODO: Make this lockless?
|
|
|
|
type DefaultRouteViewCounter struct {
|
2018-03-08 03:59:47 +00:00
|
|
|
buckets []*RWMutexCounterBucket //[RouteID]count
|
|
|
|
insert *sql.Stmt
|
2018-02-19 04:26:01 +00:00
|
|
|
}
|
|
|
|
|
2019-03-21 22:59:41 +00:00
|
|
|
func NewDefaultRouteViewCounter(acc *qgen.Accumulator) (*DefaultRouteViewCounter, error) {
|
2019-07-28 03:46:19 +00:00
|
|
|
routeBuckets := make([]*RWMutexCounterBucket, len(routeMapEnum))
|
2018-02-19 04:26:01 +00:00
|
|
|
for bucketID, _ := range routeBuckets {
|
|
|
|
routeBuckets[bucketID] = &RWMutexCounterBucket{counter: 0}
|
|
|
|
}
|
2019-07-28 03:46:19 +00:00
|
|
|
co := &DefaultRouteViewCounter{
|
2018-03-08 03:59:47 +00:00
|
|
|
buckets: routeBuckets,
|
|
|
|
insert: acc.Insert("viewchunks").Columns("count, createdAt, route").Fields("?,UTC_TIMESTAMP(),?").Prepare(),
|
2018-02-19 04:26:01 +00:00
|
|
|
}
|
2019-07-28 03:46:19 +00:00
|
|
|
c.AddScheduledFifteenMinuteTask(co.Tick) // There could be a lot of routes, so we don't want to be running this every second
|
|
|
|
//c.AddScheduledSecondTask(co.Tick)
|
|
|
|
c.AddShutdownTask(co.Tick)
|
|
|
|
return co, acc.FirstError()
|
2018-02-19 04:26:01 +00:00
|
|
|
}
|
|
|
|
|
2019-07-28 03:46:19 +00:00
|
|
|
func (co *DefaultRouteViewCounter) Tick() error {
|
|
|
|
for routeID, routeBucket := range co.buckets {
|
2018-02-19 04:26:01 +00:00
|
|
|
var count int
|
|
|
|
routeBucket.RLock()
|
|
|
|
count = routeBucket.counter
|
|
|
|
routeBucket.counter = 0
|
|
|
|
routeBucket.RUnlock()
|
|
|
|
|
2019-07-28 03:46:19 +00:00
|
|
|
err := co.insertChunk(count, routeID) // TODO: Bulk insert for speed?
|
2018-02-19 04:26:01 +00:00
|
|
|
if err != nil {
|
2019-07-28 03:46:19 +00:00
|
|
|
return errors.Wrap(errors.WithStack(err), "route counter")
|
2018-02-19 04:26:01 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2019-07-28 03:46:19 +00:00
|
|
|
func (co *DefaultRouteViewCounter) insertChunk(count int, route int) error {
|
2018-02-19 04:26:01 +00:00
|
|
|
if count == 0 {
|
|
|
|
return nil
|
|
|
|
}
|
2019-07-28 03:46:19 +00:00
|
|
|
routeName := reverseRouteMapEnum[route]
|
|
|
|
c.DebugLogf("Inserting a vchunk with a count of %d for route %s (%d)", count, routeName, route)
|
|
|
|
_, err := co.insert.Exec(count, routeName)
|
2018-02-19 04:26:01 +00:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2019-07-28 03:46:19 +00:00
|
|
|
func (co *DefaultRouteViewCounter) Bump(route int) {
|
2018-02-19 04:26:01 +00:00
|
|
|
// TODO: Test this check
|
2019-07-28 03:46:19 +00:00
|
|
|
c.DebugDetail("co.buckets[", route, "]: ", co.buckets[route])
|
|
|
|
if len(co.buckets) <= route || route < 0 {
|
2018-02-19 04:26:01 +00:00
|
|
|
return
|
|
|
|
}
|
2019-07-28 03:46:19 +00:00
|
|
|
co.buckets[route].Lock()
|
|
|
|
co.buckets[route].counter++
|
|
|
|
co.buckets[route].Unlock()
|
2018-02-19 04:26:01 +00:00
|
|
|
}
|