Fix: movie cache and movie db consistency

pull/21/head
zijiren233 2 years ago
parent 01ca838a77
commit 50633226f2

@ -25,7 +25,7 @@ func InitRoom(ctx context.Context) error {
return err return err
} }
for _, movie := range m { for _, movie := range m {
err = r.InitMovie(&movie) err = r.InitMovie(movie)
if err != nil { if err != nil {
log.Errorf("init movie error: %v", err) log.Errorf("init movie error: %v", err)
return err return err

@ -9,40 +9,35 @@ func CreateMovie(movie *model.Movie) error {
return db.Create(movie).Error return db.Create(movie).Error
} }
func GetAllMoviesByRoomID(roomID uint) ([]model.Movie, error) { func GetAllMoviesByRoomID(roomID uint) ([]*model.Movie, error) {
movies := []model.Movie{} movies := []*model.Movie{}
err := db.Where("room_id = ?", roomID).Order("position ASC").Find(&movies).Error err := db.Where("room_id = ?", roomID).Order("position ASC").Find(&movies).Error
return movies, err return movies, err
} }
func DeleteMovieByID(roomID, id uint) error { func DeleteMovieByID(roomID, id uint) error {
return db.Where("room_id = ? AND id = ?", roomID, id).Delete(&model.Movie{}).Error return db.Unscoped().Where("room_id = ? AND id = ?", roomID, id).Delete(&model.Movie{}).Error
} }
// TODO: delete error // TODO: delete error
func LoadAndDeleteMovieByID(roomID, id uint, columns ...clause.Column) (*model.Movie, error) { func LoadAndDeleteMovieByID(roomID, id uint, columns ...clause.Column) (*model.Movie, error) {
movie := &model.Movie{} movie := &model.Movie{}
err := db.Clauses(clause.Returning{Columns: columns}).Where("room_id = ? AND id = ?", roomID, id).Delete(movie).Error err := db.Unscoped().Clauses(clause.Returning{Columns: columns}).Where("room_id = ? AND id = ?", roomID, id).Delete(movie).Error
return movie, err return movie, err
} }
func DeleteMoviesByRoomID(roomID uint) error { func DeleteMoviesByRoomID(roomID uint) error {
return db.Where("room_id = ?", roomID).Delete(&model.Movie{}).Error return db.Unscoped().Where("room_id = ?", roomID).Delete(&model.Movie{}).Error
} }
func LoadAndDeleteMoviesByRoomID(roomID uint, columns ...clause.Column) ([]model.Movie, error) { func LoadAndDeleteMoviesByRoomID(roomID uint, columns ...clause.Column) ([]*model.Movie, error) {
movies := []model.Movie{} movies := []*model.Movie{}
err := db.Clauses(clause.Returning{Columns: columns}).Where("room_id = ?", roomID).Delete(&movies).Error err := db.Unscoped().Clauses(clause.Returning{Columns: columns}).Where("room_id = ?", roomID).Delete(&movies).Error
return movies, err return movies, err
} }
func UpdateMovie(movie model.Movie) error { func UpdateMovie(movie *model.Movie, columns ...clause.Column) error {
return db.Model(&model.Movie{}).Where("room_id = ? AND id = ?", movie.RoomID, movie.ID).Updates(movie).Error return db.Model(movie).Clauses(clause.Returning{Columns: columns}).Where("room_id = ? AND id = ?", movie.RoomID, movie.ID).Updates(movie).Error
}
func LoadAndUpdateMovie(movie model.Movie, columns ...clause.Column) (*model.Movie, error) {
err := db.Model(&model.Movie{}).Clauses(clause.Returning{Columns: columns}).Where("room_id = ? AND id = ?", movie.RoomID, movie.ID).Updates(&movie).Error
return &movie, err
} }
func SwapMoviePositions(roomID uint, movie1ID uint, movie2ID uint) (err error) { func SwapMoviePositions(roomID uint, movie1ID uint, movie2ID uint) (err error) {

@ -1,13 +1,11 @@
package model package model
import ( import "gorm.io/gorm"
"gorm.io/gorm"
)
type Movie struct { type Movie struct {
gorm.Model gorm.Model
Position uint `gorm:"not null" json:"-"` Position uint `gorm:"not null"`
RoomID uint `gorm:"not null;index" json:"roomId"` RoomID uint `gorm:"not null;index"`
MovieInfo `gorm:"embedded"` MovieInfo `gorm:"embedded"`
} }

@ -7,61 +7,62 @@ import (
"github.com/bluele/gcache" "github.com/bluele/gcache"
"github.com/synctv-org/synctv/internal/db" "github.com/synctv-org/synctv/internal/db"
"github.com/synctv-org/synctv/internal/model" "github.com/synctv-org/synctv/internal/model"
"github.com/zijiren233/gencontainer/dllist"
) )
var movieCache = gcache.New(2048). var movieCache = gcache.New(2048).
LRU(). LRU().
Build() Build()
func GetAllMoviesByRoomID(roomID uint) ([]model.Movie, error) { func GetAllMoviesByRoomID(roomID uint) (*dllist.Dllist[*model.Movie], error) {
i, err := movieCache.Get(roomID) i, err := movieCache.Get(roomID)
if err == nil { if err == nil {
return i.([]model.Movie), nil
return i.(*dllist.Dllist[*model.Movie]), nil
} }
m, err := db.GetAllMoviesByRoomID(roomID) m, err := db.GetAllMoviesByRoomID(roomID)
if err != nil { if err != nil {
return nil, err return nil, err
} }
return m, movieCache.SetWithExpire(roomID, m, time.Hour) d := dllist.New[*model.Movie]()
for i := range m {
d.PushBack(m[i])
}
return d, movieCache.SetWithExpire(roomID, d, time.Hour)
} }
func GetMoviesByRoomIDWithPage(roomID uint, page, pageSize int) ([]model.Movie, error) { func GetMoviesByRoomIDWithPage(roomID uint, page, max int) ([]*model.Movie, error) {
i, err := movieCache.Get(roomID) ms, err := GetAllMoviesByRoomID(roomID)
if err != nil { if err != nil {
return nil, err return nil, err
} }
ms := i.([]model.Movie) start := (page - 1) * max
if page < 1 { if start >= ms.Len() {
page = 1 start = ms.Len()
}
if pageSize < 1 {
pageSize = 1
} }
start := (page - 1) * pageSize end := start + max
end := page * pageSize if end > ms.Len() {
if start > len(ms) { end = ms.Len()
start = len(ms)
} }
if end > len(ms) { var m []*model.Movie = make([]*model.Movie, 0, end-start)
end = len(ms) idx := 0
for i := ms.Front(); i != nil; i = i.Next() {
if idx >= start && idx < end {
m = append(m, i.Value)
}
idx++
} }
return ms[start:end], nil return m, nil
} }
func GetMovieByID(roomID, id uint) (*model.Movie, error) { func GetMovieByID(roomID, id uint) (*model.Movie, error) {
var m []model.Movie ms, err := GetAllMoviesByRoomID(roomID)
i, err := movieCache.Get(roomID) if err != nil {
if err == nil { return nil, err
m = i.([]model.Movie)
} else {
m, err = GetAllMoviesByRoomID(roomID)
if err != nil {
return nil, err
}
} }
for _, v := range m { for i := ms.Front(); i != nil; i = i.Next() {
if v.ID == id { if i.Value.ID == id {
return &v, nil return i.Value, nil
} }
} }
return nil, errors.New("movie not found") return nil, errors.New("movie not found")
@ -69,126 +70,102 @@ func GetMovieByID(roomID, id uint) (*model.Movie, error) {
func GetMoviesCountByRoomID(roomID uint) (int, error) { func GetMoviesCountByRoomID(roomID uint) (int, error) {
ms, err := GetAllMoviesByRoomID(roomID) ms, err := GetAllMoviesByRoomID(roomID)
return len(ms), err if err != nil {
return 0, err
}
return ms.Len(), nil
} }
func DeleteMovieByID(roomID, id uint) error { func DeleteMovieByID(roomID, id uint) error {
err := db.DeleteMovieByID(roomID, id) ms, err := GetAllMoviesByRoomID(roomID)
if err != nil {
return err
}
i, err := movieCache.Get(roomID)
if err != nil { if err != nil {
return err return err
} }
ms := i.([]model.Movie) for i := ms.Front(); i != nil; i = i.Next() {
for i, v := range ms { if i.Value.ID == id {
if v.ID == id { ms.Remove(i)
ms = append(ms[:i], ms[i+1:]...) return db.DeleteMovieByID(roomID, id)
break
} }
} }
return nil return errors.New("movie not found")
} }
func UpdateMovie(movie model.Movie) error { func UpdateMovie(movie *model.Movie) error {
m, err := db.LoadAndUpdateMovie(movie) err := db.UpdateMovie(movie)
if err != nil { if err != nil {
return err return err
} }
i, err := movieCache.Get(movie.RoomID) m, err := GetMovieByID(movie.RoomID, movie.ID)
if err != nil { if err != nil {
return err return err
} }
ms := i.([]model.Movie) *m = *movie
for i, v := range ms {
if v.ID == movie.ID {
ms[i] = *m
break
}
}
return nil return nil
} }
func DeleteMoviesByRoomID(roomID uint) error { func DeleteMoviesByRoomID(roomID uint) error {
err := db.DeleteMoviesByRoomID(roomID)
if err != nil {
return err
}
movieCache.Remove(roomID) movieCache.Remove(roomID)
return nil return db.DeleteMoviesByRoomID(roomID)
} }
func LoadAndDeleteMovieByID(roomID, id uint) (*model.Movie, error) { func LoadAndDeleteMovieByID(roomID, id uint) (*model.Movie, error) {
m, err := db.LoadAndDeleteMovieByID(roomID, id) ms, err := GetAllMoviesByRoomID(roomID)
if err != nil {
return nil, err
}
i, err := movieCache.Get(roomID)
if err != nil { if err != nil {
return nil, err return nil, err
} }
ms := i.([]model.Movie) for i := ms.Front(); i != nil; i = i.Next() {
for i, v := range ms { if i.Value.ID == id {
if v.ID == id { ms.Remove(i)
ms = append(ms[:i], ms[i+1:]...) return db.LoadAndDeleteMovieByID(roomID, id)
break
} }
} }
return m, nil return nil, errors.New("movie not found")
} }
// data race // data race
func CreateMovie(movie *model.Movie) error { func CreateMovie(movie *model.Movie) error {
err := db.CreateMovie(movie) ms, err := GetAllMoviesByRoomID(movie.RoomID)
if err != nil { if err != nil {
return err return err
} }
i, err := movieCache.Get(movie.RoomID) err = db.CreateMovie(movie)
if err != nil { if err != nil {
movieCache.Set(movie.RoomID, []model.Movie{*movie}) return err
return nil
} }
ms := i.([]model.Movie) ms.PushBack(movie)
ms = append(ms, *movie)
movieCache.Set(movie.RoomID, ms)
return nil return nil
} }
func GetMovieWithPullKey(roomID uint, pullKey string) (*model.Movie, error) { func GetMovieWithPullKey(roomID uint, pullKey string) (*model.Movie, error) {
i, err := movieCache.Get(roomID) ms, err := GetAllMoviesByRoomID(roomID)
if err != nil { if err != nil {
return nil, err return nil, err
} }
ms := i.([]model.Movie) for i := ms.Front(); i != nil; i = i.Next() {
for _, v := range ms { if i.Value.PullKey == pullKey {
if v.PullKey == pullKey { return i.Value, nil
return &v, nil
} }
} }
return nil, errors.New("movie not found") return nil, errors.New("movie not found")
} }
func SwapMoviePositions(roomID uint, movie1ID uint, movie2ID uint) error { func SwapMoviePositions(roomID uint, movie1ID uint, movie2ID uint) error {
err := db.SwapMoviePositions(roomID, movie1ID, movie2ID) ms, err := GetAllMoviesByRoomID(roomID)
if err != nil {
return err
}
i, err := movieCache.Get(roomID)
if err != nil { if err != nil {
return err return err
} }
ms := i.([]model.Movie) var m1, m2 *model.Movie
movie1I, movie2I := 0, 0 for i := ms.Front(); i != nil; i = i.Next() {
for i, v := range ms { if i.Value.ID == movie1ID {
if v.ID == movie1ID { m1 = i.Value
movie1I = i
} }
if v.ID == movie2ID { if i.Value.ID == movie2ID {
movie2I = i m2 = i.Value
} }
} }
ms[movie1I].Position, ms[movie2I].Position = ms[movie2I].Position, ms[movie1I].Position if m1 == nil || m2 == nil {
ms[movie1I], ms[movie2I] = ms[movie2I], ms[movie1I] return errors.New("movie not found")
return nil }
m1.Position, m2.Position = m2.Position, m1.Position
return db.SwapMoviePositions(roomID, movie1ID, movie2ID)
} }

@ -77,14 +77,15 @@ func (r *Room) UpdateMovie(movieId uint, movie model.BaseMovieInfo) error {
return err return err
} }
switch { switch {
case (m.RtmpSource && !movie.RtmpSource) || (m.Live && m.Proxy && !movie.Proxy): case ((m.Live && m.Proxy) || (m.Live && m.RtmpSource)) && (!movie.Live && !movie.Proxy && !movie.RtmpSource):
r.lazyInit() r.lazyInit()
r.rtmpa.DelChannel(m.PullKey) r.rtmpa.DelChannel(m.PullKey)
m.PullKey = "" m.PullKey = ""
case m.Proxy && !movie.Proxy: case m.Proxy && !movie.Proxy:
m.PullKey = "" m.PullKey = ""
} }
return UpdateMovie(*m) m.MovieInfo.BaseMovieInfo = movie
return db.UpdateMovie(m)
} }
func (r *Room) InitMovie(movie *model.Movie) error { func (r *Room) InitMovie(movie *model.Movie) error {
@ -194,6 +195,7 @@ func (r *Room) InitMovie(movie *model.Movie) error {
func (r *Room) AddMovie(m model.MovieInfo) error { func (r *Room) AddMovie(m model.MovieInfo) error {
movie := &model.Movie{ movie := &model.Movie{
RoomID: r.ID, RoomID: r.ID,
Position: uint(time.Now().UnixMilli()),
MovieInfo: m, MovieInfo: m,
} }
@ -254,11 +256,19 @@ func (r *Room) GetMoviesCount() (int, error) {
return GetMoviesCountByRoomID(r.ID) return GetMoviesCountByRoomID(r.ID)
} }
func (r *Room) GetAllMoviesByRoomID() ([]model.Movie, error) { func (r *Room) GetAllMoviesByRoomID() ([]*model.Movie, error) {
return GetAllMoviesByRoomID(r.ID) ms, err := GetAllMoviesByRoomID(r.ID)
if err != nil {
return nil, err
}
var m []*model.Movie = make([]*model.Movie, ms.Len())
for i := ms.Front(); i != nil; i = i.Next() {
m[i.Value.Position-1] = i.Value
}
return m, nil
} }
func (r *Room) GetMoviesByRoomIDWithPage(page, pageSize int) ([]model.Movie, error) { func (r *Room) GetMoviesByRoomIDWithPage(page, pageSize int) ([]*model.Movie, error) {
return GetMoviesByRoomIDWithPage(r.ID, page, pageSize) return GetMoviesByRoomIDWithPage(r.ID, page, pageSize)
} }

Loading…
Cancel
Save