Initial commit

This commit is contained in:
Donny
2019-04-22 20:46:32 +08:00
commit 49ab8aadd1
25441 changed files with 4055000 additions and 0 deletions

View File

@@ -0,0 +1,18 @@
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [
":package-srcs",
"//app/service/main/archive/dao/archive:all-srcs",
"//app/service/main/archive/dao/share:all-srcs",
"//app/service/main/archive/dao/videoshot:all-srcs",
],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)

View File

@@ -0,0 +1,95 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_test",
"go_library",
)
go_test(
name = "go_default_test",
srcs = [
"addit_test.go",
"archive_mc_pb_test.go",
"archive_test.go",
"dao_test.go",
"player_test.go",
"region_rds_test.go",
"region_test.go",
"report_result_test.go",
"stat_mc_pb_test.go",
"stat_pb_test.go",
"stat_test.go",
"type_test.go",
"upper_rds_test.go",
"upper_test.go",
"video_mc_pb_test.go",
"video_test.go",
],
embed = [":go_default_library"],
rundir = ".",
tags = ["automanaged"],
deps = [
"//app/service/main/archive/api:go_default_library",
"//app/service/main/archive/conf:go_default_library",
"//library/time:go_default_library",
"//vendor/github.com/smartystreets/goconvey/convey:go_default_library",
],
)
go_library(
name = "go_default_library",
srcs = [
"addit.go",
"archive.go",
"archive_mc_pb.go",
"dao.go",
"player.go",
"region.go",
"region_rds.go",
"report_result.go",
"stat.go",
"stat_mc_pb.go",
"stat_pb.go",
"type.go",
"upper.go",
"upper_rds.go",
"video.go",
"video_mc_pb.go",
],
importpath = "go-common/app/service/main/archive/dao/archive",
tags = ["automanaged"],
deps = [
"//app/job/main/archive/model/databus:go_default_library",
"//app/service/main/account/api:go_default_library",
"//app/service/main/archive/api:go_default_library",
"//app/service/main/archive/conf:go_default_library",
"//app/service/main/archive/model/archive:go_default_library",
"//library/cache/memcache:go_default_library",
"//library/cache/redis:go_default_library",
"//library/database/sql:go_default_library",
"//library/ecode:go_default_library",
"//library/log:go_default_library",
"//library/net/http/blademaster:go_default_library",
"//library/queue/databus:go_default_library",
"//library/stat/prom:go_default_library",
"//library/sync/errgroup:go_default_library",
"//library/time:go_default_library",
"//library/xstr:go_default_library",
"//vendor/github.com/pkg/errors:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)

View File

@@ -0,0 +1,30 @@
package archive
import (
"context"
"go-common/app/service/main/archive/model/archive"
"go-common/library/database/sql"
"go-common/library/log"
)
const (
_additSQL = "SELECT id,aid,source,redirect_url,mission_id,up_from,order_id,description FROM archive_addit WHERE aid=?"
)
// Addit get archive addit.
func (d *Dao) Addit(c context.Context, aid int64) (addit *archive.Addit, err error) {
d.infoProm.Incr("Addit")
row := d.additStmt.QueryRow(c, aid)
addit = &archive.Addit{}
if err = row.Scan(&addit.ID, &addit.Aid, &addit.Source, &addit.RedirectURL, &addit.MissionID, &addit.UpFrom, &addit.OrderID, &addit.Description); err != nil {
if err == sql.ErrNoRows {
addit = nil
err = nil
} else {
log.Error("row.Scan error(%v)", err)
}
}
return
}

View File

@@ -0,0 +1,21 @@
package archive
import (
"context"
"testing"
"github.com/smartystreets/goconvey/convey"
)
func TestArchiveAddit(t *testing.T) {
var (
c = context.TODO()
aid = int64(1)
)
convey.Convey("Addit", t, func(ctx convey.C) {
_, err := d.Addit(c, aid)
ctx.Convey("Then err should be nil.addit should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
}

View File

@@ -0,0 +1,127 @@
package archive
import (
"context"
"database/sql"
"fmt"
"go-common/app/service/main/archive/api"
"go-common/library/log"
"go-common/library/xstr"
)
const (
_maxAIDSQL = "SELECT max(aid) FROM archive"
_arcSQL = "SELECT aid,mid,typeid,videos,copyright,title,cover,content,duration,attribute,state,access,pubtime,ctime,mission_id,order_id,redirect_url,forward,dynamic,cid,dimensions FROM archive WHERE aid=?"
_arcsSQL = "SELECT aid,mid,typeid,videos,copyright,title,cover,content,duration,attribute,state,access,pubtime,ctime,mission_id,order_id,redirect_url,forward,dynamic,cid,dimensions FROM archive WHERE aid IN (%s)"
_arcStaffSQL = "SELECT mid,title FROM archive_staff WHERE aid=?"
_arcsStaffSQL = "SELECT aid,mid,title FROM archive_staff WHERE aid IN(%s)"
)
// MaxAID get max aid
func (d *Dao) MaxAID(c context.Context) (id int64, err error) {
row := d.resultDB.QueryRow(c, _maxAIDSQL)
if err = row.Scan(&id); err != nil {
log.Error("row.Scan error(%v)", err)
return
}
return
}
// archivePB get a archive by aid.
func (d *Dao) archive3(c context.Context, aid int64) (a *api.Arc, err error) {
d.infoProm.Incr("archive3")
row := d.resultDB.QueryRow(c, _arcSQL, aid)
a = &api.Arc{}
var dimension string
if err = row.Scan(&a.Aid, &(a.Author.Mid), &a.TypeID, &a.Videos, &a.Copyright, &a.Title, &a.Pic, &a.Desc, &a.Duration,
&a.Attribute, &a.State, &a.Access, &a.PubDate, &a.Ctime, &a.MissionID, &a.OrderID, &a.RedirectURL, &a.Forward, &a.Dynamic, &a.FirstCid, &dimension); err != nil {
if err == sql.ErrNoRows {
a = nil
err = nil
} else {
log.Error("row.Scan error(%v)", err)
d.errProm.Incr("result_db")
}
return
}
a.FillDimension(dimension)
return
}
// archives3 multi get archives by avids.
func (d *Dao) archives3(c context.Context, aids []int64) (res map[int64]*api.Arc, err error) {
d.infoProm.Incr("archives3")
query := fmt.Sprintf(_arcsSQL, xstr.JoinInts(aids))
rows, err := d.resultDB.Query(c, query)
if err != nil {
log.Error("db.Query(%s) error(%v)", query, err)
d.errProm.Incr("result_db")
return
}
defer rows.Close()
res = make(map[int64]*api.Arc, len(aids))
for rows.Next() {
a := &api.Arc{}
var dimension string
if err = rows.Scan(&a.Aid, &(a.Author.Mid), &a.TypeID, &a.Videos, &a.Copyright, &a.Title, &a.Pic, &a.Desc, &a.Duration,
&a.Attribute, &a.State, &a.Access, &a.PubDate, &a.Ctime, &a.MissionID, &a.OrderID, &a.RedirectURL, &a.Forward, &a.Dynamic, &a.FirstCid, &dimension); err != nil {
log.Error("rows.Scan error(%v)", err)
d.errProm.Incr("result_db")
return
}
a.FillDimension(dimension)
res[a.Aid] = a
}
err = rows.Err()
return
}
// staff get archives staff by avid.
func (d *Dao) staff(c context.Context, aid int64) (res []*api.StaffInfo, err error) {
d.infoProm.Incr("archive_staff")
rows, err := d.resultDB.Query(c, _arcStaffSQL, aid)
if err != nil {
log.Error("d.resultDB.Query(%d) error(%v)", aid, err)
d.errProm.Incr("result_db")
return
}
defer rows.Close()
for rows.Next() {
as := &api.StaffInfo{}
if err = rows.Scan(&as.Mid, &as.Title); err != nil {
log.Error("rows.Scan error(%v)", err)
d.errProm.Incr("result_db")
return
}
res = append(res, as)
}
err = rows.Err()
return
}
// staffs get archives staff by avids.
func (d *Dao) staffs(c context.Context, aids []int64) (res map[int64][]*api.StaffInfo, err error) {
d.infoProm.Incr("archives_staff")
query := fmt.Sprintf(_arcsStaffSQL, xstr.JoinInts(aids))
rows, err := d.resultDB.Query(c, query)
if err != nil {
log.Error("d.resultDB.Query(%s) error(%v)", query, err)
d.errProm.Incr("result_db")
return
}
defer rows.Close()
res = make(map[int64][]*api.StaffInfo)
for rows.Next() {
as := &api.StaffInfo{}
var aid int64
if err = rows.Scan(&aid, &as.Mid, &as.Title); err != nil {
log.Error("rows.Scan error(%v)", err)
d.errProm.Incr("result_db")
return
}
res[aid] = append(res[aid], as)
}
err = rows.Err()
return
}

View File

@@ -0,0 +1,161 @@
package archive
import (
"context"
"strconv"
"sync"
"go-common/app/service/main/archive/api"
"go-common/library/cache/memcache"
"go-common/library/log"
"go-common/library/sync/errgroup"
)
const (
_prefixArc3 = "a3p_"
_prefixDesc = "desc_"
)
func descKey(aid int64) string {
return _prefixDesc + strconv.FormatInt(aid, 10)
}
func arcPBKey(aid int64) string {
return _prefixArc3 + strconv.FormatInt(aid, 10)
}
// archive3Cache get a archive info from cache.
func (d *Dao) archive3Cache(c context.Context, aid int64) (a *api.Arc, err error) {
var (
key = arcPBKey(aid)
rp *memcache.Item
conn = d.mc.Get(c)
)
defer conn.Close()
if rp, err = conn.Get(key); err != nil {
if err == memcache.ErrNotFound {
err = nil
} else {
d.errProm.Incr("archive_mc")
log.Error("memcache.Get(%s) error(%v)", key, err)
}
return
}
a = &api.Arc{}
if err = conn.Scan(rp, a); err != nil {
log.Error("conn.Scan(%s) error(%v)", rp.Value, err)
}
return
}
// archive3Caches multi get archives, return map[aid]*Archive and missed aids.
func (d *Dao) archive3Caches(c context.Context, aids []int64) (cached map[int64]*api.Arc, err error) {
var (
keys = make([]string, 0)
keyMap = make(map[int64]struct{}, len(aids))
eg = errgroup.Group{}
mutex = sync.Mutex{}
)
cached = make(map[int64]*api.Arc)
for _, aid := range aids {
if _, ok := keyMap[aid]; ok {
continue
}
keyMap[aid] = struct{}{}
keys = append(keys, arcPBKey(aid))
if len(keys) == 50 {
egks := keys
eg.Go(func() (err error) {
as, _ := d._archiveCaches(c, egks)
mutex.Lock()
for _, a := range as {
cached[a.Aid] = a
}
mutex.Unlock()
return
})
keys = make([]string, 0)
}
}
if len(keys) > 0 {
eg.Go(func() (err error) {
as, _ := d._archiveCaches(c, keys)
mutex.Lock()
for _, a := range as {
cached[a.Aid] = a
}
mutex.Unlock()
return
})
}
eg.Wait()
return
}
// _archiveCaches is
func (d *Dao) _archiveCaches(c context.Context, keys []string) (as map[int64]*api.Arc, err error) {
conn := d.mc.Get(c)
defer conn.Close()
rs, err := conn.GetMulti(keys)
if err != nil {
if err == memcache.ErrNotFound {
err = nil
return
}
log.Error("conn.GetMulti(%v) error(%v)", keys, err)
return
}
as = make(map[int64]*api.Arc)
for _, r := range rs {
a := &api.Arc{}
if err = conn.Scan(r, a); err != nil {
log.Error("conn.Scan error(%v)", err)
continue
}
as[a.Aid] = a
}
return
}
// addArchivePBCache set archive into cache.
func (d *Dao) addArchive3Cache(c context.Context, a *api.Arc) (err error) {
key := arcPBKey(a.Aid)
conn := d.mc.Get(c)
if err = conn.Set(&memcache.Item{Key: key, Object: a, Flags: memcache.FlagProtobuf, Expiration: 0}); err != nil {
log.Error("memcache.Set(%s) error(%v)", key, err)
d.errProm.Incr("archive_mc")
}
conn.Close()
return
}
func (d *Dao) descCache(c context.Context, aid int64) (desc string, err error) {
key := descKey(aid)
conn := d.mc.Get(c)
defer conn.Close()
var item *memcache.Item
if item, err = conn.Get(key); err != nil {
if err == memcache.ErrNotFound {
err = nil
return
}
log.Error("conn.Get(%s) error(%v)", key, err)
return
}
if err = conn.Scan(item, &desc); err != nil {
log.Error("conn.Scan error(%v)", err)
return
}
return
}
func (d *Dao) addDescCache(c context.Context, aid int64, desc string) (err error) {
key := descKey(aid)
conn := d.mc.Get(c)
defer conn.Close()
if err = conn.Set(&memcache.Item{Key: key, Value: []byte(desc), Flags: memcache.FlagRAW, Expiration: 0}); err != nil {
log.Error("conn.Set(%s, %s) error(%v)", key, desc, err)
return
}
return
}

View File

@@ -0,0 +1,98 @@
package archive
import (
"context"
"go-common/app/service/main/archive/api"
"testing"
"github.com/smartystreets/goconvey/convey"
)
func TestArchivedescKey(t *testing.T) {
var (
aid = int64(1)
)
convey.Convey("descKey", t, func(ctx convey.C) {
p1 := descKey(aid)
ctx.Convey("Then p1 should not be nil.", func(ctx convey.C) {
ctx.So(p1, convey.ShouldNotBeNil)
})
})
}
func TestArchivearcPBKey(t *testing.T) {
var (
aid = int64(1)
)
convey.Convey("arcPBKey", t, func(ctx convey.C) {
p1 := arcPBKey(aid)
ctx.Convey("Then p1 should not be nil.", func(ctx convey.C) {
ctx.So(p1, convey.ShouldNotBeNil)
})
})
}
func TestArchivearchive3Cache(t *testing.T) {
var (
c = context.TODO()
aid = int64(1)
)
convey.Convey("archive3Cache", t, func(ctx convey.C) {
d.archive3Cache(c, aid)
})
}
func TestArchivearchive3Caches(t *testing.T) {
var (
c = context.TODO()
aids = []int64{1, 2}
)
convey.Convey("archive3Caches", t, func(ctx convey.C) {
cached, err := d.archive3Caches(c, aids)
ctx.Convey("Then err should be nil.cached should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(cached, convey.ShouldNotBeNil)
})
})
}
func TestArchiveaddArchive3Cache(t *testing.T) {
var (
c = context.TODO()
a = &api.Arc{}
)
convey.Convey("addArchive3Cache", t, func(ctx convey.C) {
err := d.addArchive3Cache(c, a)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
}
func TestArchivedescCache(t *testing.T) {
var (
c = context.TODO()
aid = int64(1)
)
convey.Convey("descCache", t, func(ctx convey.C) {
desc, err := d.descCache(c, aid)
ctx.Convey("Then err should be nil.desc should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(desc, convey.ShouldNotBeNil)
})
})
}
func TestArchiveaddDescCache(t *testing.T) {
var (
c = context.TODO()
aid = int64(1)
desc = ""
)
convey.Convey("addDescCache", t, func(ctx convey.C) {
err := d.addDescCache(c, aid, desc)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
}

View File

@@ -0,0 +1,48 @@
package archive
import (
"context"
"testing"
"github.com/smartystreets/goconvey/convey"
)
func TestArchiveMaxAID(t *testing.T) {
var (
c = context.TODO()
)
convey.Convey("MaxAID", t, func(ctx convey.C) {
id, err := d.MaxAID(c)
ctx.Convey("Then err should be nil.id should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(id, convey.ShouldNotBeNil)
})
})
}
func TestArchivearchive3(t *testing.T) {
var (
c = context.TODO()
aid = int64(10097272)
)
convey.Convey("archive3", t, func(ctx convey.C) {
_, err := d.archive3(c, aid)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
}
func TestArchivearchives3(t *testing.T) {
var (
c = context.TODO()
aids = []int64{10097272}
)
convey.Convey("archives3", t, func(ctx convey.C) {
res, err := d.archives3(c, aids)
ctx.Convey("Then err should be nil.res should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(res, convey.ShouldNotBeNil)
})
})
}

View File

@@ -0,0 +1,655 @@
package archive
import (
"context"
"fmt"
"runtime"
"strconv"
"time"
ajbmdl "go-common/app/job/main/archive/model/databus"
accapi "go-common/app/service/main/account/api"
"go-common/app/service/main/archive/api"
"go-common/app/service/main/archive/conf"
"go-common/app/service/main/archive/model/archive"
arcmdl "go-common/app/service/main/archive/model/archive"
"go-common/library/cache/memcache"
"go-common/library/cache/redis"
"go-common/library/database/sql"
"go-common/library/ecode"
"go-common/library/log"
bm "go-common/library/net/http/blademaster"
"go-common/library/queue/databus"
"go-common/library/stat/prom"
"go-common/library/sync/errgroup"
)
const (
_multiInterval = 200
)
var (
_emptyPages3 = []*api.Page{}
)
// Dao is archive dao.
type Dao struct {
c *conf.Config
// db
db *sql.DB
arcReadDB *sql.DB
resultDB *sql.DB
statDB *sql.DB
clickDB *sql.DB
// acc rpc
acc accapi.AccountClient
// memcache
mc *memcache.Pool
// redis
upRds *redis.Pool
upExpire int32
// region
rgRds *redis.Pool
// archive stmt
rgnArcsStmt *sql.Stmt
upCntStmt *sql.Stmt
upPasStmt *sql.Stmt
reportResultStmt *sql.Stmt
additStmt *sql.Stmt
// video stmt
vdosStmt *sql.Stmt
// dede stmt
tpsStmt *sql.Stmt
// type cache
tNamem map[int16]string
// report_result cache
aidResult map[int64]string
// cache chan
cacheCh chan func()
hitProm *prom.Prom
missProm *prom.Prom
errProm *prom.Prom
infoProm *prom.Prom
// player http client
playerClient *bm.Client
// player qn map
playerQn map[int]struct{}
playerVipQn map[int]struct{}
cacheDatabus *databus.Databus
}
// New new a Dao and return.
func New(c *conf.Config) (d *Dao) {
d = &Dao{
c: c,
// db
db: sql.NewMySQL(c.DB.Arc),
arcReadDB: sql.NewMySQL(c.DB.ArcRead),
resultDB: sql.NewMySQL(c.DB.ArcResult),
statDB: sql.NewMySQL(c.DB.Stat),
clickDB: sql.NewMySQL(c.DB.Click),
// memcache
mc: memcache.NewPool(c.Memcache.Archive.Config),
// redis
upRds: redis.NewPool(c.Redis.Archive.Config),
upExpire: 480 * 60 * 60,
rgRds: redis.NewPool(c.Redis.Archive.Config),
// cache chan
cacheCh: make(chan func(), 1024),
hitProm: prom.CacheHit,
missProm: prom.CacheMiss,
errProm: prom.BusinessErrCount,
infoProm: prom.BusinessInfoCount,
playerClient: bm.NewClient(c.PlayerClient),
playerQn: make(map[int]struct{}),
playerVipQn: make(map[int]struct{}),
cacheDatabus: databus.New(c.CacheDatabus),
}
var err error
if d.acc, err = accapi.NewClient(c.AccClient); err != nil {
panic(fmt.Sprintf("account GRPC error(%v)!!!!!!!!!!!!!!!!!!!!!!", err))
}
d.rgnArcsStmt = d.resultDB.Prepared(_rgnArcsSQL)
d.upCntStmt = d.resultDB.Prepared(_upCntSQL)
d.upPasStmt = d.resultDB.Prepared(_upPasSQL)
d.tpsStmt = d.arcReadDB.Prepared(_tpsSQL)
d.additStmt = d.arcReadDB.Prepared(_additSQL)
// video stmt
d.vdosStmt = d.resultDB.Prepared(_vdosSQL)
// archive_report_resutl
d.reportResultStmt = d.arcReadDB.Prepared(_reportResultSQL)
// type cache
for _, pn := range d.c.PlayerQn {
d.playerQn[pn] = struct{}{}
}
for _, pvn := range d.c.PlayerVipQn {
d.playerVipQn[pvn] = struct{}{}
}
d.loadTypes()
d.loadReportResult()
for i := 0; i < runtime.NumCPU(); i++ {
go d.cacheproc()
}
go d.loadproc()
return
}
func (d *Dao) addCache(f func()) {
select {
case d.cacheCh <- f:
default:
log.Warn("d.cacheCh is full")
}
}
// Archive3 get archive by aid.
func (d *Dao) Archive3(c context.Context, aid int64) (a *api.Arc, err error) {
var cached = true
if a, err = d.archive3Cache(c, aid); err != nil {
log.Error("d.archivePBCache(%d) error(%v)", aid, err)
err = nil // NOTE ignore error use db
cached = false
}
if a != nil {
if st, _ := d.Stat3(c, aid); st != nil {
a.Stat = *st
a.FillStat()
}
a.ReportResult = d.aidResult[aid]
return
}
if a, err = d.archive3(c, aid); err != nil {
log.Error("d.archive(%d) error(%v)", aid, err)
return
}
if a == nil {
err = ecode.NothingFound
return
}
if st, _ := d.Stat3(c, aid); st != nil {
a.Stat = *st
a.FillStat()
}
d.fillArchive3(c, a, cached)
a.ReportResult = d.aidResult[aid]
return
}
// Archives3 get archives by aids.
func (d *Dao) Archives3(c context.Context, aids []int64) (am map[int64]*api.Arc, err error) {
var eg errgroup.Group
eg.Go(func() (err error) {
var (
missed []int64
missm map[int64]*api.Arc
cached = true
)
if am, err = d.archive3Caches(c, aids); err != nil {
log.Error("%+v", err)
am = make(map[int64]*api.Arc, len(aids))
err = nil // NOTE: ignore error
cached = false
}
for _, aid := range aids {
if _, ok := am[aid]; !ok {
missed = append(missed, aid)
}
}
if len(missed) == 0 {
return
}
if missm, err = d.archives3(c, missed); err != nil {
log.Error("d.archives(%v) error(%v)", missed, err)
return
}
if len(missm) == 0 {
log.Warn("archives miss(%+v)", missed)
return
}
d.fillArchives(c, missm, cached)
for _, a := range missm {
am[a.Aid] = a
}
return
})
var stm map[int64]*api.Stat
eg.Go(func() (err error) {
var (
missed []int64
missm map[int64]*api.Stat
cached = true
)
if stm, missed, err = d.statCaches3(c, aids); err != nil {
log.Error("d.statCaches(%d) error(%v)", aids, err)
missed = aids
stm = make(map[int64]*api.Stat, len(aids))
err = nil // NOTE: ignore error
cached = false
}
d.hitProm.Add("stat3", int64(len(stm)))
if stm != nil && len(missed) == 0 {
return
}
if missm, err = d.stats3(c, missed); err != nil {
log.Error("d.stats(%v) error(%v)", missed, err)
err = nil // NOTE: ignore error
}
for aid, st := range missm {
stm[aid] = st
if cached {
var cst = &api.Stat{}
*cst = *st
d.addCache(func() {
d.addStatCache3(context.TODO(), cst)
})
}
}
d.missProm.Add("stat3", int64(len(missm)))
return
})
if err = eg.Wait(); err != nil {
log.Error("eg.Wait(%v) error(%v)", aids, err)
return
}
for aid, a := range am {
if st, ok := stm[aid]; ok {
a.Stat = *st
a.FillStat()
}
a.ReportResult = d.aidResult[aid]
}
return
}
// Videos3 get archive videos by aid.
func (d *Dao) Videos3(c context.Context, aid int64) (ps []*api.Page, err error) {
var cached = true
if ps, err = d.pageCache3(c, aid); err != nil {
log.Error("d.pageCache3(%d) error(%v)", aid, err)
err = nil // NOTE ignore error use db
cached = false
}
if ps != nil {
d.hitProm.Add("videos3", 1)
return
}
if ps, err = d.videos3(c, aid); err != nil {
log.Error("d.videos(%d) error(%v)", aid, err)
return
}
if len(ps) == 0 {
log.Warn("archive(%d) have not passed video", aid)
ps = _emptyPages3
}
d.missProm.Add("videos3", 1)
if cached {
d.addCache(func() {
d.addPageCache3(context.TODO(), aid, ps)
})
}
return
}
// VideosByAids3 get videos by aids
func (d *Dao) VideosByAids3(c context.Context, aids []int64) (vs map[int64][]*api.Page, err error) {
var (
missed []int64
cached = true
)
if vs, missed, err = d.pagesCache3(c, aids); err != nil {
log.Error("d.pagesCache(%v) error(%v)", aids, err)
missed = aids
err = nil
cached = false
}
d.hitProm.Add("videos3", int64(len(vs)))
if len(missed) == 0 && vs != nil {
return
}
var missVs = make(map[int64][]*api.Page, len(missed))
if missVs, err = d.videosByAids3(c, missed); err != nil {
log.Error("d.videosByAids3(%v) error(%v)", missed, err)
return
}
d.missProm.Add("videos3", int64(len(missVs)))
for aid, v := range missVs {
vs[aid] = v
if cached {
var (
caid = aid
cv = v
)
d.addCache(func() {
d.addPageCache3(context.TODO(), caid, cv)
})
}
}
return
}
// Video3 get video by aid & cid.
func (d *Dao) Video3(c context.Context, aid, cid int64) (p *api.Page, err error) {
var cached = true
if p, err = d.videoCache3(c, aid, cid); err != nil {
log.Error("d.videoCache3(%d, %d) error(%v)", aid, cid, err)
err = nil // NOTE ignore error use db
cached = false
}
if p != nil {
d.hitProm.Add("video3", 1)
return
}
if p, err = d.video3(c, aid, cid); err != nil {
log.Error("d.video3(%d) error(%v)", aid, cid, err)
return
}
if p == nil {
log.Warn("archive(%d) cid(%d) no passed video", aid, cid)
err = ecode.NothingFound
cached = false
}
d.missProm.Add("video3", 1)
if cached {
d.addCache(func() {
d.addVideoCache3(context.TODO(), aid, cid, p)
})
}
return
}
// Description get Description from by aid || aid+cid.
func (d *Dao) Description(c context.Context, aid int64) (desc string, err error) {
var (
addit *archive.Addit
a *api.Arc
)
desc, _ = d.descCache(c, aid)
if desc != "" {
return
}
if addit, err = d.Addit(c, aid); err != nil {
log.Error("d.Addit(%d) error(%v)", aid, err)
err = nil
}
if addit != nil && addit.Description != "" {
desc = addit.Description
d.addCache(func() {
d.addDescCache(context.TODO(), aid, desc)
})
return
}
if a, err = d.archive3(c, aid); err != nil {
log.Error("d.archive(%d) error(%v)", aid, err)
return
}
if a != nil && a.Desc != "" {
desc = a.Desc
d.addCache(func() {
d.addDescCache(context.TODO(), aid, desc)
})
}
return
}
// UpVideo3 update video by aid & cid.
func (d *Dao) UpVideo3(c context.Context, aid, cid int64) (err error) {
var p *api.Page
if p, err = d.video3(c, aid, cid); err != nil {
log.Error("d.video2(%d) error(%v)", aid, cid, err)
return
}
if p == nil {
err = ecode.NothingFound
return
}
d.addCache(func() {
d.addVideoCache3(context.TODO(), aid, cid, p)
})
return
}
// UpperCache is
func (d *Dao) UpperCache(c context.Context, mid int64, action string, oldname string, oldface string) {
var (
aids []int64
err error
infoReply *accapi.InfoReply
)
if action == "updateByAdmin" {
if infoReply, err = d.acc.Info3(c, &accapi.MidReq{Mid: mid}); err != nil || infoReply == nil {
log.Error("d.acc.Info3(%d) error(%v)", mid, err)
return
}
if infoReply.Info.Face == oldface && infoReply.Info.Name == oldname {
log.Info("account updateByAdmin no need update")
return
}
}
if aids, _, _, err = d.UpperPassed(c, mid); err != nil {
log.Error("d.UpperPassed(%d) error(%v)", mid, err)
return
}
for _, aid := range aids {
d.UpArchiveCache(context.TODO(), aid)
}
}
// UpArchiveCache update archive cache by aid.
func (d *Dao) UpArchiveCache(c context.Context, aid int64) (err error) {
var (
a *api.Arc
addit *archive.Addit
desc string
)
if a, err = d.archive3(c, aid); a != nil && err == nil {
d.fillArchive3(c, a, true)
desc = a.Desc
}
if addit, err = d.Addit(c, aid); err == nil && addit != nil {
if addit.Description != "" {
desc = addit.Description
}
}
d.addCache(func() {
d.addDescCache(context.TODO(), aid, desc)
})
// pages3
var ps3 []*api.Page
if ps3, err = d.videos3(c, aid); err != nil {
log.Error("d.videos3(%d) error(%v)", aid, err)
return
}
d.addCache(func() {
d.addPageCache3(context.TODO(), aid, ps3)
})
return
}
// Ping ping success.
func (d *Dao) Ping(c context.Context) (err error) {
if err = d.db.Ping(c); err != nil {
log.Error("d.db error(%v)", err)
return
}
// mc
mconn := d.mc.Get(c)
defer mconn.Close()
if err = mconn.Set(&memcache.Item{Key: "ping", Value: []byte("pong"), Expiration: 0}); err != nil {
log.Error("mc.Store error(%v)", err)
return
}
// upper redis
rconn := d.upRds.Get(c)
if _, err = rconn.Do("SET", "ping", "pong"); err != nil {
rconn.Close()
log.Error("rds.Set error(%v)", err)
return
}
rconn.Close()
// region redis
rconn = d.rgRds.Get(c)
if _, err = rconn.Do("SET", "ping", "pong"); err != nil {
log.Error("rds.Set error(%v)", err)
}
rconn.Close()
return
}
// Close close resource.
func (d *Dao) Close() {
d.db.Close()
d.mc.Close()
d.upRds.Close()
d.rgRds.Close()
}
func (d *Dao) fillArchives(c context.Context, am map[int64]*api.Arc, cached bool) {
var (
mids []int64
aids []int64
staffs map[int64][]*api.StaffInfo
cooperationOK error
err error
)
for _, a := range am {
a.Fill()
a.TypeName = d.tNamem[int16(a.TypeID)]
if a.Author.Mid > 0 {
mids = append(mids, a.Author.Mid)
}
if a.AttrVal(archive.AttrBitIsCooperation) == archive.AttrYes {
aids = append(aids, a.Aid)
}
}
mi, err := d.acc.Infos3(c, &accapi.MidsReq{Mids: mids})
if err != nil || mi == nil {
log.Error("d.acc.Infos(%v) error(%v)", mids, err)
mi = new(accapi.InfosReply)
}
if len(aids) > 0 {
staffs, cooperationOK = d.staffs(c, aids)
}
for _, a := range am {
if m, ok := mi.Infos[a.Author.Mid]; ok {
a.Author.Name = m.Name
a.Author.Face = m.Face
}
if a.AttrVal(archive.AttrBitIsCooperation) == archive.AttrYes {
if staff, ok := staffs[a.Aid]; ok {
a.StaffInfo = staff
}
}
if cached {
var ca = &api.Arc{}
*ca = *a
d.addCache(func() {
d.addArchive3Cache(context.TODO(), ca)
if ca.Author.Name == "" || ca.Author.Face == "" || cooperationOK != nil {
log.Error("account empty aid(%d) name(%s) face(%s)", ca.Aid, ca.Author.Name, ca.Author.Face)
d.sendUpperCache(context.TODO(), ca.Aid)
}
})
}
}
}
func (d *Dao) fillArchive3(c context.Context, a *api.Arc, cached bool) {
a.Fill()
a.TypeName = d.tNamem[int16(a.TypeID)]
if a.Author.Mid > 0 {
reply, err := d.acc.Info3(c, &accapi.MidReq{Mid: a.Author.Mid})
if err != nil || reply == nil {
log.Error("d.acc.Info(%d) error(%v)", a.Author.Mid, err)
err = nil
} else {
a.Author.Name = reply.Info.Name
a.Author.Face = reply.Info.Face
}
}
var (
staffs []*api.StaffInfo
cooperationOK error
)
// cooperation
if a.AttrVal(archive.AttrBitIsCooperation) == archive.AttrYes {
if staffs, cooperationOK = d.staff(c, a.Aid); cooperationOK == nil {
a.StaffInfo = staffs
}
}
if cached {
var ca = &api.Arc{}
*ca = *a
d.addCache(func() {
d.addArchive3Cache(context.TODO(), ca)
if ca.Author.Name == "" || ca.Author.Face == "" || cooperationOK != nil {
log.Error("account empty aid(%d) name(%s) face(%s)", ca.Aid, ca.Author.Name, ca.Author.Face)
d.sendUpperCache(context.TODO(), ca.Aid)
}
})
}
}
func (d *Dao) sendUpperCache(c context.Context, aid int64) {
for i := 0; i < 10; i++ {
err := d.cacheDatabus.Send(context.Background(), strconv.FormatInt(aid, 10), &ajbmdl.Rebuild{Aid: aid})
if err != nil {
log.Error("d.cacheDatabus.Send(%d) error(%v)", aid, err)
time.Sleep(50 * time.Millisecond)
continue
}
log.Info("sendUpperCache(%d) ok", aid)
break
}
}
func (d *Dao) loadReportResult() {
var (
reportResults map[int64]*arcmdl.ReportResult
err error
ar = make(map[int64]string)
)
reportResults, err = d.ReportResults(context.TODO())
if err != nil {
log.Error("d.ReportResults error(%v)", err)
return
}
for _, rr := range reportResults {
ar[rr.Aid] = rr.Result
}
d.aidResult = ar
}
func (d *Dao) loadTypes() {
var (
types map[int16]*archive.ArcType
nm = make(map[int16]string)
err error
)
if types, err = d.Types(context.TODO()); err != nil {
log.Error("d.Types error(%v)", err)
return
}
for _, t := range types {
nm[t.ID] = t.Name
}
d.tNamem = nm
}
func (d *Dao) cacheproc() {
for {
f, ok := <-d.cacheCh
if !ok {
return
}
f()
}
}
func (d *Dao) loadproc() {
for {
time.Sleep(time.Duration(d.c.Tick))
d.loadTypes()
d.loadReportResult()
}
}

View File

@@ -0,0 +1,163 @@
package archive
import (
"context"
"flag"
"go-common/app/service/main/archive/conf"
"os"
"testing"
"github.com/smartystreets/goconvey/convey"
)
var (
d *Dao
)
func TestMain(m *testing.M) {
if os.Getenv("DEPLOY_ENV") != "" {
flag.Set("app_id", "main.app-svr.archive-service")
flag.Set("conf_token", "Y2LJhIsHx87nJaOBSxuG5TeZoLdBFlrE")
flag.Set("tree_id", "2302")
flag.Set("conf_version", "docker-1")
flag.Set("deploy_env", "uat")
flag.Set("conf_host", "config.bilibili.co")
flag.Set("conf_path", "/tmp")
flag.Set("region", "sh")
flag.Set("zone", "sh001")
}
flag.Parse()
if err := conf.Init(); err != nil {
panic(err)
}
d = New(conf.Conf)
m.Run()
os.Exit(0)
}
func TestArchiveArchive3(t *testing.T) {
var (
c = context.TODO()
aid = int64(-1)
)
convey.Convey("Archive3", t, func(ctx convey.C) {
_, err := d.Archive3(c, aid)
ctx.Convey("Then err should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldNotBeNil)
})
})
}
func TestArchiveArchives3(t *testing.T) {
var (
c = context.TODO()
aids = []int64{1009799822}
)
convey.Convey("Archives3", t, func(ctx convey.C) {
am, err := d.Archives3(c, aids)
ctx.Convey("Then err should be nil.am should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(am, convey.ShouldNotBeNil)
})
})
}
func TestArchiveVideos3(t *testing.T) {
var (
c = context.TODO()
aid = int64(10097272)
)
convey.Convey("Videos3", t, func(ctx convey.C) {
vs, err := d.Videos3(c, aid)
ctx.Convey("Then err should be nil.vs should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(vs, convey.ShouldNotBeNil)
})
})
}
func TestArchiveVideosByAids3(t *testing.T) {
var (
c = context.TODO()
aids = []int64{10097272, 10098500}
)
convey.Convey("VideosByAids3", t, func(ctx convey.C) {
vs, err := d.VideosByAids3(c, aids)
ctx.Convey("Then err should be nil.vs should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(vs, convey.ShouldNotBeNil)
})
})
}
func TestArchiveVideo3(t *testing.T) {
var (
c = context.TODO()
aid = int64(1)
cid = int64(2)
)
convey.Convey("Video3", t, func(ctx convey.C) {
v, err := d.Video3(c, aid, cid)
ctx.Convey("Then err should not be nil.v should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldNotBeNil)
ctx.So(v, convey.ShouldBeNil)
})
})
}
func TestArchiveDescription(t *testing.T) {
var (
c = context.TODO()
aid = int64(1)
desc = "我是个大描述我是个大描述"
)
convey.Convey("Description", t, func(ctx convey.C) {
err := d.addDescCache(c, aid, desc)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
desc, err := d.descCache(context.TODO(), aid)
ctx.Convey("Then err should be nil.desc should not be nil", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(desc, convey.ShouldNotBeNil)
})
})
}
func TestArchiveUpVideo3(t *testing.T) {
var (
c = context.TODO()
aid = int64(1)
cid = int64(2)
)
convey.Convey("UpVideo3", t, func(ctx convey.C) {
v, err := d.Video3(c, aid, cid)
ctx.Convey("Then err should not be nil.v should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldNotBeNil)
ctx.So(v, convey.ShouldBeNil)
})
})
}
func TestArchiveUpperCache(t *testing.T) {
var (
c = context.TODO()
aid = int64(10098500)
)
convey.Convey("UpperCache", t, func(ctx convey.C) {
err := d.UpArchiveCache(c, aid)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
}
func Test_Ping(t *testing.T) {
var c = context.TODO()
convey.Convey("Ping", t, func(ctx convey.C) {
err := d.Ping(c)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
}

View File

@@ -0,0 +1,82 @@
package archive
import (
"context"
"net/http"
"net/url"
"strconv"
"go-common/app/service/main/archive/model/archive"
"go-common/library/ecode"
"go-common/library/xstr"
"github.com/pkg/errors"
)
// ValidateQn validate qn
func (d *Dao) ValidateQn(c context.Context, qn int) (allow bool) {
_, allow = d.playerQn[qn]
return
}
// VipQn vip qn
func (d *Dao) VipQn(c context.Context, qn int) (isVipQn bool) {
_, isVipQn = d.playerVipQn[qn]
return
}
// PlayerInfos cid with player info
func (d *Dao) PlayerInfos(c context.Context, cids []int64, qn int, platform, ip string, fnver, fnval, forceHost int) (pm map[uint32]*archive.BvcVideoItem, err error) {
params := url.Values{}
params.Set("cid", xstr.JoinInts(cids))
params.Set("qn", strconv.Itoa(qn))
params.Set("platform", platform)
params.Set("uip", ip)
params.Set("layout", "pb")
params.Set("fnver", strconv.Itoa(fnver))
params.Set("fnval", strconv.Itoa(fnval))
params.Set("force_host", strconv.Itoa(forceHost))
var req *http.Request
if req, err = d.playerClient.NewRequest("GET", d.c.PlayerAPI, ip, params); err != nil {
return
}
res := new(archive.BvcResponseMsg)
if err = d.playerClient.PB(c, req, res); err != nil {
return
}
if int(res.Code) != ecode.OK.Code() {
err = errors.Wrap(ecode.Int(int(res.Code)), d.c.PlayerAPI+params.Encode())
return
}
pm = res.Data
return
}
// PGCPlayerInfos cid with pgc player info
func (d *Dao) PGCPlayerInfos(c context.Context, aids []int64, platform, ip, session string, fnval, fnver int) (pgcm map[int64]*archive.PlayerInfo, err error) {
params := url.Values{}
params.Set("aids", xstr.JoinInts(aids))
params.Set("mobi_app", platform)
params.Set("ip", ip)
params.Set("fnver", strconv.Itoa(fnver))
params.Set("fnval", strconv.Itoa(fnval))
params.Set("session", session)
res := struct {
Code int `json:"code"`
Result map[int64]*archive.PGCPlayer `json:"result"`
}{}
if err = d.playerClient.Get(c, d.c.PGCPlayerAPI, ip, params, &res); err != nil {
return
}
if res.Code != 0 {
err = errors.Wrap(ecode.Int(res.Code), d.c.PGCPlayerAPI+params.Encode())
return
}
pgcm = make(map[int64]*archive.PlayerInfo)
for _, v := range res.Result {
if v.PlayerInfo != nil {
pgcm[v.PlayerInfo.Cid] = v.PlayerInfo
}
}
return
}

View File

@@ -0,0 +1,72 @@
package archive
import (
"context"
"encoding/json"
"testing"
"github.com/smartystreets/goconvey/convey"
)
func TestArchiveValidateQn(t *testing.T) {
var (
c = context.TODO()
qn = int(80)
)
convey.Convey("ValidateQn", t, func(ctx convey.C) {
allow := d.ValidateQn(c, qn)
ctx.Convey("Then allow should not be nil.", func(ctx convey.C) {
ctx.So(allow, convey.ShouldNotBeNil)
})
})
}
func TestArchiveVipQn(t *testing.T) {
var (
c = context.TODO()
qn = int(80)
)
convey.Convey("VipQn", t, func(ctx convey.C) {
isVipQn := d.VipQn(c, qn)
ctx.Convey("Then allow should not be nil.", func(ctx convey.C) {
ctx.So(isVipQn, convey.ShouldNotBeNil)
})
})
}
func TestArchivePlayerInfos(t *testing.T) {
var (
c = context.TODO()
cids = []int64{10133958}
qn = int(16)
platform = "ios"
ip = "127.0.0.1"
fnver = int(0)
fnval = int(8)
forceHost = int(0)
)
convey.Convey("PlayerInfos", t, func(ctx convey.C) {
d.PlayerInfos(c, cids, qn, platform, ip, fnver, fnval, forceHost)
})
}
func TestArchivePGCPlayerInfos(t *testing.T) {
var (
c = context.TODO()
aids = []int64{10111001}
platform = "iphone"
ip = "121.31.246.238"
session = ""
fnval = 16
fnver = 0
)
convey.Convey("PGCPlayerInfos", t, func(ctx convey.C) {
pm, err := d.PGCPlayerInfos(c, aids, platform, ip, session, fnval, fnver)
ctx.Convey("Then err should be nil.pm should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(pm, convey.ShouldNotBeNil)
p, _ := json.Marshal(pm)
convey.Printf("%s", p)
})
})
}

View File

@@ -0,0 +1,32 @@
package archive
import (
"context"
"go-common/app/service/main/archive/api"
"go-common/library/log"
)
const (
_rgnArcsSQL = "SELECT aid,attribute,copyright,pubtime FROM archive WHERE typeid=? and (state>=0 or state=-6) LIMIT ?,?"
)
// RegionArcs multi get archvies by rid.
func (d *Dao) RegionArcs(c context.Context, rid int16, start, length int) (ras []*api.RegionArc, err error) {
d.infoProm.Incr("RegionArcs")
rows, err := d.rgnArcsStmt.Query(c, rid, start, length)
if err != nil {
log.Error("rgnArcsStmt.Query error(%v)", err)
return
}
defer rows.Close()
for rows.Next() {
a := &api.RegionArc{}
if err = rows.Scan(&a.Aid, &a.Attribute, &a.Copyright, &a.PubDate); err != nil {
log.Error("rows.Scan error(%v)", err)
return
}
ras = append(ras, a)
}
return
}

View File

@@ -0,0 +1,257 @@
package archive
import (
"context"
"fmt"
"time"
"go-common/app/service/main/archive/api"
commarc "go-common/app/service/main/archive/model/archive"
"go-common/library/cache/redis"
"go-common/library/log"
)
const (
// all type archives
_allTypeKey = "bl_arc"
// all archives.
_suffixAll = "_a"
// origin archives copyright=1.
_suffixOrigin = "_o"
// top type archives
_suffixTopAll = "_t"
// top type expire
topTypeExpire = 3 * 24 * time.Hour
// all type expire
allTypeExpire = 7 * 24 * time.Hour
)
func rgAllKey(rid int16) string {
return fmt.Sprintf("%b", rid) + _suffixAll
}
func rgOriginKey(rid int16) string {
return fmt.Sprintf("%b", rid) + _suffixOrigin
}
func rgTopKey(rid int16) string {
return fmt.Sprintf("%b%s", rid, _suffixTopAll)
}
// AddRegionArcCache add archives into region cache.
func (d *Dao) AddRegionArcCache(c context.Context, rid, reid int16, as ...*api.RegionArc) (err error) {
var (
key = rgAllKey(rid)
okey = rgOriginKey(rid)
tpKey = rgTopKey(reid)
count int
conn = d.rgRds.Get(c)
)
defer conn.Close()
defer func() {
if err != nil {
d.errProm.Incr("regin_redis")
}
}()
for _, a := range as {
if !a.AllowShow() {
continue
}
if err = conn.Send("ZADD", tpKey, a.PubDate, a.Aid); err != nil {
log.Error("conn.Send(ZADD, %s, %d, %d) error(%v)")
return
}
count++
if err = conn.Send("ZREMRANGEBYSCORE", tpKey, "-inf", time.Now().Add(-time.Duration(topTypeExpire)).Unix()); err != nil {
log.Error("conn.Send(ZREMRANGEBYSCORE, %s, %d, %d) error(%v)", tpKey)
return
}
count++
if err = conn.Send("ZADD", key, a.PubDate, a.Aid); err != nil {
log.Error("conn.Send(ZADD, %s, %d) error(%v)", key, a.Aid, err)
return
}
count++
if a.Copyright == commarc.CopyrightOriginal {
if err = conn.Send("ZADD", okey, a.PubDate, a.Aid); err != nil {
log.Error("conn.Send(ZADD, %s, %d) error(%v)", okey, a.Aid, err)
return
}
count++
}
// 连载动画不记录
if rid != 33 {
if err = conn.Send("ZADD", _allTypeKey, a.PubDate, a.Aid); err != nil {
log.Error("conn.Send(ZADD, %s, %d, %d) error(%v)", _allTypeKey, a.PubDate, a.Aid, err)
return
}
count++
if err = conn.Send("ZREMRANGEBYSCORE", _allTypeKey, "-inf", time.Now().Add(-time.Duration(allTypeExpire)).Unix()); err != nil {
log.Error("conn.Send()")
return
}
count++
}
}
if count == 0 {
return
}
if err = conn.Flush(); err != nil {
log.Error("conn.Flush error(%v)", err)
return
}
for i := 0; i < count; i++ {
if _, err = conn.Receive(); err != nil {
log.Error("conn.Receive() error(%v)", err)
return
}
}
return
}
// RegionTopArcsCache top region archives.
func (d *Dao) RegionTopArcsCache(c context.Context, reid int16, start, end int) (aids []int64, err error) {
key := rgTopKey(reid)
if reid == 0 {
key = _allTypeKey
}
if aids, err = d.zrange(c, key, start, end); err != nil {
d.errProm.Incr("regin_redis")
log.Error("dao.zrange(%s, %d, %d) error(%v)", key, start, end, err)
}
return
}
// RegionArcsCache region archives.
func (d *Dao) RegionArcsCache(c context.Context, rid int16, start, end int) (aids []int64, err error) {
key := rgAllKey(rid)
aids, err = d.zrange(c, key, start, end)
return
}
// RegionOriginArcsCache region origin archives.
func (d *Dao) RegionOriginArcsCache(c context.Context, rid int16, start, end int) (aids []int64, err error) {
key := rgOriginKey(rid)
aids, err = d.zrange(c, key, start, end)
return
}
func (d *Dao) zrange(c context.Context, key string, start, end int) (aids []int64, err error) {
conn := d.rgRds.Get(c)
defer conn.Close()
values, err := redis.Values(conn.Do("ZREVRANGE", key, start, end))
if err != nil {
d.errProm.Incr("regin_redis")
log.Error("conn.Do(ZREVRANGE, %s) error(%v)", key, err)
return
}
if len(values) == 0 {
return
}
err = redis.ScanSlice(values, &aids)
return
}
// RegionTopCountCache top region count of archives.
func (d *Dao) RegionTopCountCache(c context.Context, reids []int16, min, max int64) (recm map[int16]int, err error) {
conn := d.rgRds.Get(c)
defer conn.Close()
for _, rid := range reids {
key := rgTopKey(rid)
if err = conn.Send("ZCOUNT", key, min, max); err != nil {
d.errProm.Incr("regin_redis")
log.Error("conn.Do(ZCOUNT, %s) error(%v)", key, err)
break
}
}
if err = conn.Flush(); err != nil {
log.Error("conn.Flush error(%v)", err)
return
}
recm = make(map[int16]int, len(reids))
for _, rid := range reids {
if recm[rid], err = redis.Int(conn.Receive()); err != nil {
d.errProm.Incr("regin_redis")
log.Error("conn.Receive error(%v)")
return
}
}
return
}
// RegionAllCountCache count of all type
func (d *Dao) RegionAllCountCache(c context.Context) (count int, err error) {
conn := d.rgRds.Get(c)
defer conn.Close()
count, err = redis.Int(conn.Do("ZCARD", _allTypeKey))
return
}
// RegionCountCache count of arcs.
func (d *Dao) RegionCountCache(c context.Context, rid int16) (count int, err error) {
conn := d.rgRds.Get(c)
defer conn.Close()
key := rgAllKey(rid)
count, err = redis.Int(conn.Do("ZCARD", key))
return
}
// RegionOriginCountCache count of arcs.
func (d *Dao) RegionOriginCountCache(c context.Context, rid int16) (count int, err error) {
conn := d.rgRds.Get(c)
defer conn.Close()
key := rgOriginKey(rid)
count, err = redis.Int(conn.Do("ZCARD", key))
return
}
// DelRegionArcCache delete from zset.
func (d *Dao) DelRegionArcCache(c context.Context, rid, reid int16, aid int64) (err error) {
conn := d.rgRds.Get(c)
defer conn.Close()
defer func() {
if err != nil {
d.errProm.Incr("regin_redis")
}
}()
var (
rgAllKey = rgAllKey(rid)
oKey = rgOriginKey(rid)
rgTopKey = rgTopKey(reid)
)
if err = conn.Send("ZREM", rgAllKey, aid); err != nil {
log.Error("conn.Send error(%v)", err)
return
}
if err = conn.Send("ZREM", oKey, aid); err != nil {
log.Error("conn.Send error(%v)", err)
return
}
if err = conn.Send("ZREM", rgTopKey, aid); err != nil {
log.Error("conn.Send(ZREM, %s, %d) error(%v)", rgTopKey, aid, err)
return
}
if err = conn.Send("ZREM", _allTypeKey, aid); err != nil {
log.Error("conn.Send(ZREM, %s, %d) error(%v)", _allTypeKey, aid, err)
return
}
if err = conn.Flush(); err != nil {
log.Error("conn.Flush error(%v)", err)
return
}
if _, err = conn.Receive(); err != nil {
log.Error("conn.Receive error(%v)", err)
return
}
if _, err = conn.Receive(); err != nil {
log.Error("conn.Receive error(%v)", err)
return
}
if _, err = conn.Receive(); err != nil {
log.Error("conn.Receive error(%v)", err)
}
if _, err = conn.Receive(); err != nil {
log.Error("conn.Receive error(%v)", err)
}
return
}

View File

@@ -0,0 +1,193 @@
package archive
import (
"context"
"go-common/app/service/main/archive/api"
"testing"
"github.com/smartystreets/goconvey/convey"
)
func TestArchivergAllKey(t *testing.T) {
var (
rid = int16(97)
)
convey.Convey("rgAllKey", t, func(ctx convey.C) {
p1 := rgAllKey(rid)
ctx.Convey("Then p1 should not be nil.", func(ctx convey.C) {
ctx.So(p1, convey.ShouldNotBeNil)
})
})
}
func TestArchivergOriginKey(t *testing.T) {
var (
rid = int16(97)
)
convey.Convey("rgOriginKey", t, func(ctx convey.C) {
p1 := rgOriginKey(rid)
ctx.Convey("Then p1 should not be nil.", func(ctx convey.C) {
ctx.So(p1, convey.ShouldNotBeNil)
})
})
}
func TestArchivergTopKey(t *testing.T) {
var (
rid = int16(97)
)
convey.Convey("rgTopKey", t, func(ctx convey.C) {
p1 := rgTopKey(rid)
ctx.Convey("Then p1 should not be nil.", func(ctx convey.C) {
ctx.So(p1, convey.ShouldNotBeNil)
})
})
}
func TestArchiveAddRegionArcCache(t *testing.T) {
var (
c = context.TODO()
rid = int16(97)
reid = int16(1)
as = &api.RegionArc{}
)
convey.Convey("AddRegionArcCache", t, func(ctx convey.C) {
err := d.AddRegionArcCache(c, rid, reid, as)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
}
func TestArchiveRegionTopArcsCache(t *testing.T) {
var (
c = context.TODO()
reid = int16(1)
start = int(0)
end = int(20)
)
convey.Convey("RegionTopArcsCache", t, func(ctx convey.C) {
_, err := d.RegionTopArcsCache(c, reid, start, end)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
}
func TestArchiveRegionArcsCache(t *testing.T) {
var (
c = context.TODO()
rid = int16(97)
start = int(0)
end = int(20)
)
convey.Convey("RegionArcsCache", t, func(ctx convey.C) {
aids, err := d.RegionArcsCache(c, rid, start, end)
ctx.Convey("Then err should be nil.aids should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(aids, convey.ShouldNotBeNil)
})
})
}
func TestArchiveRegionOriginArcsCache(t *testing.T) {
var (
c = context.TODO()
rid = int16(97)
start = int(0)
end = int(20)
)
convey.Convey("RegionOriginArcsCache", t, func(ctx convey.C) {
_, err := d.RegionOriginArcsCache(c, rid, start, end)
ctx.Convey("Then err should be nil.aids should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
}
func TestArchivezrange(t *testing.T) {
var (
c = context.TODO()
key = "1_o"
start = int(1)
end = int(10)
)
convey.Convey("zrange", t, func(ctx convey.C) {
_, err := d.zrange(c, key, start, end)
ctx.Convey("Then err should be nil.aids should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
}
func TestArchiveRegionTopCountCache(t *testing.T) {
var (
c = context.TODO()
reids = []int16{1}
min = int64(0)
max = int64(10)
)
convey.Convey("RegionTopCountCache", t, func(ctx convey.C) {
recm, err := d.RegionTopCountCache(c, reids, min, max)
ctx.Convey("Then err should be nil.recm should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(recm, convey.ShouldNotBeNil)
})
})
}
func TestArchiveRegionAllCountCache(t *testing.T) {
var (
c = context.TODO()
)
convey.Convey("RegionAllCountCache", t, func(ctx convey.C) {
count, err := d.RegionAllCountCache(c)
ctx.Convey("Then err should be nil.count should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(count, convey.ShouldNotBeNil)
})
})
}
func TestArchiveRegionCountCache(t *testing.T) {
var (
c = context.TODO()
rid = int16(97)
)
convey.Convey("RegionCountCache", t, func(ctx convey.C) {
count, err := d.RegionCountCache(c, rid)
ctx.Convey("Then err should be nil.count should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(count, convey.ShouldNotBeNil)
})
})
}
func TestArchiveRegionOriginCountCache(t *testing.T) {
var (
c = context.TODO()
rid = int16(97)
)
convey.Convey("RegionOriginCountCache", t, func(ctx convey.C) {
count, err := d.RegionOriginCountCache(c, rid)
ctx.Convey("Then err should be nil.count should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(count, convey.ShouldNotBeNil)
})
})
}
func TestArchiveDelRegionArcCache(t *testing.T) {
var (
c = context.TODO()
rid = int16(97)
reid = int16(1)
aid = int64(1)
)
convey.Convey("DelRegionArcCache", t, func(ctx convey.C) {
err := d.DelRegionArcCache(c, rid, reid, aid)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
}

View File

@@ -0,0 +1,23 @@
package archive
import (
"context"
"testing"
"github.com/smartystreets/goconvey/convey"
)
func TestArchiveRegionArcs(t *testing.T) {
var (
c = context.TODO()
rid = int16(97)
start = int(0)
length = int(10)
)
convey.Convey("RegionArcs", t, func(ctx convey.C) {
_, err := d.RegionArcs(c, rid, start, length)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
}

View File

@@ -0,0 +1,34 @@
package archive
import (
"context"
arcmdl "go-common/app/service/main/archive/model/archive"
"go-common/library/log"
)
const (
_reportResultSQL = "SELECT aid,result,state,adminid,after_deal FROM archive_report_result WHERE is_show=1"
)
// ReportResults get all report
func (d *Dao) ReportResults(c context.Context) (res map[int64]*arcmdl.ReportResult, err error) {
d.infoProm.Incr("ReportResults")
rows, err := d.reportResultStmt.Query(c)
if err != nil {
log.Error("d.reportResultStmt.Query() error(%v)", err)
return
}
defer rows.Close()
res = make(map[int64]*arcmdl.ReportResult)
for rows.Next() {
rr := &arcmdl.ReportResult{}
if err = rows.Scan(&rr.Aid, &rr.Result, &rr.State, &rr.AdminID, &rr.AfterDeal); err != nil {
log.Error("row.Scan error(%v)", err)
d.errProm.Incr("report_result_db")
return
}
res[rr.Aid] = rr
}
return
}

View File

@@ -0,0 +1,21 @@
package archive
import (
"context"
"testing"
"github.com/smartystreets/goconvey/convey"
)
func TestArchiveReportResults(t *testing.T) {
var (
c = context.TODO()
)
convey.Convey("ReportResults", t, func(ctx convey.C) {
res, err := d.ReportResults(c)
ctx.Convey("Then err should be nil.res should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(res, convey.ShouldNotBeNil)
})
})
}

View File

@@ -0,0 +1,89 @@
package archive
import (
"context"
"fmt"
"go-common/app/service/main/archive/api"
"go-common/library/database/sql"
"go-common/library/log"
"go-common/library/xstr"
)
const (
_statSharding = 100
// stat
_statSQL = "SELECT aid,fav,share,reply,coin,dm,click,now_rank,his_rank,likes FROM archive_stat_%02d WHERE aid=?"
_statsSQL = "SELECT aid,fav,share,reply,coin,dm,click,now_rank,his_rank,likes FROM archive_stat_%02d WHERE aid in (%s)"
// click
_clickSQL = "SELECT aid,web,h5,outside,ios,android FROM archive_click_%02d WHERE aid=?"
)
func statTbl(aid int64) int64 {
return aid % _statSharding
}
// stat3 archive stat.
func (d *Dao) stat3(c context.Context, aid int64) (st *api.Stat, err error) {
d.infoProm.Incr("stat3")
row := d.statDB.QueryRow(c, fmt.Sprintf(_statSQL, statTbl(aid)), aid)
st = &api.Stat{}
if err = row.Scan(&st.Aid, &st.Fav, &st.Share, &st.Reply, &st.Coin, &st.Danmaku, &st.View, &st.NowRank, &st.HisRank, &st.Like); err != nil {
if err == sql.ErrNoRows {
st = nil
err = nil
} else {
d.errProm.Incr("stat_db")
log.Error("row.Scan error(%v)", err)
}
return
}
return
}
// stats3 archive stats.
func (d *Dao) stats3(c context.Context, aids []int64) (sts map[int64]*api.Stat, err error) {
d.infoProm.Incr("stats3")
tbls := make(map[int64][]int64)
for _, aid := range aids {
tbls[statTbl(aid)] = append(tbls[statTbl(aid)], aid)
}
sts = make(map[int64]*api.Stat, len(aids))
for tbl, ids := range tbls {
var rows *sql.Rows
if rows, err = d.statDB.Query(c, fmt.Sprintf(_statsSQL, tbl, xstr.JoinInts(ids))); err != nil {
log.Error("d.statDB.Query(%s) error(%v)", fmt.Sprintf(_statsSQL, tbl, xstr.JoinInts(ids)), err)
d.errProm.Incr("stat_db")
return
}
for rows.Next() {
st := &api.Stat{}
if err = rows.Scan(&st.Aid, &st.Fav, &st.Share, &st.Reply, &st.Coin, &st.Danmaku, &st.View, &st.NowRank, &st.HisRank, &st.Like); err != nil {
log.Error("rows.Scan error(%v)", err)
d.errProm.Incr("stat_db")
rows.Close()
return
}
sts[st.Aid] = st
}
rows.Close()
}
return
}
// click3 archive click.
func (d *Dao) click3(c context.Context, aid int64) (cl *api.Click, err error) {
d.infoProm.Incr("click3")
row := d.clickDB.QueryRow(c, fmt.Sprintf(_clickSQL, statTbl(aid)), aid)
cl = &api.Click{}
if err = row.Scan(&cl.Aid, &cl.Web, &cl.H5, &cl.Outter, &cl.Ios, &cl.Android); err != nil {
if err == sql.ErrNoRows {
cl = nil
err = nil
} else {
log.Error("row.Scan error(%v)", err)
d.errProm.Incr("click_db")
}
}
return
}

View File

@@ -0,0 +1,188 @@
package archive
import (
"context"
"strconv"
"go-common/app/service/main/archive/api"
"go-common/library/cache/memcache"
"go-common/library/log"
)
const (
_prefixStatPB = "stp_"
_prefixClickPB = "clkp_"
)
type batchStat3 struct {
cached map[int64]*api.Stat
missed []int64
err error
}
func statPBKey(aid int64) string {
return _prefixStatPB + strconv.FormatInt(aid, 10)
}
func clickPBKey(aid int64) string {
return _prefixClickPB + strconv.FormatInt(aid, 10)
}
// statCache3 get a archive stat from cache.
func (d *Dao) statCache3(c context.Context, aid int64) (st *api.Stat, err error) {
var (
key = statPBKey(aid)
rp *memcache.Item
conn = d.mc.Get(c)
)
defer conn.Close()
if rp, err = conn.Get(key); err != nil {
if err == memcache.ErrNotFound {
err = nil
} else {
d.errProm.Incr("stat_mc")
log.Error("memcache.Get(%s) error(%v)", key, err)
}
return
}
st = new(api.Stat)
if err = conn.Scan(rp, st); err != nil {
log.Error("conn.Scan(%s) error(%v)", rp.Value, err)
return
}
st.DisLike = 0
return
}
// statCaches3 multi get archives stat, return map[aid]*Stat and missed aids.
func (d *Dao) statCaches3(c context.Context, aids []int64) (cached map[int64]*api.Stat, missed []int64, err error) {
var (
lt = len(aids)
times int
reqCh chan batchStat3
)
if lt%_multiInterval == 0 {
times = lt / _multiInterval
} else {
times = lt/_multiInterval + 1
}
reqCh = make(chan batchStat3, times)
for i := 0; i < times; i++ {
var tmps []int64
if i == times-1 {
tmps = aids[i*_multiInterval:]
} else {
tmps = aids[i*_multiInterval : (i+1)*_multiInterval]
}
go d._statCaches3(c, tmps, reqCh)
}
if times == 1 {
req := <-reqCh
cached = req.cached
missed = req.missed
err = req.err
return
}
cached = make(map[int64]*api.Stat, len(aids))
for i := 0; i < times; i++ {
req := <-reqCh
for k, v := range req.cached {
cached[k] = v
}
missed = append(missed, req.missed...)
}
return
}
func (d *Dao) _statCaches3(c context.Context, aids []int64, reqCh chan<- batchStat3) {
var (
req batchStat3
keys = make([]string, 0, len(aids))
am = make(map[int64]struct{}, len(aids))
rps map[string]*memcache.Item
err error
conn = d.mc.Get(c)
)
defer conn.Close()
for _, aid := range aids {
keys = append(keys, statPBKey(aid))
am[aid] = struct{}{}
}
if rps, err = conn.GetMulti(keys); err != nil {
req.missed = aids
req.err = err
reqCh <- req
log.Error("conn.Gets error(%v)", err)
d.errProm.Incr("stat_mc")
return
}
var (
cached = make(map[int64]*api.Stat, len(aids))
missed []int64
)
for _, rp := range rps {
var st = new(api.Stat)
if e := conn.Scan(rp, st); e != nil {
log.Error("conn.Scan(%s) error(%v)", rp.Value, e)
continue
}
st.DisLike = 0
cached[st.Aid] = st
delete(am, st.Aid)
}
for aid := range am {
missed = append(missed, aid)
}
req.cached = cached
req.missed = missed
reqCh <- req
}
// addStatCache set archive stat into cache.
func (d *Dao) addStatCache3(c context.Context, st *api.Stat) (err error) {
key := statPBKey(st.Aid)
conn := d.mc.Get(c)
st.DisLike = 0
if err = conn.Set(&memcache.Item{Key: key, Object: st, Flags: memcache.FlagProtobuf, Expiration: 0}); err != nil {
d.errProm.Incr("stat_mc")
log.Error("memcache.Set(%s) error(%v)", key, err)
}
conn.Close()
return
}
// clickCache get a archive click from cache.
func (d *Dao) clickCache3(c context.Context, aid int64) (clk *api.Click, err error) {
var (
key = clickPBKey(aid)
rp *memcache.Item
conn = d.mc.Get(c)
)
defer conn.Close()
if rp, err = conn.Get(key); err != nil {
if err == memcache.ErrNotFound {
err = nil
} else {
d.errProm.Incr("stat_mc")
log.Error("memcache.Get(%s) error(%v)", key, err)
}
return
}
clk = new(api.Click)
if err = conn.Scan(rp, clk); err != nil {
log.Error("conn.Scan(%s) error(%v)", rp.Value, err)
}
return
}
// addClickCache set archive click into cache.
func (d *Dao) addClickCache3(c context.Context, clk *api.Click) (err error) {
key := clickPBKey(clk.Aid)
conn := d.mc.Get(c)
if err = conn.Set(&memcache.Item{Key: key, Object: clk, Flags: memcache.FlagProtobuf, Expiration: 0}); err != nil {
d.errProm.Incr("stat_mc")
log.Error("memcache.Set(%s) error(%v)", key, err)
}
conn.Close()
return
}

View File

@@ -0,0 +1,100 @@
package archive
import (
"context"
"go-common/app/service/main/archive/api"
"testing"
"github.com/smartystreets/goconvey/convey"
)
func TestArchivestatPBKey(t *testing.T) {
var (
aid = int64(1)
)
convey.Convey("statPBKey", t, func(ctx convey.C) {
p1 := statPBKey(aid)
ctx.Convey("Then p1 should not be nil.", func(ctx convey.C) {
ctx.So(p1, convey.ShouldNotBeNil)
})
})
}
func TestArchiveclickPBKey(t *testing.T) {
var (
aid = int64(1)
)
convey.Convey("clickPBKey", t, func(ctx convey.C) {
p1 := clickPBKey(aid)
ctx.Convey("Then p1 should not be nil.", func(ctx convey.C) {
ctx.So(p1, convey.ShouldNotBeNil)
})
})
}
func TestArchivestatCache3(t *testing.T) {
var (
c = context.TODO()
aid = int64(1)
)
convey.Convey("statCache3", t, func(ctx convey.C) {
_, err := d.statCache3(c, aid)
ctx.Convey("Then err should be nil.st should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
}
func TestArchivestatCaches3(t *testing.T) {
var (
c = context.TODO()
aids = []int64{1, 2}
)
convey.Convey("statCaches3", t, func(ctx convey.C) {
cached, missed, err := d.statCaches3(c, aids)
ctx.Convey("Then err should be nil.cached,missed should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(missed, convey.ShouldNotBeNil)
ctx.So(cached, convey.ShouldNotBeNil)
})
})
}
func TestArchiveaddStatCache3(t *testing.T) {
var (
c = context.TODO()
st = &api.Stat{}
)
convey.Convey("addStatCache3", t, func(ctx convey.C) {
err := d.addStatCache3(c, st)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
}
func TestArchiveclickCache3(t *testing.T) {
var (
c = context.TODO()
aid = int64(1)
)
convey.Convey("clickCache3", t, func(ctx convey.C) {
_, err := d.clickCache3(c, aid)
ctx.Convey("Then err should be nil.clk should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
}
func TestArchiveaddClickCache3(t *testing.T) {
var (
c = context.TODO()
clk = &api.Click{}
)
convey.Convey("addClickCache3", t, func(ctx convey.C) {
err := d.addClickCache3(c, clk)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
}

View File

@@ -0,0 +1,139 @@
package archive
import (
"context"
"go-common/app/service/main/archive/api"
"go-common/library/log"
)
// SetStat3 set all stat
func (d *Dao) SetStat3(c context.Context, st *api.Stat) (err error) {
d.addStatCache3(c, st)
var clk *api.Click
if clk, err = d.click3(c, st.Aid); err != nil {
log.Error("d.stat(%d) error(%v)", st.Aid, err)
return
}
if clk == nil {
clk = &api.Click{Aid: st.Aid}
}
d.addCache(func() {
d.addClickCache3(context.TODO(), clk)
})
return
}
// Stat3 get archive stat.
func (d *Dao) Stat3(c context.Context, aid int64) (st *api.Stat, err error) {
var cached = true
if st, err = d.statCache3(c, aid); err != nil {
log.Error("d.statCache(%d) error(%v)", aid, err)
cached = false
}
if st != nil {
return
}
if st, err = d.stat3(c, aid); err != nil {
log.Error("d.stat(%d) error(%v)", aid, err)
return
}
if st == nil {
st = &api.Stat{Aid: aid}
return
}
if cached {
d.addCache(func() {
d.addStatCache3(context.TODO(), st)
})
}
return
}
// Stats3 get archives stat.
func (d *Dao) Stats3(c context.Context, aids []int64) (stm map[int64]*api.Stat, err error) {
if len(aids) == 0 {
return
}
var (
missed []int64
missm map[int64]*api.Stat
cached = true
)
if stm, missed, err = d.statCaches3(c, aids); err != nil {
log.Error("d.statCaches(%d) error(%v)", aids, err)
missed = aids
stm = make(map[int64]*api.Stat, len(aids))
err = nil // ignore error
cached = false
}
if stm != nil && len(missed) == 0 {
return
}
if missm, err = d.stats3(c, missed); err != nil {
log.Error("d.stats(%v) error(%v)", missed, err)
err = nil // ignore error
}
for aid, st := range missm {
stm[aid] = st
if cached {
var cst = &api.Stat{}
*cst = *st
d.addCache(func() {
d.addStatCache3(context.TODO(), cst)
})
}
}
return
}
// Click3 get archive click.
func (d *Dao) Click3(c context.Context, aid int64) (clk *api.Click, err error) {
var cached = true
if clk, err = d.clickCache3(c, aid); err != nil {
log.Error("d.clickCache(%d) error(%v)", aid, err)
cached = false
}
if clk != nil {
return
}
if clk, err = d.click3(c, aid); err != nil {
log.Error("d.stat(%d) error(%v)", aid, err)
return
}
if clk == nil {
clk = &api.Click{Aid: aid}
return
}
if cached {
d.addCache(func() {
d.addClickCache3(context.TODO(), clk)
})
}
return
}
// InitStatCache3 if db is nil, set nil cache
func (d *Dao) InitStatCache3(c context.Context, aid int64) (err error) {
var st *api.Stat
if st, err = d.stat3(c, aid); err != nil {
log.Error("d.stat(%d) error(%v)", aid, err)
return
}
if st == nil {
d.addCache(func() {
d.addStatCache3(context.TODO(), &api.Stat{Aid: aid})
})
}
var clk *api.Click
if clk, err = d.click3(c, aid); err != nil {
log.Error("d.stat(%d) error(%v)", aid, err)
return
}
if clk == nil {
d.addCache(func() {
d.addClickCache3(context.TODO(), &api.Click{Aid: aid})
})
}
return
}

View File

@@ -0,0 +1,77 @@
package archive
import (
"context"
"go-common/app/service/main/archive/api"
"testing"
"github.com/smartystreets/goconvey/convey"
)
func TestArchiveSetStat3(t *testing.T) {
var (
c = context.TODO()
st = &api.Stat{}
)
convey.Convey("SetStat3", t, func(ctx convey.C) {
err := d.SetStat3(c, st)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
}
func TestArchiveStat3(t *testing.T) {
var (
c = context.TODO()
aid = int64(10097272)
)
convey.Convey("Stat3", t, func(ctx convey.C) {
st, err := d.Stat3(c, aid)
ctx.Convey("Then err should be nil.st should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(st, convey.ShouldNotBeNil)
})
})
}
func TestArchiveStats3(t *testing.T) {
var (
c = context.TODO()
aids = []int64{10097272}
)
convey.Convey("Stats3", t, func(ctx convey.C) {
stm, err := d.Stats3(c, aids)
ctx.Convey("Then err should be nil.stm should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(stm, convey.ShouldNotBeNil)
})
})
}
func TestArchiveClick3(t *testing.T) {
var (
c = context.TODO()
aid = int64(10097272)
)
convey.Convey("Click3", t, func(ctx convey.C) {
clk, err := d.Click3(c, aid)
ctx.Convey("Then err should be nil.clk should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(clk, convey.ShouldNotBeNil)
})
})
}
func TestArchiveInitStatCache3(t *testing.T) {
var (
c = context.TODO()
aid = int64(10097272)
)
convey.Convey("InitStatCache3", t, func(ctx convey.C) {
err := d.InitStatCache3(c, aid)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
}

View File

@@ -0,0 +1,46 @@
package archive
import (
"context"
"testing"
"github.com/smartystreets/goconvey/convey"
)
func TestArchivestatTbl(t *testing.T) {
var (
aid = int64(1)
)
convey.Convey("statTbl", t, func(ctx convey.C) {
p1 := statTbl(aid)
ctx.Convey("Then p1 should not be nil.", func(ctx convey.C) {
ctx.So(p1, convey.ShouldNotBeNil)
})
})
}
func TestArchivestat3(t *testing.T) {
var (
c = context.TODO()
aid = int64(10097272)
)
convey.Convey("stat3", t, func(ctx convey.C) {
_, err := d.stat3(c, aid)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
}
func TestArchivestats3(t *testing.T) {
var (
c = context.TODO()
aids = []int64{10097272}
)
convey.Convey("stats3", t, func(ctx convey.C) {
_, err := d.stats3(c, aids)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
}

View File

@@ -0,0 +1,38 @@
package archive
import (
"context"
"go-common/app/service/main/archive/model/archive"
"go-common/library/database/sql"
"go-common/library/log"
)
const (
_tpsSQL = "SELECT id,pid,name FROM archive_type"
)
// Types get type relation.
//func (d *Dao) Types(c context.Context) (nm map[int16]string, rids []int16, sf map[int16]int16, err error) {
func (d *Dao) Types(c context.Context) (types map[int16]*archive.ArcType, err error) {
d.infoProm.Incr("Types")
var rows *sql.Rows
if rows, err = d.tpsStmt.Query(c); err != nil {
log.Error("tpsStmt.Query error(%v)", err)
return
}
defer rows.Close()
types = make(map[int16]*archive.ArcType)
for rows.Next() {
var (
rid, pid int16
name string
)
if err = rows.Scan(&rid, &pid, &name); err != nil {
log.Error("rows.Scan error(%v)", err)
return
}
types[rid] = &archive.ArcType{ID: rid, Pid: pid, Name: name}
}
return
}

View File

@@ -0,0 +1,21 @@
package archive
import (
"context"
"testing"
"github.com/smartystreets/goconvey/convey"
)
func TestArchiveTypes(t *testing.T) {
var (
c = context.TODO()
)
convey.Convey("Types", t, func(ctx convey.C) {
types, err := d.Types(c)
ctx.Convey("Then err should be nil.types should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(types, convey.ShouldNotBeNil)
})
})
}

View File

@@ -0,0 +1,128 @@
package archive
import (
"context"
"fmt"
"go-common/library/log"
"go-common/library/time"
"go-common/library/xstr"
"github.com/pkg/errors"
)
const (
_upCntSQL = "SELECT COUNT(*) FROM archive WHERE mid=? AND (state>=0 or state=-6)"
_upsCntSQL = "SELECT mid,COUNT(*) FROM archive WHERE mid IN(%s) AND (state>=0 or state=-6) GROUP BY mid"
_upPasSQL = "SELECT aid,pubtime,copyright FROM archive WHERE mid=? AND state>=0 ORDER BY pubtime DESC"
_upsPasSQL = "SELECT aid,mid,pubtime,copyright FROM archive WHERE mid IN (%s) AND state>=0 ORDER BY pubtime DESC"
_upRecommendSQL = "SELECT reco_aid FROM archive_recommend WHERE aid=? AND state=0"
)
// UppersCount get mids count
func (d *Dao) UppersCount(c context.Context, mids []int64) (uc map[int64]int, err error) {
rows, err := d.resultDB.Query(c, fmt.Sprintf(_upsCntSQL, xstr.JoinInts(mids)))
if err != nil {
err = errors.WithStack(err)
return
}
uc = make(map[int64]int, len(mids))
defer rows.Close()
for rows.Next() {
var (
mid int64
cnt int
)
if err = rows.Scan(&mid, &cnt); err != nil {
err = errors.WithStack(err)
return
}
uc[mid] = cnt
}
return
}
// UpperCount get the count of archives by mid of Up.
func (d *Dao) UpperCount(c context.Context, mid int64) (count int, err error) {
d.infoProm.Incr("UpperCount")
row := d.upCntStmt.QueryRow(c, mid)
if err = row.Scan(&count); err != nil {
log.Error("row.Scan error(%v)", err)
}
return
}
// UpperPassed get upper passed archives.
func (d *Dao) UpperPassed(c context.Context, mid int64) (aids []int64, ptimes []time.Time, copyrights []int8, err error) {
d.infoProm.Incr("UpperPassed")
rows, err := d.upPasStmt.Query(c, mid)
if err != nil {
log.Error("getUpPasStmt.Query(%d) error(%v)", mid, err)
return
}
defer rows.Close()
for rows.Next() {
var (
aid int64
ptime time.Time
copyright int8
)
if err = rows.Scan(&aid, &ptime, &copyright); err != nil {
log.Error("rows.Scan error(%v)", err)
return
}
aids = append(aids, aid)
ptimes = append(ptimes, ptime)
copyrights = append(copyrights, copyright)
}
return
}
// UppersPassed get uppers passed archives.
func (d *Dao) UppersPassed(c context.Context, mids []int64) (aidm map[int64][]int64, ptimes map[int64][]time.Time, copyrights map[int64][]int8, err error) {
d.infoProm.Incr("UppersPassed")
rows, err := d.resultDB.Query(c, fmt.Sprintf(_upsPasSQL, xstr.JoinInts(mids)))
if err != nil {
log.Error("UpsPassed error(%v)", err)
return
}
defer rows.Close()
aidm = make(map[int64][]int64, len(mids))
ptimes = make(map[int64][]time.Time, len(mids))
copyrights = make(map[int64][]int8, len(mids))
for rows.Next() {
var (
aid, mid int64
ptime time.Time
copyright int8
)
if err = rows.Scan(&aid, &mid, &ptime, &copyright); err != nil {
log.Error("rows.Scan error(%v)", err)
return
}
aidm[mid] = append(aidm[mid], aid)
ptimes[mid] = append(ptimes[mid], ptime)
copyrights[mid] = append(copyrights[mid], copyright)
}
return
}
// UpperReommend get up recommend
func (d *Dao) UpperReommend(c context.Context, aid int64) (reAids []int64, err error) {
d.infoProm.Incr("UpperRecommend")
rows, err := d.arcReadDB.Query(c, _upRecommendSQL, aid)
if err != nil {
log.Error("d.arcReadDB.Query(%s, %d) error(%v)", _upRecommendSQL, aid)
return
}
defer rows.Close()
for rows.Next() {
var reAid int64
if err = rows.Scan(&reAid); err != nil {
log.Error("rows.Scan error(%v)", err)
return
}
reAids = append(reAids, reAid)
}
return
}

View File

@@ -0,0 +1,316 @@
package archive
import (
"context"
"strconv"
"go-common/app/service/main/archive/model/archive"
"go-common/library/cache/redis"
"go-common/library/log"
"go-common/library/time"
)
const (
_prefixUpCnt = "uc_"
_prefixUpPas = "up_"
)
func upCntKey(mid int64) string {
return _prefixUpCnt + strconv.FormatInt(mid, 10)
}
func upPasKey(mid int64) string {
return _prefixUpPas + strconv.FormatInt(mid, 10)
}
// AddUpperCountCache the count of up's archives
func (d *Dao) AddUpperCountCache(c context.Context, mid int64, count int) (err error) {
var (
key = upCntKey(mid)
conn = d.upRds.Get(c)
expireTime = d.upExpire
)
defer conn.Close()
if count == 0 {
expireTime = 600
}
if _, err = conn.Do("SETEX", key, expireTime, count); err != nil {
log.Error("conn.Do(SETEX, %s, %d, %d)", key, expireTime, count)
return
}
return
}
// UpperCountCache get up count from cache.
func (d *Dao) UpperCountCache(c context.Context, mid int64) (count int, err error) {
var (
key = upCntKey(mid)
conn = d.upRds.Get(c)
)
defer conn.Close()
if count, err = redis.Int(conn.Do("GET", key)); err != nil {
if err == redis.ErrNil {
count = -1
err = nil
} else {
d.errProm.Incr("upper_redis")
log.Error("conn.Do(GET, %s) error(%v)", key, err)
}
}
return
}
// UppersCountCache return uppers count cache
func (d *Dao) UppersCountCache(c context.Context, mids []int64) (cached map[int64]int, missed []int64, err error) {
conn := d.upRds.Get(c)
defer conn.Close()
cached = make(map[int64]int)
for _, mid := range mids {
key := upCntKey(mid)
if err = conn.Send("GET", key); err != nil {
missed = mids
continue
}
}
if err = conn.Flush(); err != nil {
missed = mids
return
}
for _, mid := range mids {
var cnt int
if cnt, err = redis.Int(conn.Receive()); err != nil {
if err == redis.ErrNil {
missed = append(missed, mid)
err = nil
continue
}
}
cached[mid] = cnt
}
return
}
// UpperPassedCache get upper passed archives from cache.
func (d *Dao) UpperPassedCache(c context.Context, mid int64, start, end int) (aids []int64, err error) {
var (
key = upPasKey(mid)
conn = d.upRds.Get(c)
)
defer conn.Close()
if aids, err = redis.Int64s(conn.Do("ZREVRANGE", key, start, end)); err != nil {
d.errProm.Incr("upper_redis")
log.Error("conn.Do(ZRANGE, %s, 0, -1) error(%v)", key, err)
}
return
}
// UppersPassedCacheWithScore get uppers passed archive from cache with score
func (d *Dao) UppersPassedCacheWithScore(c context.Context, mids []int64, start, end int) (aidm map[int64][]*archive.AidPubTime, err error) {
conn := d.upRds.Get(c)
defer conn.Close()
aidm = make(map[int64][]*archive.AidPubTime, len(mids))
for _, mid := range mids {
key := upPasKey(mid)
if err = conn.Send("ZREVRANGE", key, start, end, "WITHSCORES"); err != nil {
d.errProm.Incr("upper_redis")
log.Error("conn.Send(ZREVRANGE, %s) error(%v)", key, err)
return
}
}
if err = conn.Flush(); err != nil {
log.Error("conn.Flush error(%v)", err)
return
}
for _, mid := range mids {
aidScores, err := redis.Int64s(conn.Receive())
if err != nil {
d.errProm.Incr("upper_redis")
log.Error("conn.Do(GET, %d) error(%v)", mid, err)
continue
}
for i := 0; i < len(aidScores); i += 2 {
var (
score int64
ptime int64
copyright int8
)
score = aidScores[i+1]
if score > 1000000000 {
ptime = score >> 2
copyright = int8(score & 3)
aidm[mid] = append(aidm[mid], &archive.AidPubTime{Aid: aidScores[i], PubDate: time.Time(ptime), Copyright: copyright})
} else {
aidm[mid] = append(aidm[mid], &archive.AidPubTime{Aid: aidScores[i], PubDate: time.Time(score)})
}
}
}
return
}
// UppersPassedCache get uppers passed archives from cache.
func (d *Dao) UppersPassedCache(c context.Context, mids []int64, start, end int) (aidm map[int64][]int64, err error) {
conn := d.upRds.Get(c)
defer conn.Close()
aidm = make(map[int64][]int64, len(mids))
for _, mid := range mids {
key := upPasKey(mid)
if err = conn.Send("ZREVRANGE", key, start, end); err != nil {
d.errProm.Incr("upper_redis")
log.Error("conn.Send(ZREVRANGE, %s) error(%v)", key, err)
return
}
}
if err = conn.Flush(); err != nil {
log.Error("conn.Flush error(%v)", err)
return
}
for _, mid := range mids {
aids, err := redis.Int64s(conn.Receive())
if err != nil {
d.errProm.Incr("upper_redis")
log.Error("conn.Do(GET, %d) error(%v)", mid, err)
continue
}
aidm[mid] = aids
}
return
}
// ExpireUpperPassedCache expire up passed cache.
func (d *Dao) ExpireUpperPassedCache(c context.Context, mid int64) (ok bool, err error) {
var (
key = upPasKey(mid)
conn = d.upRds.Get(c)
)
defer conn.Close()
if ok, err = redis.Bool(conn.Do("EXPIRE", key, d.upExpire)); err != nil {
d.errProm.Incr("upper_redis")
log.Error("conn.Do(EXPIRE, %s, %d) error(%v)", key, d.upExpire, err)
}
return
}
// ExpireUppersCountCache expire ups count cache
func (d *Dao) ExpireUppersCountCache(c context.Context, mids []int64) (cachedUp, missed []int64, err error) {
var conn = d.upRds.Get(c)
defer conn.Close()
defer func() {
if err != nil {
d.errProm.Incr("upper_redis")
}
}()
for _, mid := range mids {
var key = upCntKey(mid)
if err = conn.Send("GET", key); err != nil {
log.Error("conn.Send(GET, %s) error(%v)", key, err)
return
}
}
for _, mid := range mids {
var key = upCntKey(mid)
if err = conn.Send("EXPIRE", key, d.upExpire); err != nil {
log.Error("conn.Send(GET, %s) error(%v)", key, err)
return
}
}
if err = conn.Flush(); err != nil {
log.Error("conn.Flush error(%v)", err)
return
}
cachedUp = make([]int64, 0)
missed = make([]int64, 0)
for _, mid := range mids {
var cnt int
if cnt, err = redis.Int(conn.Receive()); err != nil {
if err == redis.ErrNil {
err = nil
missed = append(missed, mid)
} else {
log.Error("conn.Receive error(%v)", err)
return
}
} else if cnt > 0 {
cachedUp = append(cachedUp, mid)
}
}
for _, mid := range mids {
if _, err = redis.Bool(conn.Receive()); err != nil {
log.Error("conn.Receive mid(%d) error(%v)", mid, err)
return
}
}
return
}
// ExpireUppersPassedCache expire uppers passed cache.
func (d *Dao) ExpireUppersPassedCache(c context.Context, mids []int64) (res map[int64]bool, err error) {
conn := d.upRds.Get(c)
defer conn.Close()
res = make(map[int64]bool, len(mids))
for _, mid := range mids {
key := upPasKey(mid)
if err = conn.Send("EXPIRE", key, d.upExpire); err != nil {
d.errProm.Incr("upper_redis")
log.Error("conn.Send(%s) error(%v)", key, err)
return
}
}
if err = conn.Flush(); err != nil {
log.Error("conn.Flush error(%v)", err)
return
}
var ok bool
for _, mid := range mids {
if ok, err = redis.Bool(conn.Receive()); err != nil {
d.errProm.Incr("upper_redis")
log.Error("conn.Receive() error(%v)", err)
return
}
res[mid] = ok
}
return
}
// AddUpperPassedCache add up paassed cache.
func (d *Dao) AddUpperPassedCache(c context.Context, mid int64, aids []int64, ptimes []time.Time, copyrights []int8) (err error) {
var (
key = upPasKey(mid)
conn = d.upRds.Get(c)
)
defer conn.Close()
for k, aid := range aids {
score := int64(ptimes[k]<<2) | int64(copyrights[k])
if err = conn.Send("ZADD", key, score, aid); err != nil {
d.errProm.Incr("upper_redis")
log.Error("conn.Send(ZADD, %s, %d, %d) error(%v)", key, aid, ptimes[k], err)
return
}
}
if err = conn.Flush(); err != nil {
d.errProm.Incr("upper_redis")
log.Error("conn.Flush error(%v)", err)
return
}
for i := 0; i < len(aids); i++ {
if _, err = conn.Receive(); err != nil {
d.errProm.Incr("upper_redis")
log.Error("conn.Receive error(%v)", err)
return
}
}
return
}
// DelUpperPassedCache delete up passed cache.
func (d *Dao) DelUpperPassedCache(c context.Context, mid, aid int64) (err error) {
var (
key = upPasKey(mid)
conn = d.upRds.Get(c)
)
defer conn.Close()
if _, err = conn.Do("ZREM", key, aid); err != nil {
d.errProm.Incr("upper_redis")
log.Error("conn.Do(ZERM, %s, %d) error(%v)", key, aid, err)
}
return
}

View File

@@ -0,0 +1,196 @@
package archive
import (
"context"
"go-common/library/time"
"testing"
"github.com/smartystreets/goconvey/convey"
)
func TestArchiveupCntKey(t *testing.T) {
var (
mid = int64(1)
)
convey.Convey("upCntKey", t, func(ctx convey.C) {
p1 := upCntKey(mid)
ctx.Convey("Then p1 should not be nil.", func(ctx convey.C) {
ctx.So(p1, convey.ShouldNotBeNil)
})
})
}
func TestArchiveupPasKey(t *testing.T) {
var (
mid = int64(1)
)
convey.Convey("upPasKey", t, func(ctx convey.C) {
p1 := upPasKey(mid)
ctx.Convey("Then p1 should not be nil.", func(ctx convey.C) {
ctx.So(p1, convey.ShouldNotBeNil)
})
})
}
func TestArchiveAddUpperCountCache(t *testing.T) {
var (
c = context.TODO()
mid = int64(1)
count = int(10)
)
convey.Convey("AddUpperCountCache", t, func(ctx convey.C) {
err := d.AddUpperCountCache(c, mid, count)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
}
func TestArchiveUpperCountCache(t *testing.T) {
var (
c = context.TODO()
mid = int64(1)
)
convey.Convey("UpperCountCache", t, func(ctx convey.C) {
count, err := d.UpperCountCache(c, mid)
ctx.Convey("Then err should be nil.count should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(count, convey.ShouldNotBeNil)
})
})
}
func TestArchiveUppersCountCache(t *testing.T) {
var (
c = context.TODO()
mids = []int64{1, 2}
)
convey.Convey("UppersCountCache", t, func(ctx convey.C) {
cached, missed, err := d.UppersCountCache(c, mids)
ctx.Convey("Then err should be nil.cached,missed should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(missed, convey.ShouldNotBeNil)
ctx.So(cached, convey.ShouldNotBeNil)
})
})
}
func TestArchiveUpperPassedCache(t *testing.T) {
var (
c = context.TODO()
mid = int64(1)
start = int(0)
end = int(10)
)
convey.Convey("UpperPassedCache", t, func(ctx convey.C) {
_, err := d.UpperPassedCache(c, mid, start, end)
ctx.Convey("Then err should be nil.aids should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
}
func TestArchiveUppersPassedCacheWithScore(t *testing.T) {
var (
c = context.TODO()
mids = []int64{1, 2}
start = int(0)
end = int(10)
)
convey.Convey("UppersPassedCacheWithScore", t, func(ctx convey.C) {
aidm, err := d.UppersPassedCacheWithScore(c, mids, start, end)
ctx.Convey("Then err should be nil.aidm should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(aidm, convey.ShouldNotBeNil)
})
})
}
func TestArchiveUppersPassedCache(t *testing.T) {
var (
c = context.TODO()
mids = []int64{1, 2}
start = int(0)
end = int(10)
)
convey.Convey("UppersPassedCache", t, func(ctx convey.C) {
aidm, err := d.UppersPassedCache(c, mids, start, end)
ctx.Convey("Then err should be nil.aidm should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(aidm, convey.ShouldNotBeNil)
})
})
}
func TestArchiveExpireUpperPassedCache(t *testing.T) {
var (
c = context.TODO()
mid = int64(1)
)
convey.Convey("ExpireUpperPassedCache", t, func(ctx convey.C) {
ok, err := d.ExpireUpperPassedCache(c, mid)
ctx.Convey("Then err should be nil.ok should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(ok, convey.ShouldNotBeNil)
})
})
}
func TestArchiveExpireUppersCountCache(t *testing.T) {
var (
c = context.TODO()
mids = []int64{1, 2}
)
convey.Convey("ExpireUppersCountCache", t, func(ctx convey.C) {
cachedUp, missed, err := d.ExpireUppersCountCache(c, mids)
ctx.Convey("Then err should be nil.cachedUp,missed should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(missed, convey.ShouldNotBeNil)
ctx.So(cachedUp, convey.ShouldNotBeNil)
})
})
}
func TestArchiveExpireUppersPassedCache(t *testing.T) {
var (
c = context.TODO()
mids = []int64{1, 2}
)
convey.Convey("ExpireUppersPassedCache", t, func(ctx convey.C) {
res, err := d.ExpireUppersPassedCache(c, mids)
ctx.Convey("Then err should be nil.res should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(res, convey.ShouldNotBeNil)
})
})
}
func TestArchiveAddUpperPassedCache(t *testing.T) {
var (
c = context.TODO()
mid = int64(1)
aids = []int64{1}
ptimes = []time.Time{1531553274}
copyrights = []int8{1}
)
convey.Convey("AddUpperPassedCache", t, func(ctx convey.C) {
err := d.AddUpperPassedCache(c, mid, aids, ptimes, copyrights)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
}
func TestArchiveDelUpperPassedCache(t *testing.T) {
var (
c = context.TODO()
mid = int64(1)
aid = int64(1)
)
convey.Convey("DelUpperPassedCache", t, func(ctx convey.C) {
err := d.DelUpperPassedCache(c, mid, aid)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
}

View File

@@ -0,0 +1,78 @@
package archive
import (
"context"
"testing"
"github.com/smartystreets/goconvey/convey"
)
func TestArchiveUppersCount(t *testing.T) {
var (
c = context.TODO()
mids = []int64{1, 2}
)
convey.Convey("UppersCount", t, func(ctx convey.C) {
uc, err := d.UppersCount(c, mids)
ctx.Convey("Then err should be nil.uc should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(uc, convey.ShouldNotBeNil)
})
})
}
func TestArchiveUpperCount(t *testing.T) {
var (
c = context.TODO()
mid = int64(1)
)
convey.Convey("UpperCount", t, func(ctx convey.C) {
count, err := d.UpperCount(c, mid)
ctx.Convey("Then err should be nil.count should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(count, convey.ShouldNotBeNil)
})
})
}
func TestArchiveUpperPassed(t *testing.T) {
var (
c = context.TODO()
mid = int64(1)
)
convey.Convey("UpperPassed", t, func(ctx convey.C) {
_, _, _, err := d.UpperPassed(c, mid)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
}
func TestArchiveUppersPassed(t *testing.T) {
var (
c = context.TODO()
mids = []int64{1}
)
convey.Convey("UppersPassed", t, func(ctx convey.C) {
aidm, ptimes, copyrights, err := d.UppersPassed(c, mids)
ctx.Convey("Then err should be nil.aidm,ptimes,copyrights should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(copyrights, convey.ShouldNotBeNil)
ctx.So(ptimes, convey.ShouldNotBeNil)
ctx.So(aidm, convey.ShouldNotBeNil)
})
})
}
func TestArchiveUpperReommend(t *testing.T) {
var (
c = context.TODO()
aid = int64(10097272)
)
convey.Convey("UpperReommend", t, func(ctx convey.C) {
_, err := d.UpperReommend(c, aid)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
}

View File

@@ -0,0 +1,162 @@
package archive
import (
"context"
"database/sql"
"fmt"
"go-common/app/service/main/archive/api"
"go-common/library/log"
"go-common/library/xstr"
)
const (
_vdosSQL = "SELECT cid,src_type,index_order,eptitle,duration,filename,weblink,dimensions FROM archive_video WHERE aid=? ORDER BY index_order"
_vdosByAidsSQL = "SELECT aid,cid,src_type,index_order,eptitle,duration,filename,weblink,dimensions FROM archive_video WHERE aid in (%s) ORDER BY index_order"
_vdosByCidsSQL = "SELECT aid,cid,src_type,index_order,eptitle,duration,filename,weblink FROM archive_video WHERE cid IN (%s)"
_vdoSQL = "SELECT cid,src_type,index_order,eptitle,duration,filename,weblink,description,dimensions FROM archive_video WHERE aid=? AND cid=?"
_firstCidSQL = "SELECT cid,src_type,dimensions FROM archive_video WHERE aid=? ORDER BY index_order LIMIT 1"
)
// firstCid get first cid
func (d *Dao) firstCid(c context.Context, aid int64) (cid int64, dimensions string, err error) {
var srcType string
row := d.resultDB.QueryRow(c, _firstCidSQL, aid)
if err = row.Scan(&cid, &srcType, &dimensions); err != nil {
if err == sql.ErrNoRows {
err = nil
} else {
log.Error("row.Scan error(%v)", err)
}
return
}
if srcType != "vupload" {
cid = 0
}
return
}
// videos3 get videos by aid.
func (d *Dao) videos3(c context.Context, aid int64) (ps []*api.Page, err error) {
d.infoProm.Incr("videos3")
rows, err := d.vdosStmt.Query(c, aid)
if err != nil {
d.errProm.Incr("archive_db")
log.Error("d.vdosStmt.Query(%d) error(%v)", aid, err)
return
}
defer rows.Close()
var page = int32(0)
for rows.Next() {
var (
p = &api.Page{}
fn string
dimensions string
)
page++
if err = rows.Scan(&p.Cid, &p.From, &p.Page, &p.Part, &p.Duration, &fn, &p.WebLink, &dimensions); err != nil {
log.Error("rows.Scan error(%v)", err)
d.errProm.Incr("archive_db")
return
}
p.Page = page
if p.From != "vupload" {
p.Vid = fn
}
p.FillDimension(dimensions)
ps = append(ps, p)
}
return
}
// videosByAids3 get videos by aids
func (d *Dao) videosByAids3(c context.Context, aids []int64) (vs map[int64][]*api.Page, err error) {
d.infoProm.Incr("videosByAids3")
rows, err := d.resultDB.Query(c, fmt.Sprintf(_vdosByAidsSQL, xstr.JoinInts(aids)))
if err != nil {
d.errProm.Incr("archive_db")
log.Error("d.resultDB.Query(%s) error(%v)", fmt.Sprintf(_vdosByAidsSQL, xstr.JoinInts(aids)), err)
return
}
vs = make(map[int64][]*api.Page, len(aids))
var pages = make(map[int64]int32, len(aids))
defer rows.Close()
for rows.Next() {
var (
p = &api.Page{}
aid int64
fn string
dimensions string
)
if err = rows.Scan(&aid, &p.Cid, &p.From, &p.Page, &p.Part, &p.Duration, &fn, &p.WebLink, &dimensions); err != nil {
d.errProm.Incr("archive_db")
log.Error("rows.Scan error(%v)", err)
return
}
pages[aid]++
p.Page = pages[aid]
if p.From != "vupload" {
p.Vid = fn
}
p.FillDimension(dimensions)
vs[aid] = append(vs[aid], p)
}
return
}
// VideosByCids get videos by cids.
func (d *Dao) VideosByCids(c context.Context, cids []int64) (vs map[int64]map[int64]*api.Page, err error) {
if len(cids) == 0 {
return
}
d.infoProm.Incr("videosByCids")
rows, err := d.arcReadDB.Query(c, fmt.Sprintf(_vdosByCidsSQL, xstr.JoinInts(cids)))
if err != nil {
log.Error("d.arcReadDB.Query() error(%v)", err)
return
}
defer rows.Close()
vs = make(map[int64]map[int64]*api.Page, len(cids))
for rows.Next() {
var (
aid int64
p = &api.Page{}
fn string
)
if err = rows.Scan(&aid, &p.Cid, &p.From, &p.Page, &p.Part, &p.Duration, &fn, &p.WebLink); err != nil {
log.Error("rows.Scan error(%v)", err)
return
}
if p.From != "vupload" {
p.Vid = fn
}
if _, ok := vs[aid]; !ok {
vs[aid] = make(map[int64]*api.Page)
}
vs[aid][int64(p.Cid)] = p
}
return
}
// video3 get video by aid & cid.
func (d *Dao) video3(c context.Context, aid, cid int64) (p *api.Page, err error) {
d.infoProm.Incr("video3")
var fn, dimension string
row := d.resultDB.QueryRow(c, _vdoSQL, aid, cid)
p = &api.Page{}
if err = row.Scan(&p.Cid, &p.From, &p.Page, &p.Part, &p.Duration, &fn, &p.WebLink, &p.Desc, &dimension); err != nil {
if err == sql.ErrNoRows {
p = nil
err = nil
} else {
log.Error("row.Scan error(%v)", err)
d.errProm.Incr("result_db")
}
return
}
if p.From != "vupload" {
p.Vid = fn
}
p.FillDimension(dimension)
return
}

View File

@@ -0,0 +1,209 @@
package archive
import (
"context"
"strconv"
"go-common/app/service/main/archive/api"
"go-common/library/cache/memcache"
"go-common/library/log"
)
const (
_prefixPBPage = "psb_"
)
func pagePBKey(aid int64) string {
return _prefixPBPage + strconv.FormatInt(aid, 10)
}
func videoPBKey2(aid, cid int64) string {
return _prefixPBPage + strconv.FormatInt(aid, 10) + strconv.FormatInt(cid, 10)
}
type batchVdo3 struct {
cached map[int64][]*api.Page
missed []int64
err error
}
// addPageCache3 add pages cache by aid.
func (d *Dao) addPageCache3(c context.Context, aid int64, ps []*api.Page) (err error) {
var vs = &api.AidVideos{Aid: aid, Pages: ps}
key := pagePBKey(aid)
conn := d.mc.Get(c)
if err = conn.Set(&memcache.Item{Key: key, Object: vs, Expiration: 0, Flags: memcache.FlagProtobuf}); err != nil {
d.errProm.Incr("video_mc")
log.Error("memcache.Set(%s) error(%v)", key, err)
}
conn.Close()
return
}
// addVideoCache3 add video2 cache by aid & cid.
func (d *Dao) addVideoCache3(c context.Context, aid, cid int64, p *api.Page) (err error) {
key := videoPBKey2(aid, cid)
conn := d.mc.Get(c)
if err = conn.Set(&memcache.Item{Key: key, Object: p, Expiration: 0, Flags: memcache.FlagProtobuf}); err != nil {
d.errProm.Incr("video3_mc")
log.Error("conn.Set(%s) error(%v)", key, err)
}
conn.Close()
return
}
// DelVideoCache3 del video2 cache by aid & cid.
func (d *Dao) DelVideoCache3(c context.Context, aid, cid int64) (err error) {
key := videoPBKey2(aid, cid)
conn := d.mc.Get(c)
if err = conn.Delete(key); err != nil {
if err == memcache.ErrNotFound {
err = nil
} else {
d.errProm.Incr("video3_mc")
log.Error("conn.Set(%s) error(%v)", key, err)
}
}
conn.Close()
return
}
// pageCache3 get page cache by aid.
func (d *Dao) pageCache3(c context.Context, aid int64) (ps []*api.Page, err error) {
var (
key = pagePBKey(aid)
rp *memcache.Item
conn = d.mc.Get(c)
)
defer conn.Close()
if rp, err = conn.Get(key); err != nil {
if err == memcache.ErrNotFound {
err = nil
ps = nil
} else {
d.errProm.Incr("video_mc")
log.Error("conn.Get(%s) error(%v)", key, err)
}
return
}
var vs = new(api.AidVideos)
if err = conn.Scan(rp, vs); err != nil {
log.Error("conn.Scan(%s) error(%v)", rp.Value, err)
ps = nil
return
}
ps = vs.Pages
return
}
// pagesCache3 get pages cache by aids
func (d *Dao) pagesCache3(c context.Context, aids []int64) (cached map[int64][]*api.Page, missed []int64, err error) {
var (
lt = len(aids)
times int
reqCh chan batchVdo3
)
if lt%_multiInterval == 0 {
times = lt / _multiInterval
} else {
times = lt/_multiInterval + 1
}
reqCh = make(chan batchVdo3, times)
for i := 0; i < times; i++ {
var tmps []int64
if i == times-1 {
tmps = aids[i*_multiInterval:]
} else {
tmps = aids[i*_multiInterval : (i+1)*_multiInterval]
}
go d._videoCaches3(c, tmps, reqCh)
}
if times == 1 {
req := <-reqCh
cached = req.cached
missed = req.missed
err = req.err
return
}
cached = make(map[int64][]*api.Page, len(aids))
for i := 0; i < times; i++ {
req := <-reqCh
for k, v := range req.cached {
cached[k] = v
}
missed = append(missed, req.missed...)
}
return
}
// videoCache3 get video cache by aid & cid.
func (d *Dao) videoCache3(c context.Context, aid, cid int64) (p *api.Page, err error) {
var (
key = videoPBKey2(aid, cid)
rp *memcache.Item
conn = d.mc.Get(c)
)
defer conn.Close()
if rp, err = conn.Get(key); err != nil {
if err == memcache.ErrNotFound {
err = nil
p = nil
} else {
d.errProm.Incr("video2_mc")
log.Error("conn.Get(%s) error(%v)", key, err)
}
return
}
p = new(api.Page)
if err = conn.Scan(rp, p); err != nil {
log.Error("conn.Scan(%s) error(%v)", rp.Value, err)
p = nil
return
}
return
}
func (d *Dao) _videoCaches3(c context.Context, aids []int64, reqCh chan<- batchVdo3) {
var (
req batchVdo3
keys = make([]string, 0, len(aids))
am = make(map[int64]struct{}, len(aids))
rps map[string]*memcache.Item
err error
conn = d.mc.Get(c)
)
defer conn.Close()
for _, aid := range aids {
keys = append(keys, pagePBKey(aid))
am[aid] = struct{}{}
}
if rps, err = conn.GetMulti(keys); err != nil {
req.missed = aids
req.cached = make(map[int64][]*api.Page)
req.err = err
reqCh <- req
log.Error("conn.Gets error(%v)", err)
d.errProm.Incr("video_mc")
return
}
var (
cached = make(map[int64][]*api.Page, len(aids))
missed []int64
)
for _, rp := range rps {
var v = new(api.AidVideos)
if e := conn.Scan(rp, v); e != nil {
log.Error("conn.Scan(%s) error(%v)", rp.Value, e)
d.errProm.Incr("video_mc")
continue
}
cached[v.Aid] = v.Pages
delete(am, v.Aid)
}
for aid := range am {
missed = append(missed, aid)
}
req.cached = cached
req.missed = missed
reqCh <- req
}

View File

@@ -0,0 +1,117 @@
package archive
import (
"context"
"go-common/app/service/main/archive/api"
"testing"
"github.com/smartystreets/goconvey/convey"
)
func TestArchivepagePBKey(t *testing.T) {
var (
aid = int64(1)
)
convey.Convey("pagePBKey", t, func(ctx convey.C) {
p1 := pagePBKey(aid)
ctx.Convey("Then p1 should not be nil.", func(ctx convey.C) {
ctx.So(p1, convey.ShouldNotBeNil)
})
})
}
func TestArchivevideoPBKey2(t *testing.T) {
var (
aid = int64(1)
cid = int64(1)
)
convey.Convey("videoPBKey2", t, func(ctx convey.C) {
p1 := videoPBKey2(aid, cid)
ctx.Convey("Then p1 should not be nil.", func(ctx convey.C) {
ctx.So(p1, convey.ShouldNotBeNil)
})
})
}
func TestArchiveaddPageCache3(t *testing.T) {
var (
c = context.TODO()
aid = int64(10097272)
ps = []*api.Page{}
)
convey.Convey("addPageCache3", t, func(ctx convey.C) {
err := d.addPageCache3(c, aid, ps)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
}
func TestArchiveaddVideoCache3(t *testing.T) {
var (
c = context.TODO()
aid = int64(10097272)
cid = int64(10097272)
p = &api.Page{}
)
convey.Convey("addVideoCache3", t, func(ctx convey.C) {
err := d.addVideoCache3(c, aid, cid, p)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
}
func TestArchiveDelVideoCache3(t *testing.T) {
var (
c = context.TODO()
aid = int64(10097272)
cid = int64(10097272)
)
convey.Convey("DelVideoCache3", t, func(ctx convey.C) {
err := d.DelVideoCache3(c, aid, cid)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
}
func TestArchivepageCache3(t *testing.T) {
var (
c = context.TODO()
aid = int64(10097272)
)
convey.Convey("pageCache3", t, func(ctx convey.C) {
_, err := d.pageCache3(c, aid)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
}
func TestArchivepagesCache3(t *testing.T) {
var (
c = context.TODO()
aids = []int64{10097272}
)
convey.Convey("pagesCache3", t, func(ctx convey.C) {
_, _, err := d.pagesCache3(c, aids)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
}
func TestArchivevideoCache3(t *testing.T) {
var (
c = context.TODO()
aid = int64(10097272)
cid = int64(10097272)
)
convey.Convey("videoCache3", t, func(ctx convey.C) {
_, err := d.videoCache3(c, aid, cid)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
}

View File

@@ -0,0 +1,78 @@
package archive
import (
"context"
"testing"
"github.com/smartystreets/goconvey/convey"
)
func TestArchivefirstCid(t *testing.T) {
var (
c = context.TODO()
aid = int64(10097272)
)
convey.Convey("firstCid", t, func(ctx convey.C) {
cid, dimensions, err := d.firstCid(c, aid)
ctx.Convey("Then err should be nil.cid,dimensions should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(dimensions, convey.ShouldNotBeNil)
ctx.So(cid, convey.ShouldNotBeNil)
})
})
}
func TestArchivevideos3(t *testing.T) {
var (
c = context.TODO()
aid = int64(10097272)
)
convey.Convey("videos3", t, func(ctx convey.C) {
_, err := d.videos3(c, aid)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
}
func TestArchivevideosByAids3(t *testing.T) {
var (
c = context.TODO()
aids = []int64{10097272}
)
convey.Convey("videosByAids3", t, func(ctx convey.C) {
vs, err := d.videosByAids3(c, aids)
ctx.Convey("Then err should be nil.vs should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(vs, convey.ShouldNotBeNil)
})
})
}
func TestArchiveVideosByCids(t *testing.T) {
var (
c = context.TODO()
cids = []int64{10097272}
)
convey.Convey("VideosByCids", t, func(ctx convey.C) {
vs, err := d.VideosByCids(c, cids)
ctx.Convey("Then err should be nil.vs should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(vs, convey.ShouldNotBeNil)
})
})
}
func TestArchivevideo3(t *testing.T) {
var (
c = context.TODO()
aid = int64(10097272)
cid = int64(10097272)
)
convey.Convey("video3", t, func(ctx convey.C) {
_, err := d.video3(c, aid, cid)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
}

View File

@@ -0,0 +1,55 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_test",
"go_library",
)
go_test(
name = "go_default_test",
srcs = [
"dao_test.go",
"databus_test.go",
"redis_test.go",
],
embed = [":go_default_library"],
rundir = ".",
tags = ["automanaged"],
deps = [
"//app/service/main/archive/conf:go_default_library",
"//vendor/github.com/smartystreets/goconvey/convey:go_default_library",
],
)
go_library(
name = "go_default_library",
srcs = [
"dao.go",
"databus.go",
"redis.go",
],
importpath = "go-common/app/service/main/archive/dao/share",
tags = ["automanaged"],
deps = [
"//app/service/main/archive/conf:go_default_library",
"//library/cache/redis:go_default_library",
"//library/log:go_default_library",
"//library/net/ip:go_default_library",
"//library/queue/databus:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)

View File

@@ -0,0 +1,48 @@
package share
import (
"context"
"go-common/library/cache/redis"
"go-common/library/queue/databus"
"go-common/app/service/main/archive/conf"
)
// Dao is share dao.
type Dao struct {
c *conf.Config
// redis
rds *redis.Pool
expire int32
// databus
statDbus *databus.Databus
shareDbus *databus.Databus
}
// New new a share dao.
func New(c *conf.Config) (d *Dao) {
d = &Dao{
c: c,
rds: redis.NewPool(c.Redis.Archive.Config),
expire: 168 * 60 * 60,
statDbus: databus.New(c.StatDatabus),
shareDbus: databus.New(c.ShareDatabus),
}
return d
}
// Close close resource.
func (d *Dao) Close() {
if d.rds != nil {
d.rds.Close()
}
}
// Ping ping success.
func (d *Dao) Ping(c context.Context) (err error) {
conn := d.rds.Get(c)
_, err = conn.Do("SET", "PING", "PONG")
conn.Close()
return
}

View File

@@ -0,0 +1,33 @@
package share
import (
"flag"
"go-common/app/service/main/archive/conf"
"os"
"testing"
)
var (
d *Dao
)
func TestMain(m *testing.M) {
if os.Getenv("DEPLOY_ENV") != "" {
flag.Set("app_id", "main.app-svr.archive-service")
flag.Set("conf_token", "Y2LJhIsHx87nJaOBSxuG5TeZoLdBFlrE")
flag.Set("tree_id", "2302")
flag.Set("conf_version", "docker-1")
flag.Set("deploy_env", "uat")
flag.Set("conf_host", "config.bilibili.co")
flag.Set("conf_path", "/tmp")
flag.Set("region", "sh")
flag.Set("zone", "sh001")
}
flag.Parse()
if err := conf.Init(); err != nil {
panic(err)
}
d = New(conf.Conf)
m.Run()
os.Exit(0)
}

View File

@@ -0,0 +1,37 @@
package share
import (
"context"
"strconv"
"time"
"go-common/library/log"
)
// PubStatDatabus pub share count into databus.
func (d *Dao) PubStatDatabus(c context.Context, aid int64, share int) (err error) {
type stat struct {
Type string `json:"type"`
ID int64 `json:"id"`
Count int `json:"count"`
Ts int64 `json:"timestamp"`
}
if err = d.statDbus.Send(c, strconv.FormatInt(aid, 10), &stat{Type: "archive", ID: aid, Count: share, Ts: time.Now().Unix()}); err != nil {
log.Error("d.databus.Send error(%v)", err)
}
return
}
// PubShare pub first share to databus
func (d *Dao) PubShare(c context.Context, aid int64, mid int64, ip string) (err error) {
type share struct {
Event string `json:"event"`
Mid int64 `json:"mid"`
IP string `json:"ip"`
Ts int64 `json:"ts"`
}
if err = d.shareDbus.Send(c, strconv.FormatInt(mid, 10), &share{Event: "share", Mid: mid, IP: ip, Ts: time.Now().Unix()}); err != nil {
log.Error("d.shareDbus.Send error(%v)", err)
}
return
}

View File

@@ -0,0 +1,37 @@
package share
import (
"context"
"testing"
"github.com/smartystreets/goconvey/convey"
)
func TestSharePubStatDatabus(t *testing.T) {
var (
c = context.TODO()
aid = int64(1)
share = int(1)
)
convey.Convey("PubStatDatabus", t, func(ctx convey.C) {
err := d.PubStatDatabus(c, aid, share)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
}
func TestSharePubShare(t *testing.T) {
var (
c = context.TODO()
aid = int64(1)
mid = int64(1)
ip = "127.0.0.1"
)
convey.Convey("PubShare", t, func(ctx convey.C) {
err := d.PubShare(c, aid, mid, ip)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
}

View File

@@ -0,0 +1,75 @@
package share
import (
"context"
"fmt"
"time"
"go-common/library/cache/redis"
"go-common/library/log"
xip "go-common/library/net/ip"
)
const (
_prefixShare = "as"
// the first shared every day
_prefixFirst = "afs"
)
func redisKey(aid int64) string {
return fmt.Sprintf("%s_%d", _prefixShare, aid)
}
func redisFKey(mid int64, date string) string {
return fmt.Sprintf("%s_%s_%d", _prefixFirst, date, mid%10000)
}
// AddShare add a share with mid and ip to redis.
func (d *Dao) AddShare(c context.Context, mid, aid int64, ip string) (ok bool, err error) {
var (
key = redisKey(aid)
value = (mid << 32) | int64(xip.InetAtoN(ip))
conn = d.rds.Get(c)
)
defer conn.Close()
if err = conn.Send("SADD", key, value); err != nil {
log.Error("conn.Send(SADD, %s, %d) error(%v)", key, value, err)
return
}
if err = conn.Send("EXPIRE", key, d.expire); err != nil {
log.Error("conn.Send(EXPIRE, %s, %d) error(%v)", key, value, err)
return
}
if err = conn.Flush(); err != nil {
log.Error("conn.Flush error(%v)", err)
}
if ok, err = redis.Bool(conn.Receive()); err != nil {
log.Error("conn.Receive error(%v)", err)
}
if _, err = conn.Receive(); err != nil {
log.Error("conn.Receive error(%v)", err)
}
return
}
// HadFirstShare if key not exist need set expire to one day.
func (d *Dao) HadFirstShare(c context.Context, mid, aid int64, ip string) (had bool, err error) {
var (
date = time.Now().Format("0102")
key = redisFKey(mid, date)
addOk bool
conn = d.rds.Get(c)
)
defer conn.Close()
if addOk, err = redis.Bool(conn.Do("SADD", key, mid)); err != nil {
log.Error("conn.Send(SADD, %s, %d) error(%v)", key, mid, err)
return
}
if addOk {
if _, err = conn.Do("EXPIRE", key, 24*60*60); err != nil {
log.Error("conn.Send(EXPIRE, %s, 24*60*60) error(%v)", key, err)
}
}
had = !addOk
return
}

View File

@@ -0,0 +1,65 @@
package share
import (
"context"
"testing"
"github.com/smartystreets/goconvey/convey"
)
func TestShareredisKey(t *testing.T) {
var (
aid = int64(1)
)
convey.Convey("redisKey", t, func(ctx convey.C) {
p1 := redisKey(aid)
ctx.Convey("Then p1 should not be nil.", func(ctx convey.C) {
ctx.So(p1, convey.ShouldNotBeNil)
})
})
}
func TestShareredisFKey(t *testing.T) {
var (
mid = int64(1)
date = ""
)
convey.Convey("redisFKey", t, func(ctx convey.C) {
p1 := redisFKey(mid, date)
ctx.Convey("Then p1 should not be nil.", func(ctx convey.C) {
ctx.So(p1, convey.ShouldNotBeNil)
})
})
}
func TestShareAddShare(t *testing.T) {
var (
c = context.TODO()
mid = int64(1)
aid = int64(1)
ip = ""
)
convey.Convey("AddShare", t, func(ctx convey.C) {
ok, err := d.AddShare(c, mid, aid, ip)
ctx.Convey("Then err should be nil.ok should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(ok, convey.ShouldNotBeNil)
})
})
}
func TestShareHadFirstShare(t *testing.T) {
var (
c = context.TODO()
mid = int64(1)
aid = int64(1)
ip = ""
)
convey.Convey("HadFirstShare", t, func(ctx convey.C) {
had, err := d.HadFirstShare(c, mid, aid, ip)
ctx.Convey("Then err should be nil.had should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(had, convey.ShouldNotBeNil)
})
})
}

View File

@@ -0,0 +1,56 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_test",
"go_library",
)
go_test(
name = "go_default_test",
srcs = [
"dao_test.go",
"mysql_test.go",
"redis_test.go",
],
embed = [":go_default_library"],
rundir = ".",
tags = ["automanaged"],
deps = [
"//app/service/main/archive/conf:go_default_library",
"//vendor/github.com/smartystreets/goconvey/convey:go_default_library",
],
)
go_library(
name = "go_default_library",
srcs = [
"dao.go",
"mysql.go",
"redis.go",
],
importpath = "go-common/app/service/main/archive/dao/videoshot",
tags = ["automanaged"],
deps = [
"//app/service/main/archive/conf:go_default_library",
"//app/service/main/archive/model/videoshot:go_default_library",
"//library/cache/redis:go_default_library",
"//library/database/sql:go_default_library",
"//library/log:go_default_library",
"//library/stat/prom:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)

View File

@@ -0,0 +1,106 @@
package videoshot
import (
"context"
"go-common/library/cache/redis"
"go-common/library/database/sql"
"go-common/library/log"
"go-common/library/stat/prom"
"go-common/app/service/main/archive/conf"
"go-common/app/service/main/archive/model/videoshot"
)
// Dao is videoshot dao.
type Dao struct {
// mysql
db *sql.DB
dbRead *sql.DB
getStmt *sql.Stmt
inStmt *sql.Stmt
// redis
rds *redis.Pool
// prom
infoProm *prom.Prom
// chan
cacheCh chan func()
}
// New new a videoshot dao.
func New(c *conf.Config) (d *Dao) {
d = &Dao{
db: sql.NewMySQL(c.DB.Arc),
dbRead: sql.NewMySQL(c.DB.ArcRead),
rds: redis.NewPool(c.Redis.Archive.Config),
cacheCh: make(chan func(), 1024),
}
d.getStmt = d.dbRead.Prepared(_getSQL)
d.inStmt = d.db.Prepared(_inSQL)
d.infoProm = prom.BusinessInfoCount
go d.cacheproc()
return d
}
// Videoshot get videoshot.
func (d *Dao) Videoshot(c context.Context, cid int64) (v *videoshot.Videoshot, err error) {
var count, ver int
if count, ver, err = d.cache(c, cid); err != nil {
log.Error("d.cache(%d) error(%v)", cid, err)
err = nil // NOTE: ignore error use db
}
if count != 0 {
v = &videoshot.Videoshot{Cid: cid, Count: count}
v.SetVersion(ver)
return
}
if v, err = d.videoshot(c, cid); err != nil || v == nil {
log.Warn("d.videoshot(%d) error(%v) or v==nil", cid, err)
return
}
d.cacheCh <- func() {
d.addCache(context.TODO(), v.Cid, v.Version(), v.Count)
}
return
}
// AddVideoshot add videoshot.
func (d *Dao) AddVideoshot(c context.Context, v *videoshot.Videoshot) (err error) {
if _, err = d.addVideoshot(c, v); err != nil {
log.Error("d.addVideoshot(%v) error(%v)", v, err)
return
}
d.cacheCh <- func() {
d.addCache(context.TODO(), v.Cid, v.Version(), v.Count)
}
return
}
// Close close resource.
func (d *Dao) Close() {
if d.rds != nil {
d.rds.Close()
}
if d.db != nil {
d.db.Close()
}
close(d.cacheCh)
}
// Ping ping success.
func (d *Dao) Ping(c context.Context) (err error) {
conn := d.rds.Get(c)
_, err = conn.Do("SET", "PING", "PONG")
conn.Close()
return
}
func (d *Dao) cacheproc() {
for {
f, ok := <-d.cacheCh
if !ok {
return
}
f()
}
}

View File

@@ -0,0 +1,33 @@
package videoshot
import (
"flag"
"go-common/app/service/main/archive/conf"
"os"
"testing"
)
var (
d *Dao
)
func TestMain(m *testing.M) {
if os.Getenv("DEPLOY_ENV") != "" {
flag.Set("app_id", "main.app-svr.archive-service")
flag.Set("conf_token", "Y2LJhIsHx87nJaOBSxuG5TeZoLdBFlrE")
flag.Set("tree_id", "2302")
flag.Set("conf_version", "docker-1")
flag.Set("deploy_env", "uat")
flag.Set("conf_host", "config.bilibili.co")
flag.Set("conf_path", "/tmp")
flag.Set("region", "sh")
flag.Set("zone", "sh001")
}
flag.Parse()
if err := conf.Init(); err != nil {
panic(err)
}
d = New(conf.Conf)
m.Run()
os.Exit(0)
}

View File

@@ -0,0 +1,41 @@
package videoshot
import (
"context"
"database/sql"
"go-common/app/service/main/archive/model/videoshot"
"go-common/library/log"
)
const (
_inSQL = "INSERT INTO archive_video_shot (id,count,ctime,mtime) VALUES (?,?,?,?) ON DUPLICATE KEY UPDATE count=?,mtime=? "
_getSQL = "SELECT id,count,ctime,mtime FROM archive_video_shot WHERE id=?"
)
// videoshot get a videoshot by id.
func (d *Dao) videoshot(c context.Context, cid int64) (shot *videoshot.Videoshot, err error) {
d.infoProm.Incr("videoshot")
row := d.getStmt.QueryRow(c, cid)
shot = &videoshot.Videoshot{}
if err = row.Scan(&shot.Cid, &shot.Count, &shot.CTime, &shot.MTime); err != nil {
if err == sql.ErrNoRows {
shot = nil
err = nil
} else {
log.Error("row.Scan() error(%v)", err)
}
}
return
}
// addVideoshot add a videoshot into mysql.
func (d *Dao) addVideoshot(c context.Context, shot *videoshot.Videoshot) (cid int64, err error) {
res, err := d.inStmt.Exec(c, shot.Cid, shot.Count, shot.CTime, shot.MTime, shot.Count, shot.MTime)
if err != nil {
log.Error("inStmt.Exec error(%v)", err)
return
}
cid, err = res.LastInsertId()
return
}

View File

@@ -0,0 +1,21 @@
package videoshot
import (
"context"
"testing"
"github.com/smartystreets/goconvey/convey"
)
func TestVideoshotvideoshot(t *testing.T) {
var (
c = context.TODO()
cid = int64(10097272)
)
convey.Convey("videoshot", t, func(ctx convey.C) {
_, err := d.videoshot(c, cid)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
}

View File

@@ -0,0 +1,55 @@
package videoshot
import (
"context"
"fmt"
"go-common/library/cache/redis"
"go-common/library/log"
)
const (
// _hashKeyNum the max count of hash key
_hashKeyNum = int64(100000)
_keyPrefix = "vs_"
)
func hashKey(cid int64) string {
return fmt.Sprintf("%s%d", _keyPrefix, cid%_hashKeyNum)
}
// cache get videoshot's count by id.
func (d *Dao) cache(c context.Context, cid int64) (count, ver int, err error) {
var (
key = hashKey(cid)
conn = d.rds.Get(c)
out int64
)
defer conn.Close()
if out, err = redis.Int64(conn.Do("HGET", key, cid)); err != nil {
if err == redis.ErrNil {
err = nil
} else {
log.Error("HGET(%s, %d) error(%v)", key, cid, err)
}
return
}
ver = int(out >> 32)
count = int(int32(out))
return
}
// addCache set videoshot info into redis.
func (d *Dao) addCache(c context.Context, cid int64, ver, count int) (err error) {
var (
key = hashKey(cid)
conn = d.rds.Get(c)
in int64
)
in = int64(ver)<<32 | int64(count)
defer conn.Close()
if _, err = conn.Do("HSET", key, cid, in); err != nil {
log.Error("HSET(%s, %d, %d)", key, cid, count, err)
}
return
}

View File

@@ -0,0 +1,50 @@
package videoshot
import (
"context"
"testing"
"github.com/smartystreets/goconvey/convey"
)
func TestVideoshothashKey(t *testing.T) {
var (
cid = int64(1)
)
convey.Convey("hashKey", t, func(ctx convey.C) {
p1 := hashKey(cid)
ctx.Convey("Then p1 should not be nil.", func(ctx convey.C) {
ctx.So(p1, convey.ShouldNotBeNil)
})
})
}
func TestVideoshotcache(t *testing.T) {
var (
c = context.TODO()
cid = int64(1)
)
convey.Convey("cache", t, func(ctx convey.C) {
count, ver, err := d.cache(c, cid)
ctx.Convey("Then err should be nil.count,ver should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(ver, convey.ShouldNotBeNil)
ctx.So(count, convey.ShouldNotBeNil)
})
})
}
func TestVideoshotaddCache(t *testing.T) {
var (
c = context.TODO()
cid = int64(1)
ver = int(0)
count = int(0)
)
convey.Convey("addCache", t, func(ctx convey.C) {
err := d.addCache(c, cid, ver, count)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
}