Create & Init Project...

This commit is contained in:
2019-04-22 18:49:16 +08:00
commit fc4fa37393
25440 changed files with 4054998 additions and 0 deletions

View File

@@ -0,0 +1,74 @@
load(
"@io_bazel_rules_go//go:def.bzl",
"go_test",
"go_library",
)
go_test(
name = "go_default_test",
srcs = [
"api_test.go",
"arctypes_test.go",
"dao_test.go",
"memcache_test.go",
"valid_test.go",
"view_test.go",
],
embed = [":go_default_library"],
rundir = ".",
tags = ["automanaged"],
deps = [
"//app/interface/main/tv/conf:go_default_library",
"//app/interface/main/tv/model/view:go_default_library",
"//app/service/main/archive/api:go_default_library",
"//library/database/sql:go_default_library",
"//vendor/github.com/smartystreets/goconvey/convey:go_default_library",
"//vendor/gopkg.in/h2non/gock.v1:go_default_library",
],
)
go_library(
name = "go_default_library",
srcs = [
"api.go",
"arctypes.go",
"dao.go",
"memcache.go",
"valid.go",
"view.go",
],
importpath = "go-common/app/interface/main/tv/dao/archive",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/interface/main/history/model:go_default_library",
"//app/interface/main/history/rpc/client:go_default_library",
"//app/interface/main/tv/conf:go_default_library",
"//app/interface/main/tv/model:go_default_library",
"//app/interface/main/tv/model/view:go_default_library",
"//app/service/main/archive/api:go_default_library",
"//app/service/main/archive/model/archive:go_default_library",
"//library/cache/memcache: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/net/metadata: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,41 @@
package archive
import (
"context"
"net/url"
"strconv"
"go-common/library/ecode"
"go-common/library/xstr"
"github.com/pkg/errors"
)
const (
_realteURL = "/recsys/related"
)
// RelateAids get relate by aid
func (d *Dao) RelateAids(c context.Context, aid int64, ip string) (aids []int64, err error) {
params := url.Values{}
params.Set("key", strconv.FormatInt(aid, 10))
var res struct {
Code int `json:"code"`
Data []*struct {
Value string `json:"value"`
} `json:"data"`
}
if err = d.client.Get(c, d.relateURL, ip, params, &res); err != nil {
return
}
if res.Code != ecode.OK.Code() {
err = errors.Wrap(ecode.Int(res.Code), d.relateURL+"?"+params.Encode())
return
}
if len(res.Data) != 0 {
if aids, err = xstr.SplitInts(res.Data[0].Value); err != nil {
err = errors.Wrap(err, res.Data[0].Value)
}
}
return
}

View File

@@ -0,0 +1,28 @@
package archive
import (
"context"
"fmt"
"testing"
"go-common/library/database/sql"
. "github.com/smartystreets/goconvey/convey"
)
func getPassAid(db *sql.DB) (aid int64, err error) {
if err = db.QueryRow(context.Background(), "select aid from ugc_archive where deleted = 0 and valid = 1 and result = 1 limit 1").Scan(&aid); err != nil {
fmt.Println(err)
}
return
}
func TestDao_RelateAids(t *testing.T) {
Convey("TestDao_RelateAids", t, WithDao(func(d *Dao) {
httpMock("GET", d.relateURL).Reply(200).JSON(`{"data":[{"key": "1234", "value": "23999,515522,55,10099960,10099978,10099959,10099959,10099959,10099959,10099959,10099959,10099959,10099959,10099959,10099959,10099959,10099959,10099959,10099959,10099959,10099959,10099959"}]}`)
aids, err := d.RelateAids(context.Background(), 333444, "")
So(err, ShouldBeNil)
So(len(aids), ShouldBeGreaterThan, 0)
fmt.Println(aids)
}))
}

View File

@@ -0,0 +1,120 @@
package archive
import (
"context"
"go-common/app/interface/main/tv/model"
arcwar "go-common/app/service/main/archive/api"
"go-common/library/ecode"
"go-common/library/log"
)
// call ArcRPC for types data
func (d *Dao) loadTypes(ctx context.Context) {
var (
res = make(map[int32]*arcwar.Tp)
resRel = make(map[int32][]*arcwar.Tp)
reply *arcwar.TypesReply
err error
)
if reply, err = d.arcClient.Types(ctx, &arcwar.NoArgRequest{}); err != nil {
log.Error("arcRPC loadType Error %v", err)
return
}
res = reply.Types
log.Info("Reload Types Data! Len: %d", len(res))
for _, v := range res {
if v.Pid != 0 {
if _, ok := resRel[v.Pid]; !ok {
resRel[v.Pid] = []*arcwar.Tp{}
}
resRel[v.Pid] = append(resRel[v.Pid], v)
}
}
if len(res) > 0 {
d.arcTypes = res
}
if len(resRel) > 0 {
d.arcTypesRel = resRel
}
}
// GetPTypeName get first level of types name
func (d *Dao) GetPTypeName(typeID int32) (firstName string, secondName string) {
var (
second, first *arcwar.Tp
ok bool
)
if second, ok = d.arcTypes[typeID]; !ok {
log.Error("can't find type for ID: %d ", typeID)
return
}
secondName = second.Name
if first, ok = d.arcTypes[second.Pid]; !ok {
log.Error("can't find type for ID: %d, second Info: %v", second, second.Pid)
return
}
firstName = first.Name
return
}
// TargetTypes get all the ugc ranks that AI prepared for us
func (d *Dao) TargetTypes() (tids []int32, err error) {
if len(d.arcTypesRel) == 0 {
err = ecode.ServiceUnavailable
return
}
for _, v := range d.conf.Cfg.ZonesInfo.TargetTypes {
if children, ok := d.arcTypesRel[v]; ok { // second level types
for _, child := range children {
tids = append(tids, child.ID)
}
}
tids = append(tids, v)
}
return
}
// FirstTypes returns only first level of types
func (d *Dao) FirstTypes() (typeMap map[int32]*model.ArcType, err error) {
if len(d.arcTypes) == 0 {
err = ecode.ServiceUnavailable
return
}
typeMap = make(map[int32]*model.ArcType)
for _, v := range d.arcTypes { // only pick first level of types
if v.Pid == 0 {
typeMap[v.ID] = &model.ArcType{
ID: v.ID,
Name: v.Name,
}
}
}
return
}
// TypeInfo returns the type info
func (d *Dao) TypeInfo(typeid int32) (*arcwar.Tp, error) {
if len(d.arcTypes) == 0 {
return nil, ecode.ServiceUnavailable
}
info, ok := d.arcTypes[typeid]
if !ok {
return nil, ecode.NothingFound
}
return info, nil
}
// TypeChildren returns a first level's type children
func (d *Dao) TypeChildren(typeid int32) (children []*arcwar.Tp, err error) {
if len(d.arcTypesRel) == 0 {
err = ecode.ServiceUnavailable
return
}
children, found := d.arcTypesRel[typeid]
if !found {
err = ecode.NothingFound
return
}
return
}

View File

@@ -0,0 +1,78 @@
package archive
import (
"context"
"testing"
"github.com/smartystreets/goconvey/convey"
)
func TestArchiveloadTypes(t *testing.T) {
var (
c = context.Background()
)
convey.Convey("loadTypes", t, func(ctx convey.C) {
d.loadTypes(c)
ctx.Convey("No return values", func(ctx convey.C) {
})
})
}
func TestArchiveGetPTypeName(t *testing.T) {
var (
typeID = int32(3)
)
convey.Convey("GetPTypeName", t, func(ctx convey.C) {
firstName, secondName := d.GetPTypeName(typeID)
ctx.Convey("Then firstName,secondName should not be nil.", func(ctx convey.C) {
ctx.So(secondName, convey.ShouldNotBeNil)
ctx.So(firstName, convey.ShouldNotBeNil)
})
})
}
func TestArchiveTargetTypes(t *testing.T) {
convey.Convey("TargetTypes", t, func(ctx convey.C) {
tids, err := d.TargetTypes()
ctx.Convey("Then err should be nil.tids should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(tids, convey.ShouldNotBeNil)
})
})
}
func TestArchiveFirstTypes(t *testing.T) {
convey.Convey("FirstTypes", t, func(ctx convey.C) {
typeMap, err := d.FirstTypes()
ctx.Convey("Then err should be nil.typeMap should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(typeMap, convey.ShouldNotBeNil)
})
})
}
func TestArchiveTypeInfo(t *testing.T) {
var (
typeid = int32(3)
)
convey.Convey("TypeInfo", t, func(ctx convey.C) {
p1, err := d.TypeInfo(typeid)
ctx.Convey("Then err should be nil.p1 should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(p1, convey.ShouldNotBeNil)
})
})
}
func TestArchiveTypeChildren(t *testing.T) {
var (
typeid = int32(3)
)
convey.Convey("TypeChildren", t, func(ctx convey.C) {
children, err := d.TypeChildren(typeid)
ctx.Convey("Then err should be nil.children should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(children, convey.ShouldNotBeNil)
})
})
}

View File

@@ -0,0 +1,89 @@
package archive
import (
"context"
"runtime"
"time"
hisrpc "go-common/app/interface/main/history/rpc/client"
"go-common/app/interface/main/tv/conf"
arcwar "go-common/app/service/main/archive/api"
"go-common/library/cache/memcache"
"go-common/library/database/sql"
"go-common/library/log"
bm "go-common/library/net/http/blademaster"
)
// Dao is archive dao.
type Dao struct {
// cfg
db *sql.DB
conf *conf.Config
relateURL string
// memory
arcTypes map[int32]*arcwar.Tp // map for arc types
arcTypesRel map[int32][]*arcwar.Tp // map for relation between arc type
// http client
client *bm.Client
// rpc
arcClient arcwar.ArchiveClient
hisRPC *hisrpc.Service
// memcache
arcMc *memcache.Pool
expireRlt int32
expireArc int32
expireView int32
// chan
mCh chan func()
}
// New new a archive dao.
func New(c *conf.Config) (d *Dao) {
d = &Dao{
// http client
client: bm.NewClient(c.HTTPClient),
// rpc
hisRPC: hisrpc.New(c.HisRPC),
// cfg
relateURL: c.Host.Data + _realteURL,
conf: c,
db: sql.NewMySQL(c.Mysql),
// memorry
arcTypes: make(map[int32]*arcwar.Tp),
arcTypesRel: make(map[int32][]*arcwar.Tp),
// memcache
arcMc: memcache.NewPool(c.Memcache.Config),
expireRlt: int32(time.Duration(c.Memcache.RelateExpire) / time.Second),
expireView: int32(time.Duration(c.Memcache.ViewExpire) / time.Second),
expireArc: int32(time.Duration(c.Memcache.ArcExpire) / time.Second),
// mc proc
mCh: make(chan func(), 10240),
}
var err error
if d.arcClient, err = arcwar.NewClient(c.ArcClient); err != nil {
panic(err)
}
// video db
for i := 0; i < runtime.NumCPU()*2; i++ {
go d.cacheproc()
}
d.loadTypes(context.Background())
return
}
// addCache add archive to mc or redis
func (d *Dao) addCache(f func()) {
select {
case d.mCh <- f:
default:
log.Warn("cacheproc chan full")
}
}
// cacheproc write memcache and stat redis use goroutine
func (d *Dao) cacheproc() {
for {
f := <-d.mCh
f()
}
}

View File

@@ -0,0 +1,51 @@
package archive
import (
"flag"
"os"
"strings"
"go-common/app/interface/main/tv/conf"
. "github.com/smartystreets/goconvey/convey"
"gopkg.in/h2non/gock.v1"
)
var (
d *Dao
)
func init() {
//dir, _ := filepath.Abs("../../cmd/tv-interface.toml")
//flag.Set("conf", dir)
if os.Getenv("DEPLOY_ENV") != "" {
flag.Set("app_id", "main.web-svr.tv-interface")
flag.Set("conf_token", "07c1826c1f39df02a1411cdd6f455879")
flag.Set("tree_id", "15326")
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)
}
func WithDao(f func(d *Dao)) func() {
return func() {
Reset(func() {})
f(d)
}
}
func httpMock(method, url string) *gock.Request {
r := gock.New(url)
r.Method = strings.ToUpper(method)
d.client.SetTransport(gock.DefaultTransport)
return r
}

View File

@@ -0,0 +1,146 @@
package archive
import (
"context"
"strconv"
"go-common/app/interface/main/tv/model/view"
arcwar "go-common/app/service/main/archive/api"
"go-common/library/cache/memcache"
"go-common/library/log"
"github.com/pkg/errors"
)
const (
_prefixRelate = "al_"
_prefixViewStatic = "avp_"
_prefixArchive = "a3p_"
)
func keyRl(aid int64) string {
return _prefixRelate + strconv.FormatInt(aid, 10)
}
func keyView(aid int64) string {
return _prefixViewStatic + strconv.FormatInt(aid, 10)
}
func keyArc(aid int64) string {
return _prefixArchive + strconv.FormatInt(aid, 10)
}
// AddArcCache add arc cache
func (d *Dao) AddArcCache(aid int64, arc *arcwar.Arc) {
d.addCache(func() {
d.addArcCache(context.TODO(), aid, arc)
})
}
// AddRelatesCache add relates
func (d *Dao) AddRelatesCache(aid int64, rls []*view.Relate) {
d.addCache(func() {
d.addRelatesCache(context.TODO(), aid, rls)
})
}
// AddViewCache add view relates
func (d *Dao) AddViewCache(aid int64, vp *arcwar.ViewReply) {
d.addCache(func() {
d.addViewCache(context.TODO(), aid, vp)
})
}
// addViewCache add relates cache.
func (d *Dao) addViewCache(c context.Context, aid int64, vp *arcwar.ViewReply) (err error) {
conn := d.arcMc.Get(c)
key := keyView(aid)
item := &memcache.Item{Key: key, Object: vp, Flags: memcache.FlagJSON, Expiration: d.expireView}
if err = conn.Set(item); err != nil {
err = errors.Wrapf(err, "conn.Set(%s,%v,%d)", key, vp, d.expireView)
}
conn.Close()
return
}
// RelatesCache get relates.
func (d *Dao) RelatesCache(c context.Context, aid int64) (rls []*view.Relate, err error) {
conn := d.arcMc.Get(c)
key := keyRl(aid)
defer conn.Close()
r, err := conn.Get(key)
if err != nil {
if err == memcache.ErrNotFound {
err = nil
return
}
err = errors.Wrapf(err, "conn.Get(%s)", key)
return
}
if err = conn.Scan(r, &rls); err != nil {
err = errors.Wrapf(err, "conn.Scan(%s)", r.Value)
}
return
}
// addRelatesCache add relates cache.
func (d *Dao) addRelatesCache(c context.Context, aid int64, rls []*view.Relate) (err error) {
conn := d.arcMc.Get(c)
key := keyRl(aid)
item := &memcache.Item{Key: key, Object: rls, Flags: memcache.FlagJSON, Expiration: d.expireRlt}
if err = conn.Set(item); err != nil {
err = errors.Wrapf(err, "conn.Set(%s,%v,%d)", key, rls, d.expireRlt)
}
conn.Close()
return
}
// addRelatesCache add relates cache.
func (d *Dao) addArcCache(c context.Context, aid int64, cached *arcwar.Arc) (err error) {
conn := d.arcMc.Get(c)
key := keyArc(aid)
item := &memcache.Item{Key: key, Object: cached, Flags: memcache.FlagJSON, Expiration: d.expireArc}
if err = conn.Set(item); err != nil {
err = errors.Wrapf(err, "conn.Set(%s,%v,%d)", key, cached, d.expireArc)
}
conn.Close()
return
}
// arcsCache get archives cache.
func (d *Dao) arcsCache(c context.Context, aids []int64) (cached map[int64]*arcwar.Arc, missed []int64, err error) {
cached = make(map[int64]*arcwar.Arc, len(aids))
conn := d.arcMc.Get(c)
defer conn.Close()
keys := make([]string, 0, len(aids))
aidmap := make(map[string]int64, len(aids))
for _, aid := range aids {
k := keyArc(aid)
if _, ok := aidmap[k]; !ok {
keys = append(keys, k)
aidmap[k] = aid
}
}
rs, err := conn.GetMulti(keys)
if err != nil {
err = errors.Wrapf(err, "conn.GetMulti(%v)", keys)
return
}
for k, r := range rs {
a := &arcwar.Arc{}
if err = conn.Scan(r, a); err != nil {
log.Error("conn.Scan(%s) error(%v)", r.Value, err)
err = nil
continue
}
cached[aidmap[k]] = a
// delete hit key
delete(aidmap, k)
}
// missed key
missed = make([]int64, 0, len(aidmap))
for _, aid := range aidmap {
missed = append(missed, aid)
}
return
}

View File

@@ -0,0 +1,171 @@
package archive
import (
"context"
"fmt"
"testing"
"go-common/app/interface/main/tv/model/view"
arcwar "go-common/app/service/main/archive/api"
"github.com/smartystreets/goconvey/convey"
)
func TestArchivekeyRl(t *testing.T) {
var (
aid = int64(123)
)
convey.Convey("keyRl", t, func(ctx convey.C) {
p1 := keyRl(aid)
ctx.Convey("Then p1 should not be nil.", func(ctx convey.C) {
ctx.So(p1, convey.ShouldNotBeNil)
})
})
}
func TestArchivekeyView(t *testing.T) {
var (
aid = int64(123)
)
convey.Convey("keyView", t, func(ctx convey.C) {
p1 := keyView(aid)
ctx.Convey("Then p1 should not be nil.", func(ctx convey.C) {
ctx.So(p1, convey.ShouldNotBeNil)
})
})
}
func TestArchivekeyArc(t *testing.T) {
var (
aid = int64(123)
)
convey.Convey("keyArc", t, func(ctx convey.C) {
p1 := keyArc(aid)
ctx.Convey("Then p1 should not be nil.", func(ctx convey.C) {
ctx.So(p1, convey.ShouldNotBeNil)
})
})
}
func TestArchiveAddArcCache(t *testing.T) {
var (
aid = int64(123)
arc = &arcwar.Arc{
Aid: aid,
}
)
convey.Convey("AddArcCache", t, func(ctx convey.C) {
d.AddArcCache(aid, arc)
ctx.Convey("No return values", func(ctx convey.C) {
})
})
}
func TestArchiveAddRelatesCache(t *testing.T) {
var (
aid = int64(123)
rls = []*view.Relate{
{
Aid: aid,
},
}
)
convey.Convey("AddRelatesCache", t, func(ctx convey.C) {
d.AddRelatesCache(aid, rls)
d.addRelatesCache(context.TODO(), aid, rls)
ctx.Convey("No return values", func(ctx convey.C) {
})
})
}
func TestArchiveAddViewCache(t *testing.T) {
convey.Convey("AddViewCache", t, func(c convey.C) {
aid, errGet := getPassAid(d.db)
if errGet != nil {
fmt.Println(errGet)
return
}
vp, err := d.view3(context.Background(), aid)
fmt.Println(vp, " ", aid)
convey.So(err, convey.ShouldBeNil)
convey.So(vp, convey.ShouldNotBeNil)
d.AddViewCache(aid, vp)
c.Convey("No return values", func(ctx convey.C) {
})
})
}
func TestArchiveaddViewCache(t *testing.T) {
var (
c = context.Background()
aid = int64(123)
vp = &arcwar.ViewReply{}
)
convey.Convey("addViewCache", t, func(ctx convey.C) {
err := d.addViewCache(c, aid, vp)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
}
func TestArchiveRelatesCache(t *testing.T) {
var (
c = context.Background()
aid = int64(123)
)
convey.Convey("RelatesCache", t, func(ctx convey.C) {
rls, err := d.RelatesCache(c, aid)
ctx.Convey("Then err should be nil.rls should not be nil.", func(ctx convey.C) {
fmt.Println(rls)
ctx.So(err, convey.ShouldBeNil)
ctx.So(rls, convey.ShouldNotBeNil)
})
})
}
func TestArchiveaddRelatesCache(t *testing.T) {
var (
c = context.Background()
aid = int64(123)
rls = []*view.Relate{
{Aid: aid},
}
)
convey.Convey("addRelatesCache", t, func(ctx convey.C) {
err := d.addRelatesCache(c, aid, rls)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
}
func TestArchiveaddArcCache(t *testing.T) {
var (
c = context.Background()
aid = int64(123)
cached = &arcwar.Arc{Aid: 123}
)
convey.Convey("addArcCache", t, func(ctx convey.C) {
err := d.addArcCache(c, aid, cached)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
}
func TestArchivearcsCache(t *testing.T) {
var (
c = context.Background()
aids = []int64{123}
)
convey.Convey("arcsCache", t, func(ctx convey.C) {
cached, missed, err := d.arcsCache(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(len(missed)+len(cached), convey.ShouldEqual, len(aids))
fmt.Println(cached)
fmt.Println(missed)
})
})
}

View File

@@ -0,0 +1,28 @@
package archive
import (
arcwar "go-common/app/service/main/archive/api"
"go-common/app/service/main/archive/model/archive"
)
// validView distinguishes whether an view is valid
func validView(vp *arcwar.ViewReply, checkAttr bool) (valid bool) {
if vp == nil {
return
}
if vp.Arc == nil {
return
}
if vp.Arc.Aid == 0 {
return
}
if len(vp.Pages) == 0 {
return
}
if checkAttr {
if vp.Arc.AttrVal(archive.AttrBitIsMovie) == archive.AttrYes {
return // regard it as none
}
}
return true
}

View File

@@ -0,0 +1,21 @@
package archive
import (
"testing"
arcwar "go-common/app/service/main/archive/api"
"github.com/smartystreets/goconvey/convey"
)
func TestArchivevalidView(t *testing.T) {
var (
vp = &arcwar.ViewReply{}
)
convey.Convey("validView", t, func(ctx convey.C) {
valid := validView(vp, true)
ctx.Convey("Then valid should not be nil.", func(ctx convey.C) {
ctx.So(valid, convey.ShouldNotBeNil)
})
})
}

View File

@@ -0,0 +1,221 @@
package archive
import (
"context"
history "go-common/app/interface/main/history/model"
"go-common/app/interface/main/tv/model/view"
arcwar "go-common/app/service/main/archive/api"
"go-common/library/cache/memcache"
"go-common/library/ecode"
"go-common/library/log"
"go-common/library/net/metadata"
"github.com/pkg/errors"
)
// Archive3 picks one archive data
func (d *Dao) Archive3(c context.Context, aid int64) (arc *arcwar.Arc, err error) {
var (
arcReply *arcwar.ArcReply
arg = &arcwar.ArcRequest{Aid: aid}
)
arcReply, err = d.arcClient.Arc(c, arg)
if err != nil {
log.Error("d.arcRPC.Archive(%v) error(%+v)", arg, err)
if ecode.Cause(err) == ecode.NothingFound {
err = nil
return
}
}
arc = arcReply.Arc
return
}
// LoadViews picks view meta information from Cache & RPC
func (d *Dao) LoadViews(ctx context.Context, aids []int64) (resMetas map[int64]*arcwar.ViewReply) {
var (
missedMetas = make(map[int64]*arcwar.ViewReply)
addCache = true
)
resMetas = make(map[int64]*arcwar.ViewReply, len(aids))
cachedMetas, missed, err := d.ViewsCache(ctx, aids)
if err != nil {
log.Error("LoadViews ViewsCache Sids:%v, Error:%v", aids, err)
err = nil
addCache = false // mc error, we don't add
}
if len(missed) > 0 {
for _, vv := range missed {
if vp, _ := d.view3(ctx, vv); vp != nil {
missedMetas[vv] = vp
resMetas[vv] = vp
}
}
}
// merge info from DB and the info from MC
for sid, v := range cachedMetas {
resMetas[sid] = v
}
log.Info("LoadViews Info Hit %d, Missed %d", len(cachedMetas), len(missed))
if addCache && len(missedMetas) > 0 { // async Reset the DB data in MC for next time
log.Info("Set MissedMetas %d Data in MC", missedMetas)
for aid, vp := range missedMetas {
d.AddViewCache(aid, vp)
}
}
return
}
// GetView gets the aid's View info from Cache or RPC
func (d *Dao) GetView(c context.Context, aid int64) (vp *arcwar.ViewReply, err error) {
var (
addCache = false
)
if vp, err = d.viewCache(c, aid); err != nil {
log.Error("ViewPage viewCache AID %d, Err %v", aid, err)
}
if !validView(vp, true) { // back source
if vp, err = d.view3(c, aid); err != nil {
log.Error("%+v", err)
err = ecode.NothingFound
return
}
addCache = true
}
if !validView(vp, false) {
err = ecode.NothingFound
return
}
if addCache {
d.AddViewCache(aid, vp)
return
}
return
}
// view3 view archive with pages pb.
func (d *Dao) view3(c context.Context, aid int64) (reply *arcwar.ViewReply, err error) {
var arg = &arcwar.ViewRequest{Aid: aid}
if reply, err = d.arcClient.View(c, arg); err != nil {
log.Error("d.arcRPC.view3(%v) error(%+v)", arg, err)
if ecode.Cause(err) == ecode.NothingFound {
err = nil
return
}
}
return
}
// viewCache get view cache from remote memecache .
func (d *Dao) viewCache(c context.Context, aid int64) (vs *arcwar.ViewReply, err error) {
conn := d.arcMc.Get(c)
key := keyView(aid)
defer conn.Close()
r, err := conn.Get(key)
if err != nil {
if err == memcache.ErrNotFound {
err = nil
return
}
err = errors.Wrapf(err, "conn.Get(%s)", key)
return
}
vs = &arcwar.ViewReply{Arc: &arcwar.Arc{}}
if err = conn.Scan(r, vs); err != nil {
vs = nil
err = errors.Wrapf(err, "conn.Scan(%s)", r.Value)
}
return
}
// Progress is archive plays progress .
func (d *Dao) Progress(c context.Context, aid, mid int64) (h *view.History, err error) {
ip := metadata.String(c, metadata.RemoteIP)
arg := &history.ArgPro{Mid: mid, Aids: []int64{aid}, RealIP: ip}
his, err := d.hisRPC.Progress(c, arg)
if err != nil {
log.Error("d.hisRPC.Progress(%v) error(%v)", arg, err)
return
}
if his[aid] != nil {
h = &view.History{Cid: his[aid].Cid, Progress: his[aid].Pro}
}
return
}
// ViewsCache pick view from cache
func (d *Dao) ViewsCache(c context.Context, aids []int64) (cached map[int64]*arcwar.ViewReply, missed []int64, err error) {
if len(aids) == 0 {
return
}
var allKeys []string
cached = make(map[int64]*arcwar.ViewReply, len(aids))
idmap := make(map[string]int64, len(aids))
for _, id := range aids {
k := keyView(id)
allKeys = append(allKeys, k)
idmap[k] = id
}
conn := d.arcMc.Get(c)
defer conn.Close()
replys, err := conn.GetMulti(allKeys)
if err != nil {
log.Error("conn.Gets(%v) error(%v)", allKeys, err)
err = nil
return
}
for key, item := range replys {
vp := &arcwar.ViewReply{}
if err = conn.Scan(item, vp); err != nil {
log.Error("item.Scan(%s) error(%v)", item.Value, err)
err = nil
continue
}
if !validView(vp, true) {
continue
}
cached[idmap[key]] = vp
delete(idmap, key)
}
missed = make([]int64, 0, len(idmap))
for _, id := range idmap {
missed = append(missed, id)
}
return
}
// Archives multi get archives.
func (d *Dao) Archives(c context.Context, aids []int64) (as map[int64]*arcwar.Arc, err error) {
if len(aids) == 0 {
return
}
var (
missed []int64
tmp map[int64]*arcwar.Arc
reply *arcwar.ArcsReply
)
if as, missed, err = d.arcsCache(c, aids); err != nil {
as = make(map[int64]*arcwar.Arc, len(aids))
missed = aids
log.Error("%+v", err)
err = nil
}
if len(missed) == 0 {
return
}
arg := &arcwar.ArcsRequest{Aids: missed}
if reply, err = d.arcClient.Arcs(c, arg); err != nil {
log.Error("d.arcRPC.Archives3(%v) error(%v)", arg, err)
if reply, err = d.arcClient.Arcs(c, arg); err != nil {
err = errors.Wrapf(err, "%v", arg)
return
}
}
tmp = reply.Arcs
for aid, a := range tmp {
as[aid] = a
d.AddArcCache(aid, a) // re-fill the cache
}
return
}

View File

@@ -0,0 +1,95 @@
package archive
import (
"context"
"encoding/json"
"fmt"
"testing"
. "github.com/smartystreets/goconvey/convey"
)
func Test_View3(t *testing.T) {
Convey("view3", t, func() {
aid, errGet := getPassAid(d.db)
if errGet != nil {
fmt.Println(errGet)
return
}
vp, err := d.view3(context.Background(), aid)
fmt.Println(vp, " ", aid)
So(err, ShouldBeNil)
So(vp, ShouldNotBeNil)
})
}
func Test_ViewCache(t *testing.T) {
Convey("viewCache", t, func() {
reply, err := d.viewCache(context.TODO(), 123)
So(reply, ShouldNotBeNil)
So(err, ShouldBeNil)
})
}
func TestDao_Progress(t *testing.T) {
Convey("TestDao_Progress", t, func() {
aid, errGet := getPassAid(d.db)
if errGet != nil {
fmt.Println(errGet)
return
}
h, err := d.Progress(context.TODO(), aid, 88895137)
So(err, ShouldBeNil)
fmt.Println(h)
})
}
func TestDao_LoadViews(t *testing.T) {
Convey("TestDao_LoadViews", t, func() {
resMetas := d.LoadViews(context.Background(), []int64{10110328, 10099960})
data, _ := json.Marshal(resMetas)
fmt.Println(string(data))
})
}
func TestDao_Archives(t *testing.T) {
Convey("TestDao_Archives", t, WithDao(func(d *Dao) {
aid, errGet := getPassAid(d.db)
if errGet != nil {
fmt.Println(errGet)
return
}
as, err := d.Archives(context.Background(), []int64{aid})
So(err, ShouldBeNil)
So(len(as), ShouldBeGreaterThan, 0)
fmt.Println(as)
}))
}
func TestDao_GetView(t *testing.T) {
Convey("TestDao_Archives", t, WithDao(func(d *Dao) {
aid, errGet := getPassAid(d.db)
if errGet != nil {
fmt.Println(errGet)
return
}
vp, err := d.GetView(context.Background(), aid)
So(err, ShouldBeNil)
So(vp, ShouldNotBeNil)
fmt.Println(vp)
}))
}
func TestDao_Archive3(t *testing.T) {
Convey("TestDao_Archives", t, WithDao(func(d *Dao) {
aid, errGet := getPassAid(d.db)
if errGet != nil {
fmt.Println(errGet)
return
}
vp, err := d.Archive3(context.Background(), aid)
So(err, ShouldBeNil)
So(vp, ShouldNotBeNil)
fmt.Println(vp)
}))
}