mirror of
https://github.com/stashapp/stash.git
synced 2025-12-06 08:26:00 +01:00
Fix database locked errors (#3153)
* Make read-only operations use WithReadTxn * Allow one database write thread * Add unit test for concurrent transactions * Perform some actions after commit to release txn * Suppress some errors from cancelled context
This commit is contained in:
parent
420c6fa9d7
commit
f39fa416a9
54 changed files with 626 additions and 311 deletions
|
|
@ -95,8 +95,12 @@ func (r *Resolver) withTxn(ctx context.Context, fn func(ctx context.Context) err
|
||||||
return txn.WithTxn(ctx, r.txnManager, fn)
|
return txn.WithTxn(ctx, r.txnManager, fn)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (r *Resolver) withReadTxn(ctx context.Context, fn func(ctx context.Context) error) error {
|
||||||
|
return txn.WithReadTxn(ctx, r.txnManager, fn)
|
||||||
|
}
|
||||||
|
|
||||||
func (r *queryResolver) MarkerWall(ctx context.Context, q *string) (ret []*models.SceneMarker, err error) {
|
func (r *queryResolver) MarkerWall(ctx context.Context, q *string) (ret []*models.SceneMarker, err error) {
|
||||||
if err := r.withTxn(ctx, func(ctx context.Context) error {
|
if err := r.withReadTxn(ctx, func(ctx context.Context) error {
|
||||||
ret, err = r.repository.SceneMarker.Wall(ctx, q)
|
ret, err = r.repository.SceneMarker.Wall(ctx, q)
|
||||||
return err
|
return err
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
|
|
@ -106,7 +110,7 @@ func (r *queryResolver) MarkerWall(ctx context.Context, q *string) (ret []*model
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *queryResolver) SceneWall(ctx context.Context, q *string) (ret []*models.Scene, err error) {
|
func (r *queryResolver) SceneWall(ctx context.Context, q *string) (ret []*models.Scene, err error) {
|
||||||
if err := r.withTxn(ctx, func(ctx context.Context) error {
|
if err := r.withReadTxn(ctx, func(ctx context.Context) error {
|
||||||
ret, err = r.repository.Scene.Wall(ctx, q)
|
ret, err = r.repository.Scene.Wall(ctx, q)
|
||||||
return err
|
return err
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
|
|
@ -117,7 +121,7 @@ func (r *queryResolver) SceneWall(ctx context.Context, q *string) (ret []*models
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *queryResolver) MarkerStrings(ctx context.Context, q *string, sort *string) (ret []*models.MarkerStringsResultType, err error) {
|
func (r *queryResolver) MarkerStrings(ctx context.Context, q *string, sort *string) (ret []*models.MarkerStringsResultType, err error) {
|
||||||
if err := r.withTxn(ctx, func(ctx context.Context) error {
|
if err := r.withReadTxn(ctx, func(ctx context.Context) error {
|
||||||
ret, err = r.repository.SceneMarker.GetMarkerStrings(ctx, q, sort)
|
ret, err = r.repository.SceneMarker.GetMarkerStrings(ctx, q, sort)
|
||||||
return err
|
return err
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
|
|
@ -129,7 +133,7 @@ func (r *queryResolver) MarkerStrings(ctx context.Context, q *string, sort *stri
|
||||||
|
|
||||||
func (r *queryResolver) Stats(ctx context.Context) (*StatsResultType, error) {
|
func (r *queryResolver) Stats(ctx context.Context) (*StatsResultType, error) {
|
||||||
var ret StatsResultType
|
var ret StatsResultType
|
||||||
if err := r.withTxn(ctx, func(ctx context.Context) error {
|
if err := r.withReadTxn(ctx, func(ctx context.Context) error {
|
||||||
repo := r.repository
|
repo := r.repository
|
||||||
scenesQB := repo.Scene
|
scenesQB := repo.Scene
|
||||||
imageQB := repo.Image
|
imageQB := repo.Image
|
||||||
|
|
@ -205,7 +209,7 @@ func (r *queryResolver) SceneMarkerTags(ctx context.Context, scene_id string) ([
|
||||||
var keys []int
|
var keys []int
|
||||||
tags := make(map[int]*SceneMarkerTag)
|
tags := make(map[int]*SceneMarkerTag)
|
||||||
|
|
||||||
if err := r.withTxn(ctx, func(ctx context.Context) error {
|
if err := r.withReadTxn(ctx, func(ctx context.Context) error {
|
||||||
sceneMarkers, err := r.repository.SceneMarker.FindBySceneID(ctx, sceneID)
|
sceneMarkers, err := r.repository.SceneMarker.FindBySceneID(ctx, sceneID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
|
|
||||||
|
|
@ -73,7 +73,7 @@ func (r *galleryResolver) Folder(ctx context.Context, obj *models.Gallery) (*Fol
|
||||||
|
|
||||||
var ret *file.Folder
|
var ret *file.Folder
|
||||||
|
|
||||||
if err := r.withTxn(ctx, func(ctx context.Context) error {
|
if err := r.withReadTxn(ctx, func(ctx context.Context) error {
|
||||||
var err error
|
var err error
|
||||||
|
|
||||||
ret, err = r.repository.Folder.Find(ctx, *obj.FolderID)
|
ret, err = r.repository.Folder.Find(ctx, *obj.FolderID)
|
||||||
|
|
@ -124,7 +124,7 @@ func (r *galleryResolver) FileModTime(ctx context.Context, obj *models.Gallery)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *galleryResolver) Images(ctx context.Context, obj *models.Gallery) (ret []*models.Image, err error) {
|
func (r *galleryResolver) Images(ctx context.Context, obj *models.Gallery) (ret []*models.Image, err error) {
|
||||||
if err := r.withTxn(ctx, func(ctx context.Context) error {
|
if err := r.withReadTxn(ctx, func(ctx context.Context) error {
|
||||||
var err error
|
var err error
|
||||||
|
|
||||||
// #2376 - sort images by path
|
// #2376 - sort images by path
|
||||||
|
|
@ -143,7 +143,7 @@ func (r *galleryResolver) Images(ctx context.Context, obj *models.Gallery) (ret
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *galleryResolver) Cover(ctx context.Context, obj *models.Gallery) (ret *models.Image, err error) {
|
func (r *galleryResolver) Cover(ctx context.Context, obj *models.Gallery) (ret *models.Image, err error) {
|
||||||
if err := r.withTxn(ctx, func(ctx context.Context) error {
|
if err := r.withReadTxn(ctx, func(ctx context.Context) error {
|
||||||
// doing this via Query is really slow, so stick with FindByGalleryID
|
// doing this via Query is really slow, so stick with FindByGalleryID
|
||||||
imgs, err := r.repository.Image.FindByGalleryID(ctx, obj.ID)
|
imgs, err := r.repository.Image.FindByGalleryID(ctx, obj.ID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -179,7 +179,7 @@ func (r *galleryResolver) Date(ctx context.Context, obj *models.Gallery) (*strin
|
||||||
|
|
||||||
func (r *galleryResolver) Checksum(ctx context.Context, obj *models.Gallery) (string, error) {
|
func (r *galleryResolver) Checksum(ctx context.Context, obj *models.Gallery) (string, error) {
|
||||||
if !obj.Files.PrimaryLoaded() {
|
if !obj.Files.PrimaryLoaded() {
|
||||||
if err := r.withTxn(ctx, func(ctx context.Context) error {
|
if err := r.withReadTxn(ctx, func(ctx context.Context) error {
|
||||||
return obj.LoadPrimaryFile(ctx, r.repository.File)
|
return obj.LoadPrimaryFile(ctx, r.repository.File)
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
|
|
@ -203,7 +203,7 @@ func (r *galleryResolver) Rating100(ctx context.Context, obj *models.Gallery) (*
|
||||||
|
|
||||||
func (r *galleryResolver) Scenes(ctx context.Context, obj *models.Gallery) (ret []*models.Scene, err error) {
|
func (r *galleryResolver) Scenes(ctx context.Context, obj *models.Gallery) (ret []*models.Scene, err error) {
|
||||||
if !obj.SceneIDs.Loaded() {
|
if !obj.SceneIDs.Loaded() {
|
||||||
if err := r.withTxn(ctx, func(ctx context.Context) error {
|
if err := r.withReadTxn(ctx, func(ctx context.Context) error {
|
||||||
return obj.LoadSceneIDs(ctx, r.repository.Gallery)
|
return obj.LoadSceneIDs(ctx, r.repository.Gallery)
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|
@ -225,7 +225,7 @@ func (r *galleryResolver) Studio(ctx context.Context, obj *models.Gallery) (ret
|
||||||
|
|
||||||
func (r *galleryResolver) Tags(ctx context.Context, obj *models.Gallery) (ret []*models.Tag, err error) {
|
func (r *galleryResolver) Tags(ctx context.Context, obj *models.Gallery) (ret []*models.Tag, err error) {
|
||||||
if !obj.TagIDs.Loaded() {
|
if !obj.TagIDs.Loaded() {
|
||||||
if err := r.withTxn(ctx, func(ctx context.Context) error {
|
if err := r.withReadTxn(ctx, func(ctx context.Context) error {
|
||||||
return obj.LoadTagIDs(ctx, r.repository.Gallery)
|
return obj.LoadTagIDs(ctx, r.repository.Gallery)
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|
@ -239,7 +239,7 @@ func (r *galleryResolver) Tags(ctx context.Context, obj *models.Gallery) (ret []
|
||||||
|
|
||||||
func (r *galleryResolver) Performers(ctx context.Context, obj *models.Gallery) (ret []*models.Performer, err error) {
|
func (r *galleryResolver) Performers(ctx context.Context, obj *models.Gallery) (ret []*models.Performer, err error) {
|
||||||
if !obj.PerformerIDs.Loaded() {
|
if !obj.PerformerIDs.Loaded() {
|
||||||
if err := r.withTxn(ctx, func(ctx context.Context) error {
|
if err := r.withReadTxn(ctx, func(ctx context.Context) error {
|
||||||
return obj.LoadPerformerIDs(ctx, r.repository.Gallery)
|
return obj.LoadPerformerIDs(ctx, r.repository.Gallery)
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|
@ -252,7 +252,7 @@ func (r *galleryResolver) Performers(ctx context.Context, obj *models.Gallery) (
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *galleryResolver) ImageCount(ctx context.Context, obj *models.Gallery) (ret int, err error) {
|
func (r *galleryResolver) ImageCount(ctx context.Context, obj *models.Gallery) (ret int, err error) {
|
||||||
if err := r.withTxn(ctx, func(ctx context.Context) error {
|
if err := r.withReadTxn(ctx, func(ctx context.Context) error {
|
||||||
var err error
|
var err error
|
||||||
ret, err = r.repository.Image.CountByGalleryID(ctx, obj.ID)
|
ret, err = r.repository.Image.CountByGalleryID(ctx, obj.ID)
|
||||||
return err
|
return err
|
||||||
|
|
|
||||||
|
|
@ -132,7 +132,7 @@ func (r *imageResolver) Paths(ctx context.Context, obj *models.Image) (*ImagePat
|
||||||
|
|
||||||
func (r *imageResolver) Galleries(ctx context.Context, obj *models.Image) (ret []*models.Gallery, err error) {
|
func (r *imageResolver) Galleries(ctx context.Context, obj *models.Image) (ret []*models.Gallery, err error) {
|
||||||
if !obj.GalleryIDs.Loaded() {
|
if !obj.GalleryIDs.Loaded() {
|
||||||
if err := r.withTxn(ctx, func(ctx context.Context) error {
|
if err := r.withReadTxn(ctx, func(ctx context.Context) error {
|
||||||
return obj.LoadGalleryIDs(ctx, r.repository.Image)
|
return obj.LoadGalleryIDs(ctx, r.repository.Image)
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|
@ -166,7 +166,7 @@ func (r *imageResolver) Studio(ctx context.Context, obj *models.Image) (ret *mod
|
||||||
|
|
||||||
func (r *imageResolver) Tags(ctx context.Context, obj *models.Image) (ret []*models.Tag, err error) {
|
func (r *imageResolver) Tags(ctx context.Context, obj *models.Image) (ret []*models.Tag, err error) {
|
||||||
if !obj.TagIDs.Loaded() {
|
if !obj.TagIDs.Loaded() {
|
||||||
if err := r.withTxn(ctx, func(ctx context.Context) error {
|
if err := r.withReadTxn(ctx, func(ctx context.Context) error {
|
||||||
return obj.LoadTagIDs(ctx, r.repository.Image)
|
return obj.LoadTagIDs(ctx, r.repository.Image)
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|
@ -180,7 +180,7 @@ func (r *imageResolver) Tags(ctx context.Context, obj *models.Image) (ret []*mod
|
||||||
|
|
||||||
func (r *imageResolver) Performers(ctx context.Context, obj *models.Image) (ret []*models.Performer, err error) {
|
func (r *imageResolver) Performers(ctx context.Context, obj *models.Image) (ret []*models.Performer, err error) {
|
||||||
if !obj.PerformerIDs.Loaded() {
|
if !obj.PerformerIDs.Loaded() {
|
||||||
if err := r.withTxn(ctx, func(ctx context.Context) error {
|
if err := r.withReadTxn(ctx, func(ctx context.Context) error {
|
||||||
return obj.LoadPerformerIDs(ctx, r.repository.Image)
|
return obj.LoadPerformerIDs(ctx, r.repository.Image)
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|
|
||||||
|
|
@ -94,7 +94,7 @@ func (r *movieResolver) FrontImagePath(ctx context.Context, obj *models.Movie) (
|
||||||
func (r *movieResolver) BackImagePath(ctx context.Context, obj *models.Movie) (*string, error) {
|
func (r *movieResolver) BackImagePath(ctx context.Context, obj *models.Movie) (*string, error) {
|
||||||
// don't return any thing if there is no back image
|
// don't return any thing if there is no back image
|
||||||
var img []byte
|
var img []byte
|
||||||
if err := r.withTxn(ctx, func(ctx context.Context) error {
|
if err := r.withReadTxn(ctx, func(ctx context.Context) error {
|
||||||
var err error
|
var err error
|
||||||
img, err = r.repository.Movie.GetBackImage(ctx, obj.ID)
|
img, err = r.repository.Movie.GetBackImage(ctx, obj.ID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -117,7 +117,7 @@ func (r *movieResolver) BackImagePath(ctx context.Context, obj *models.Movie) (*
|
||||||
|
|
||||||
func (r *movieResolver) SceneCount(ctx context.Context, obj *models.Movie) (ret *int, err error) {
|
func (r *movieResolver) SceneCount(ctx context.Context, obj *models.Movie) (ret *int, err error) {
|
||||||
var res int
|
var res int
|
||||||
if err := r.withTxn(ctx, func(ctx context.Context) error {
|
if err := r.withReadTxn(ctx, func(ctx context.Context) error {
|
||||||
res, err = r.repository.Scene.CountByMovieID(ctx, obj.ID)
|
res, err = r.repository.Scene.CountByMovieID(ctx, obj.ID)
|
||||||
return err
|
return err
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
|
|
@ -128,7 +128,7 @@ func (r *movieResolver) SceneCount(ctx context.Context, obj *models.Movie) (ret
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *movieResolver) Scenes(ctx context.Context, obj *models.Movie) (ret []*models.Scene, err error) {
|
func (r *movieResolver) Scenes(ctx context.Context, obj *models.Movie) (ret []*models.Scene, err error) {
|
||||||
if err := r.withTxn(ctx, func(ctx context.Context) error {
|
if err := r.withReadTxn(ctx, func(ctx context.Context) error {
|
||||||
var err error
|
var err error
|
||||||
ret, err = r.repository.Scene.FindByMovieID(ctx, obj.ID)
|
ret, err = r.repository.Scene.FindByMovieID(ctx, obj.ID)
|
||||||
return err
|
return err
|
||||||
|
|
|
||||||
|
|
@ -37,7 +37,7 @@ func (r *performerResolver) ImagePath(ctx context.Context, obj *models.Performer
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *performerResolver) Tags(ctx context.Context, obj *models.Performer) (ret []*models.Tag, err error) {
|
func (r *performerResolver) Tags(ctx context.Context, obj *models.Performer) (ret []*models.Tag, err error) {
|
||||||
if err := r.withTxn(ctx, func(ctx context.Context) error {
|
if err := r.withReadTxn(ctx, func(ctx context.Context) error {
|
||||||
ret, err = r.repository.Tag.FindByPerformerID(ctx, obj.ID)
|
ret, err = r.repository.Tag.FindByPerformerID(ctx, obj.ID)
|
||||||
return err
|
return err
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
|
|
@ -49,7 +49,7 @@ func (r *performerResolver) Tags(ctx context.Context, obj *models.Performer) (re
|
||||||
|
|
||||||
func (r *performerResolver) SceneCount(ctx context.Context, obj *models.Performer) (ret *int, err error) {
|
func (r *performerResolver) SceneCount(ctx context.Context, obj *models.Performer) (ret *int, err error) {
|
||||||
var res int
|
var res int
|
||||||
if err := r.withTxn(ctx, func(ctx context.Context) error {
|
if err := r.withReadTxn(ctx, func(ctx context.Context) error {
|
||||||
res, err = r.repository.Scene.CountByPerformerID(ctx, obj.ID)
|
res, err = r.repository.Scene.CountByPerformerID(ctx, obj.ID)
|
||||||
return err
|
return err
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
|
|
@ -61,7 +61,7 @@ func (r *performerResolver) SceneCount(ctx context.Context, obj *models.Performe
|
||||||
|
|
||||||
func (r *performerResolver) ImageCount(ctx context.Context, obj *models.Performer) (ret *int, err error) {
|
func (r *performerResolver) ImageCount(ctx context.Context, obj *models.Performer) (ret *int, err error) {
|
||||||
var res int
|
var res int
|
||||||
if err := r.withTxn(ctx, func(ctx context.Context) error {
|
if err := r.withReadTxn(ctx, func(ctx context.Context) error {
|
||||||
res, err = image.CountByPerformerID(ctx, r.repository.Image, obj.ID)
|
res, err = image.CountByPerformerID(ctx, r.repository.Image, obj.ID)
|
||||||
return err
|
return err
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
|
|
@ -73,7 +73,7 @@ func (r *performerResolver) ImageCount(ctx context.Context, obj *models.Performe
|
||||||
|
|
||||||
func (r *performerResolver) GalleryCount(ctx context.Context, obj *models.Performer) (ret *int, err error) {
|
func (r *performerResolver) GalleryCount(ctx context.Context, obj *models.Performer) (ret *int, err error) {
|
||||||
var res int
|
var res int
|
||||||
if err := r.withTxn(ctx, func(ctx context.Context) error {
|
if err := r.withReadTxn(ctx, func(ctx context.Context) error {
|
||||||
res, err = gallery.CountByPerformerID(ctx, r.repository.Gallery, obj.ID)
|
res, err = gallery.CountByPerformerID(ctx, r.repository.Gallery, obj.ID)
|
||||||
return err
|
return err
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
|
|
@ -84,7 +84,7 @@ func (r *performerResolver) GalleryCount(ctx context.Context, obj *models.Perfor
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *performerResolver) Scenes(ctx context.Context, obj *models.Performer) (ret []*models.Scene, err error) {
|
func (r *performerResolver) Scenes(ctx context.Context, obj *models.Performer) (ret []*models.Scene, err error) {
|
||||||
if err := r.withTxn(ctx, func(ctx context.Context) error {
|
if err := r.withReadTxn(ctx, func(ctx context.Context) error {
|
||||||
ret, err = r.repository.Scene.FindByPerformerID(ctx, obj.ID)
|
ret, err = r.repository.Scene.FindByPerformerID(ctx, obj.ID)
|
||||||
return err
|
return err
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
|
|
@ -96,7 +96,7 @@ func (r *performerResolver) Scenes(ctx context.Context, obj *models.Performer) (
|
||||||
|
|
||||||
func (r *performerResolver) StashIds(ctx context.Context, obj *models.Performer) ([]*models.StashID, error) {
|
func (r *performerResolver) StashIds(ctx context.Context, obj *models.Performer) ([]*models.StashID, error) {
|
||||||
var ret []models.StashID
|
var ret []models.StashID
|
||||||
if err := r.withTxn(ctx, func(ctx context.Context) error {
|
if err := r.withReadTxn(ctx, func(ctx context.Context) error {
|
||||||
var err error
|
var err error
|
||||||
ret, err = r.repository.Performer.GetStashIDs(ctx, obj.ID)
|
ret, err = r.repository.Performer.GetStashIDs(ctx, obj.ID)
|
||||||
return err
|
return err
|
||||||
|
|
@ -128,7 +128,7 @@ func (r *performerResolver) DeathDate(ctx context.Context, obj *models.Performer
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *performerResolver) Movies(ctx context.Context, obj *models.Performer) (ret []*models.Movie, err error) {
|
func (r *performerResolver) Movies(ctx context.Context, obj *models.Performer) (ret []*models.Movie, err error) {
|
||||||
if err := r.withTxn(ctx, func(ctx context.Context) error {
|
if err := r.withReadTxn(ctx, func(ctx context.Context) error {
|
||||||
ret, err = r.repository.Movie.FindByPerformerID(ctx, obj.ID)
|
ret, err = r.repository.Movie.FindByPerformerID(ctx, obj.ID)
|
||||||
return err
|
return err
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
|
|
@ -140,7 +140,7 @@ func (r *performerResolver) Movies(ctx context.Context, obj *models.Performer) (
|
||||||
|
|
||||||
func (r *performerResolver) MovieCount(ctx context.Context, obj *models.Performer) (ret *int, err error) {
|
func (r *performerResolver) MovieCount(ctx context.Context, obj *models.Performer) (ret *int, err error) {
|
||||||
var res int
|
var res int
|
||||||
if err := r.withTxn(ctx, func(ctx context.Context) error {
|
if err := r.withReadTxn(ctx, func(ctx context.Context) error {
|
||||||
res, err = r.repository.Movie.CountByPerformerID(ctx, obj.ID)
|
res, err = r.repository.Movie.CountByPerformerID(ctx, obj.ID)
|
||||||
return err
|
return err
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
|
|
|
||||||
|
|
@ -206,7 +206,7 @@ func (r *sceneResolver) Paths(ctx context.Context, obj *models.Scene) (*ScenePat
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *sceneResolver) SceneMarkers(ctx context.Context, obj *models.Scene) (ret []*models.SceneMarker, err error) {
|
func (r *sceneResolver) SceneMarkers(ctx context.Context, obj *models.Scene) (ret []*models.SceneMarker, err error) {
|
||||||
if err := r.withTxn(ctx, func(ctx context.Context) error {
|
if err := r.withReadTxn(ctx, func(ctx context.Context) error {
|
||||||
ret, err = r.repository.SceneMarker.FindBySceneID(ctx, obj.ID)
|
ret, err = r.repository.SceneMarker.FindBySceneID(ctx, obj.ID)
|
||||||
return err
|
return err
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
|
|
@ -225,7 +225,7 @@ func (r *sceneResolver) Captions(ctx context.Context, obj *models.Scene) (ret []
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := r.withTxn(ctx, func(ctx context.Context) error {
|
if err := r.withReadTxn(ctx, func(ctx context.Context) error {
|
||||||
ret, err = r.repository.File.GetCaptions(ctx, primaryFile.Base().ID)
|
ret, err = r.repository.File.GetCaptions(ctx, primaryFile.Base().ID)
|
||||||
return err
|
return err
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
|
|
@ -237,7 +237,7 @@ func (r *sceneResolver) Captions(ctx context.Context, obj *models.Scene) (ret []
|
||||||
|
|
||||||
func (r *sceneResolver) Galleries(ctx context.Context, obj *models.Scene) (ret []*models.Gallery, err error) {
|
func (r *sceneResolver) Galleries(ctx context.Context, obj *models.Scene) (ret []*models.Gallery, err error) {
|
||||||
if !obj.GalleryIDs.Loaded() {
|
if !obj.GalleryIDs.Loaded() {
|
||||||
if err := r.withTxn(ctx, func(ctx context.Context) error {
|
if err := r.withReadTxn(ctx, func(ctx context.Context) error {
|
||||||
return obj.LoadGalleryIDs(ctx, r.repository.Scene)
|
return obj.LoadGalleryIDs(ctx, r.repository.Scene)
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|
@ -259,7 +259,7 @@ func (r *sceneResolver) Studio(ctx context.Context, obj *models.Scene) (ret *mod
|
||||||
|
|
||||||
func (r *sceneResolver) Movies(ctx context.Context, obj *models.Scene) (ret []*SceneMovie, err error) {
|
func (r *sceneResolver) Movies(ctx context.Context, obj *models.Scene) (ret []*SceneMovie, err error) {
|
||||||
if !obj.Movies.Loaded() {
|
if !obj.Movies.Loaded() {
|
||||||
if err := r.withTxn(ctx, func(ctx context.Context) error {
|
if err := r.withReadTxn(ctx, func(ctx context.Context) error {
|
||||||
qb := r.repository.Scene
|
qb := r.repository.Scene
|
||||||
|
|
||||||
return obj.LoadMovies(ctx, qb)
|
return obj.LoadMovies(ctx, qb)
|
||||||
|
|
@ -290,7 +290,7 @@ func (r *sceneResolver) Movies(ctx context.Context, obj *models.Scene) (ret []*S
|
||||||
|
|
||||||
func (r *sceneResolver) Tags(ctx context.Context, obj *models.Scene) (ret []*models.Tag, err error) {
|
func (r *sceneResolver) Tags(ctx context.Context, obj *models.Scene) (ret []*models.Tag, err error) {
|
||||||
if !obj.TagIDs.Loaded() {
|
if !obj.TagIDs.Loaded() {
|
||||||
if err := r.withTxn(ctx, func(ctx context.Context) error {
|
if err := r.withReadTxn(ctx, func(ctx context.Context) error {
|
||||||
return obj.LoadTagIDs(ctx, r.repository.Scene)
|
return obj.LoadTagIDs(ctx, r.repository.Scene)
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|
@ -304,7 +304,7 @@ func (r *sceneResolver) Tags(ctx context.Context, obj *models.Scene) (ret []*mod
|
||||||
|
|
||||||
func (r *sceneResolver) Performers(ctx context.Context, obj *models.Scene) (ret []*models.Performer, err error) {
|
func (r *sceneResolver) Performers(ctx context.Context, obj *models.Scene) (ret []*models.Performer, err error) {
|
||||||
if !obj.PerformerIDs.Loaded() {
|
if !obj.PerformerIDs.Loaded() {
|
||||||
if err := r.withTxn(ctx, func(ctx context.Context) error {
|
if err := r.withReadTxn(ctx, func(ctx context.Context) error {
|
||||||
return obj.LoadPerformerIDs(ctx, r.repository.Scene)
|
return obj.LoadPerformerIDs(ctx, r.repository.Scene)
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|
@ -327,7 +327,7 @@ func stashIDsSliceToPtrSlice(v []models.StashID) []*models.StashID {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *sceneResolver) StashIds(ctx context.Context, obj *models.Scene) (ret []*models.StashID, err error) {
|
func (r *sceneResolver) StashIds(ctx context.Context, obj *models.Scene) (ret []*models.StashID, err error) {
|
||||||
if err := r.withTxn(ctx, func(ctx context.Context) error {
|
if err := r.withReadTxn(ctx, func(ctx context.Context) error {
|
||||||
return obj.LoadStashIDs(ctx, r.repository.Scene)
|
return obj.LoadStashIDs(ctx, r.repository.Scene)
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,7 @@ func (r *sceneMarkerResolver) Scene(ctx context.Context, obj *models.SceneMarker
|
||||||
panic("Invalid scene id")
|
panic("Invalid scene id")
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := r.withTxn(ctx, func(ctx context.Context) error {
|
if err := r.withReadTxn(ctx, func(ctx context.Context) error {
|
||||||
sceneID := int(obj.SceneID.Int64)
|
sceneID := int(obj.SceneID.Int64)
|
||||||
ret, err = r.repository.Scene.Find(ctx, sceneID)
|
ret, err = r.repository.Scene.Find(ctx, sceneID)
|
||||||
return err
|
return err
|
||||||
|
|
@ -25,7 +25,7 @@ func (r *sceneMarkerResolver) Scene(ctx context.Context, obj *models.SceneMarker
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *sceneMarkerResolver) PrimaryTag(ctx context.Context, obj *models.SceneMarker) (ret *models.Tag, err error) {
|
func (r *sceneMarkerResolver) PrimaryTag(ctx context.Context, obj *models.SceneMarker) (ret *models.Tag, err error) {
|
||||||
if err := r.withTxn(ctx, func(ctx context.Context) error {
|
if err := r.withReadTxn(ctx, func(ctx context.Context) error {
|
||||||
ret, err = r.repository.Tag.Find(ctx, obj.PrimaryTagID)
|
ret, err = r.repository.Tag.Find(ctx, obj.PrimaryTagID)
|
||||||
return err
|
return err
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
|
|
@ -36,7 +36,7 @@ func (r *sceneMarkerResolver) PrimaryTag(ctx context.Context, obj *models.SceneM
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *sceneMarkerResolver) Tags(ctx context.Context, obj *models.SceneMarker) (ret []*models.Tag, err error) {
|
func (r *sceneMarkerResolver) Tags(ctx context.Context, obj *models.SceneMarker) (ret []*models.Tag, err error) {
|
||||||
if err := r.withTxn(ctx, func(ctx context.Context) error {
|
if err := r.withReadTxn(ctx, func(ctx context.Context) error {
|
||||||
ret, err = r.repository.Tag.FindBySceneMarkerID(ctx, obj.ID)
|
ret, err = r.repository.Tag.FindBySceneMarkerID(ctx, obj.ID)
|
||||||
return err
|
return err
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
|
|
|
||||||
|
|
@ -30,7 +30,7 @@ func (r *studioResolver) ImagePath(ctx context.Context, obj *models.Studio) (*st
|
||||||
imagePath := urlbuilders.NewStudioURLBuilder(baseURL, obj).GetStudioImageURL()
|
imagePath := urlbuilders.NewStudioURLBuilder(baseURL, obj).GetStudioImageURL()
|
||||||
|
|
||||||
var hasImage bool
|
var hasImage bool
|
||||||
if err := r.withTxn(ctx, func(ctx context.Context) error {
|
if err := r.withReadTxn(ctx, func(ctx context.Context) error {
|
||||||
var err error
|
var err error
|
||||||
hasImage, err = r.repository.Studio.HasImage(ctx, obj.ID)
|
hasImage, err = r.repository.Studio.HasImage(ctx, obj.ID)
|
||||||
return err
|
return err
|
||||||
|
|
@ -47,7 +47,7 @@ func (r *studioResolver) ImagePath(ctx context.Context, obj *models.Studio) (*st
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *studioResolver) Aliases(ctx context.Context, obj *models.Studio) (ret []string, err error) {
|
func (r *studioResolver) Aliases(ctx context.Context, obj *models.Studio) (ret []string, err error) {
|
||||||
if err := r.withTxn(ctx, func(ctx context.Context) error {
|
if err := r.withReadTxn(ctx, func(ctx context.Context) error {
|
||||||
ret, err = r.repository.Studio.GetAliases(ctx, obj.ID)
|
ret, err = r.repository.Studio.GetAliases(ctx, obj.ID)
|
||||||
return err
|
return err
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
|
|
@ -59,7 +59,7 @@ func (r *studioResolver) Aliases(ctx context.Context, obj *models.Studio) (ret [
|
||||||
|
|
||||||
func (r *studioResolver) SceneCount(ctx context.Context, obj *models.Studio) (ret *int, err error) {
|
func (r *studioResolver) SceneCount(ctx context.Context, obj *models.Studio) (ret *int, err error) {
|
||||||
var res int
|
var res int
|
||||||
if err := r.withTxn(ctx, func(ctx context.Context) error {
|
if err := r.withReadTxn(ctx, func(ctx context.Context) error {
|
||||||
res, err = r.repository.Scene.CountByStudioID(ctx, obj.ID)
|
res, err = r.repository.Scene.CountByStudioID(ctx, obj.ID)
|
||||||
return err
|
return err
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
|
|
@ -71,7 +71,7 @@ func (r *studioResolver) SceneCount(ctx context.Context, obj *models.Studio) (re
|
||||||
|
|
||||||
func (r *studioResolver) ImageCount(ctx context.Context, obj *models.Studio) (ret *int, err error) {
|
func (r *studioResolver) ImageCount(ctx context.Context, obj *models.Studio) (ret *int, err error) {
|
||||||
var res int
|
var res int
|
||||||
if err := r.withTxn(ctx, func(ctx context.Context) error {
|
if err := r.withReadTxn(ctx, func(ctx context.Context) error {
|
||||||
res, err = image.CountByStudioID(ctx, r.repository.Image, obj.ID)
|
res, err = image.CountByStudioID(ctx, r.repository.Image, obj.ID)
|
||||||
return err
|
return err
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
|
|
@ -83,7 +83,7 @@ func (r *studioResolver) ImageCount(ctx context.Context, obj *models.Studio) (re
|
||||||
|
|
||||||
func (r *studioResolver) GalleryCount(ctx context.Context, obj *models.Studio) (ret *int, err error) {
|
func (r *studioResolver) GalleryCount(ctx context.Context, obj *models.Studio) (ret *int, err error) {
|
||||||
var res int
|
var res int
|
||||||
if err := r.withTxn(ctx, func(ctx context.Context) error {
|
if err := r.withReadTxn(ctx, func(ctx context.Context) error {
|
||||||
res, err = gallery.CountByStudioID(ctx, r.repository.Gallery, obj.ID)
|
res, err = gallery.CountByStudioID(ctx, r.repository.Gallery, obj.ID)
|
||||||
return err
|
return err
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
|
|
@ -102,7 +102,7 @@ func (r *studioResolver) ParentStudio(ctx context.Context, obj *models.Studio) (
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *studioResolver) ChildStudios(ctx context.Context, obj *models.Studio) (ret []*models.Studio, err error) {
|
func (r *studioResolver) ChildStudios(ctx context.Context, obj *models.Studio) (ret []*models.Studio, err error) {
|
||||||
if err := r.withTxn(ctx, func(ctx context.Context) error {
|
if err := r.withReadTxn(ctx, func(ctx context.Context) error {
|
||||||
ret, err = r.repository.Studio.FindChildren(ctx, obj.ID)
|
ret, err = r.repository.Studio.FindChildren(ctx, obj.ID)
|
||||||
return err
|
return err
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
|
|
@ -114,7 +114,7 @@ func (r *studioResolver) ChildStudios(ctx context.Context, obj *models.Studio) (
|
||||||
|
|
||||||
func (r *studioResolver) StashIds(ctx context.Context, obj *models.Studio) ([]*models.StashID, error) {
|
func (r *studioResolver) StashIds(ctx context.Context, obj *models.Studio) ([]*models.StashID, error) {
|
||||||
var ret []models.StashID
|
var ret []models.StashID
|
||||||
if err := r.withTxn(ctx, func(ctx context.Context) error {
|
if err := r.withReadTxn(ctx, func(ctx context.Context) error {
|
||||||
var err error
|
var err error
|
||||||
ret, err = r.repository.Studio.GetStashIDs(ctx, obj.ID)
|
ret, err = r.repository.Studio.GetStashIDs(ctx, obj.ID)
|
||||||
return err
|
return err
|
||||||
|
|
@ -157,7 +157,7 @@ func (r *studioResolver) UpdatedAt(ctx context.Context, obj *models.Studio) (*ti
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *studioResolver) Movies(ctx context.Context, obj *models.Studio) (ret []*models.Movie, err error) {
|
func (r *studioResolver) Movies(ctx context.Context, obj *models.Studio) (ret []*models.Movie, err error) {
|
||||||
if err := r.withTxn(ctx, func(ctx context.Context) error {
|
if err := r.withReadTxn(ctx, func(ctx context.Context) error {
|
||||||
ret, err = r.repository.Movie.FindByStudioID(ctx, obj.ID)
|
ret, err = r.repository.Movie.FindByStudioID(ctx, obj.ID)
|
||||||
return err
|
return err
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
|
|
@ -169,7 +169,7 @@ func (r *studioResolver) Movies(ctx context.Context, obj *models.Studio) (ret []
|
||||||
|
|
||||||
func (r *studioResolver) MovieCount(ctx context.Context, obj *models.Studio) (ret *int, err error) {
|
func (r *studioResolver) MovieCount(ctx context.Context, obj *models.Studio) (ret *int, err error) {
|
||||||
var res int
|
var res int
|
||||||
if err := r.withTxn(ctx, func(ctx context.Context) error {
|
if err := r.withReadTxn(ctx, func(ctx context.Context) error {
|
||||||
res, err = r.repository.Movie.CountByStudioID(ctx, obj.ID)
|
res, err = r.repository.Movie.CountByStudioID(ctx, obj.ID)
|
||||||
return err
|
return err
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,7 @@ func (r *tagResolver) Description(ctx context.Context, obj *models.Tag) (*string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *tagResolver) Parents(ctx context.Context, obj *models.Tag) (ret []*models.Tag, err error) {
|
func (r *tagResolver) Parents(ctx context.Context, obj *models.Tag) (ret []*models.Tag, err error) {
|
||||||
if err := r.withTxn(ctx, func(ctx context.Context) error {
|
if err := r.withReadTxn(ctx, func(ctx context.Context) error {
|
||||||
ret, err = r.repository.Tag.FindByChildTagID(ctx, obj.ID)
|
ret, err = r.repository.Tag.FindByChildTagID(ctx, obj.ID)
|
||||||
return err
|
return err
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
|
|
@ -29,7 +29,7 @@ func (r *tagResolver) Parents(ctx context.Context, obj *models.Tag) (ret []*mode
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *tagResolver) Children(ctx context.Context, obj *models.Tag) (ret []*models.Tag, err error) {
|
func (r *tagResolver) Children(ctx context.Context, obj *models.Tag) (ret []*models.Tag, err error) {
|
||||||
if err := r.withTxn(ctx, func(ctx context.Context) error {
|
if err := r.withReadTxn(ctx, func(ctx context.Context) error {
|
||||||
ret, err = r.repository.Tag.FindByParentTagID(ctx, obj.ID)
|
ret, err = r.repository.Tag.FindByParentTagID(ctx, obj.ID)
|
||||||
return err
|
return err
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
|
|
@ -40,7 +40,7 @@ func (r *tagResolver) Children(ctx context.Context, obj *models.Tag) (ret []*mod
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *tagResolver) Aliases(ctx context.Context, obj *models.Tag) (ret []string, err error) {
|
func (r *tagResolver) Aliases(ctx context.Context, obj *models.Tag) (ret []string, err error) {
|
||||||
if err := r.withTxn(ctx, func(ctx context.Context) error {
|
if err := r.withReadTxn(ctx, func(ctx context.Context) error {
|
||||||
ret, err = r.repository.Tag.GetAliases(ctx, obj.ID)
|
ret, err = r.repository.Tag.GetAliases(ctx, obj.ID)
|
||||||
return err
|
return err
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
|
|
@ -52,7 +52,7 @@ func (r *tagResolver) Aliases(ctx context.Context, obj *models.Tag) (ret []strin
|
||||||
|
|
||||||
func (r *tagResolver) SceneCount(ctx context.Context, obj *models.Tag) (ret *int, err error) {
|
func (r *tagResolver) SceneCount(ctx context.Context, obj *models.Tag) (ret *int, err error) {
|
||||||
var count int
|
var count int
|
||||||
if err := r.withTxn(ctx, func(ctx context.Context) error {
|
if err := r.withReadTxn(ctx, func(ctx context.Context) error {
|
||||||
count, err = r.repository.Scene.CountByTagID(ctx, obj.ID)
|
count, err = r.repository.Scene.CountByTagID(ctx, obj.ID)
|
||||||
return err
|
return err
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
|
|
@ -64,7 +64,7 @@ func (r *tagResolver) SceneCount(ctx context.Context, obj *models.Tag) (ret *int
|
||||||
|
|
||||||
func (r *tagResolver) SceneMarkerCount(ctx context.Context, obj *models.Tag) (ret *int, err error) {
|
func (r *tagResolver) SceneMarkerCount(ctx context.Context, obj *models.Tag) (ret *int, err error) {
|
||||||
var count int
|
var count int
|
||||||
if err := r.withTxn(ctx, func(ctx context.Context) error {
|
if err := r.withReadTxn(ctx, func(ctx context.Context) error {
|
||||||
count, err = r.repository.SceneMarker.CountByTagID(ctx, obj.ID)
|
count, err = r.repository.SceneMarker.CountByTagID(ctx, obj.ID)
|
||||||
return err
|
return err
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
|
|
@ -76,7 +76,7 @@ func (r *tagResolver) SceneMarkerCount(ctx context.Context, obj *models.Tag) (re
|
||||||
|
|
||||||
func (r *tagResolver) ImageCount(ctx context.Context, obj *models.Tag) (ret *int, err error) {
|
func (r *tagResolver) ImageCount(ctx context.Context, obj *models.Tag) (ret *int, err error) {
|
||||||
var res int
|
var res int
|
||||||
if err := r.withTxn(ctx, func(ctx context.Context) error {
|
if err := r.withReadTxn(ctx, func(ctx context.Context) error {
|
||||||
res, err = image.CountByTagID(ctx, r.repository.Image, obj.ID)
|
res, err = image.CountByTagID(ctx, r.repository.Image, obj.ID)
|
||||||
return err
|
return err
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
|
|
@ -88,7 +88,7 @@ func (r *tagResolver) ImageCount(ctx context.Context, obj *models.Tag) (ret *int
|
||||||
|
|
||||||
func (r *tagResolver) GalleryCount(ctx context.Context, obj *models.Tag) (ret *int, err error) {
|
func (r *tagResolver) GalleryCount(ctx context.Context, obj *models.Tag) (ret *int, err error) {
|
||||||
var res int
|
var res int
|
||||||
if err := r.withTxn(ctx, func(ctx context.Context) error {
|
if err := r.withReadTxn(ctx, func(ctx context.Context) error {
|
||||||
res, err = gallery.CountByTagID(ctx, r.repository.Gallery, obj.ID)
|
res, err = gallery.CountByTagID(ctx, r.repository.Gallery, obj.ID)
|
||||||
return err
|
return err
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
|
|
@ -100,7 +100,7 @@ func (r *tagResolver) GalleryCount(ctx context.Context, obj *models.Tag) (ret *i
|
||||||
|
|
||||||
func (r *tagResolver) PerformerCount(ctx context.Context, obj *models.Tag) (ret *int, err error) {
|
func (r *tagResolver) PerformerCount(ctx context.Context, obj *models.Tag) (ret *int, err error) {
|
||||||
var count int
|
var count int
|
||||||
if err := r.withTxn(ctx, func(ctx context.Context) error {
|
if err := r.withReadTxn(ctx, func(ctx context.Context) error {
|
||||||
count, err = r.repository.Performer.CountByTagID(ctx, obj.ID)
|
count, err = r.repository.Performer.CountByTagID(ctx, obj.ID)
|
||||||
return err
|
return err
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
|
|
|
||||||
|
|
@ -51,7 +51,7 @@ func (r *mutationResolver) SubmitStashBoxSceneDraft(ctx context.Context, input S
|
||||||
}
|
}
|
||||||
|
|
||||||
var res *string
|
var res *string
|
||||||
err = r.withTxn(ctx, func(ctx context.Context) error {
|
err = r.withReadTxn(ctx, func(ctx context.Context) error {
|
||||||
qb := r.repository.Scene
|
qb := r.repository.Scene
|
||||||
scene, err := qb.Find(ctx, id)
|
scene, err := qb.Find(ctx, id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -82,7 +82,7 @@ func (r *mutationResolver) SubmitStashBoxPerformerDraft(ctx context.Context, inp
|
||||||
}
|
}
|
||||||
|
|
||||||
var res *string
|
var res *string
|
||||||
err = r.withTxn(ctx, func(ctx context.Context) error {
|
err = r.withReadTxn(ctx, func(ctx context.Context) error {
|
||||||
qb := r.repository.Performer
|
qb := r.repository.Performer
|
||||||
performer, err := qb.Find(ctx, id)
|
performer, err := qb.Find(ctx, id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,7 @@ func (r *queryResolver) FindGallery(ctx context.Context, id string) (ret *models
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := r.withTxn(ctx, func(ctx context.Context) error {
|
if err := r.withReadTxn(ctx, func(ctx context.Context) error {
|
||||||
ret, err = r.repository.Gallery.Find(ctx, idInt)
|
ret, err = r.repository.Gallery.Find(ctx, idInt)
|
||||||
return err
|
return err
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
|
|
@ -24,7 +24,7 @@ func (r *queryResolver) FindGallery(ctx context.Context, id string) (ret *models
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *queryResolver) FindGalleries(ctx context.Context, galleryFilter *models.GalleryFilterType, filter *models.FindFilterType) (ret *FindGalleriesResultType, err error) {
|
func (r *queryResolver) FindGalleries(ctx context.Context, galleryFilter *models.GalleryFilterType, filter *models.FindFilterType) (ret *FindGalleriesResultType, err error) {
|
||||||
if err := r.withTxn(ctx, func(ctx context.Context) error {
|
if err := r.withReadTxn(ctx, func(ctx context.Context) error {
|
||||||
galleries, total, err := r.repository.Gallery.Query(ctx, galleryFilter, filter)
|
galleries, total, err := r.repository.Gallery.Query(ctx, galleryFilter, filter)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,7 @@ import (
|
||||||
func (r *queryResolver) FindImage(ctx context.Context, id *string, checksum *string) (*models.Image, error) {
|
func (r *queryResolver) FindImage(ctx context.Context, id *string, checksum *string) (*models.Image, error) {
|
||||||
var image *models.Image
|
var image *models.Image
|
||||||
|
|
||||||
if err := r.withTxn(ctx, func(ctx context.Context) error {
|
if err := r.withReadTxn(ctx, func(ctx context.Context) error {
|
||||||
qb := r.repository.Image
|
qb := r.repository.Image
|
||||||
var err error
|
var err error
|
||||||
|
|
||||||
|
|
@ -47,7 +47,7 @@ func (r *queryResolver) FindImage(ctx context.Context, id *string, checksum *str
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *queryResolver) FindImages(ctx context.Context, imageFilter *models.ImageFilterType, imageIds []int, filter *models.FindFilterType) (ret *FindImagesResultType, err error) {
|
func (r *queryResolver) FindImages(ctx context.Context, imageFilter *models.ImageFilterType, imageIds []int, filter *models.FindFilterType) (ret *FindImagesResultType, err error) {
|
||||||
if err := r.withTxn(ctx, func(ctx context.Context) error {
|
if err := r.withReadTxn(ctx, func(ctx context.Context) error {
|
||||||
qb := r.repository.Image
|
qb := r.repository.Image
|
||||||
|
|
||||||
fields := graphql.CollectAllFields(ctx)
|
fields := graphql.CollectAllFields(ctx)
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,7 @@ func (r *queryResolver) FindMovie(ctx context.Context, id string) (ret *models.M
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := r.withTxn(ctx, func(ctx context.Context) error {
|
if err := r.withReadTxn(ctx, func(ctx context.Context) error {
|
||||||
ret, err = r.repository.Movie.Find(ctx, idInt)
|
ret, err = r.repository.Movie.Find(ctx, idInt)
|
||||||
return err
|
return err
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
|
|
@ -24,7 +24,7 @@ func (r *queryResolver) FindMovie(ctx context.Context, id string) (ret *models.M
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *queryResolver) FindMovies(ctx context.Context, movieFilter *models.MovieFilterType, filter *models.FindFilterType) (ret *FindMoviesResultType, err error) {
|
func (r *queryResolver) FindMovies(ctx context.Context, movieFilter *models.MovieFilterType, filter *models.FindFilterType) (ret *FindMoviesResultType, err error) {
|
||||||
if err := r.withTxn(ctx, func(ctx context.Context) error {
|
if err := r.withReadTxn(ctx, func(ctx context.Context) error {
|
||||||
movies, total, err := r.repository.Movie.Query(ctx, movieFilter, filter)
|
movies, total, err := r.repository.Movie.Query(ctx, movieFilter, filter)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
|
@ -44,7 +44,7 @@ func (r *queryResolver) FindMovies(ctx context.Context, movieFilter *models.Movi
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *queryResolver) AllMovies(ctx context.Context) (ret []*models.Movie, err error) {
|
func (r *queryResolver) AllMovies(ctx context.Context) (ret []*models.Movie, err error) {
|
||||||
if err := r.withTxn(ctx, func(ctx context.Context) error {
|
if err := r.withReadTxn(ctx, func(ctx context.Context) error {
|
||||||
ret, err = r.repository.Movie.All(ctx)
|
ret, err = r.repository.Movie.All(ctx)
|
||||||
return err
|
return err
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,7 @@ func (r *queryResolver) FindPerformer(ctx context.Context, id string) (ret *mode
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := r.withTxn(ctx, func(ctx context.Context) error {
|
if err := r.withReadTxn(ctx, func(ctx context.Context) error {
|
||||||
ret, err = r.repository.Performer.Find(ctx, idInt)
|
ret, err = r.repository.Performer.Find(ctx, idInt)
|
||||||
return err
|
return err
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
|
|
@ -24,7 +24,7 @@ func (r *queryResolver) FindPerformer(ctx context.Context, id string) (ret *mode
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *queryResolver) FindPerformers(ctx context.Context, performerFilter *models.PerformerFilterType, filter *models.FindFilterType) (ret *FindPerformersResultType, err error) {
|
func (r *queryResolver) FindPerformers(ctx context.Context, performerFilter *models.PerformerFilterType, filter *models.FindFilterType) (ret *FindPerformersResultType, err error) {
|
||||||
if err := r.withTxn(ctx, func(ctx context.Context) error {
|
if err := r.withReadTxn(ctx, func(ctx context.Context) error {
|
||||||
performers, total, err := r.repository.Performer.Query(ctx, performerFilter, filter)
|
performers, total, err := r.repository.Performer.Query(ctx, performerFilter, filter)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
|
@ -43,7 +43,7 @@ func (r *queryResolver) FindPerformers(ctx context.Context, performerFilter *mod
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *queryResolver) AllPerformers(ctx context.Context) (ret []*models.Performer, err error) {
|
func (r *queryResolver) AllPerformers(ctx context.Context) (ret []*models.Performer, err error) {
|
||||||
if err := r.withTxn(ctx, func(ctx context.Context) error {
|
if err := r.withReadTxn(ctx, func(ctx context.Context) error {
|
||||||
ret, err = r.repository.Performer.All(ctx)
|
ret, err = r.repository.Performer.All(ctx)
|
||||||
return err
|
return err
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,7 @@ func (r *queryResolver) FindSavedFilter(ctx context.Context, id string) (ret *mo
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := r.withTxn(ctx, func(ctx context.Context) error {
|
if err := r.withReadTxn(ctx, func(ctx context.Context) error {
|
||||||
ret, err = r.repository.SavedFilter.Find(ctx, idInt)
|
ret, err = r.repository.SavedFilter.Find(ctx, idInt)
|
||||||
return err
|
return err
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
|
|
@ -23,7 +23,7 @@ func (r *queryResolver) FindSavedFilter(ctx context.Context, id string) (ret *mo
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *queryResolver) FindSavedFilters(ctx context.Context, mode *models.FilterMode) (ret []*models.SavedFilter, err error) {
|
func (r *queryResolver) FindSavedFilters(ctx context.Context, mode *models.FilterMode) (ret []*models.SavedFilter, err error) {
|
||||||
if err := r.withTxn(ctx, func(ctx context.Context) error {
|
if err := r.withReadTxn(ctx, func(ctx context.Context) error {
|
||||||
if mode != nil {
|
if mode != nil {
|
||||||
ret, err = r.repository.SavedFilter.FindByMode(ctx, *mode)
|
ret, err = r.repository.SavedFilter.FindByMode(ctx, *mode)
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -37,7 +37,7 @@ func (r *queryResolver) FindSavedFilters(ctx context.Context, mode *models.Filte
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *queryResolver) FindDefaultFilter(ctx context.Context, mode models.FilterMode) (ret *models.SavedFilter, err error) {
|
func (r *queryResolver) FindDefaultFilter(ctx context.Context, mode models.FilterMode) (ret *models.SavedFilter, err error) {
|
||||||
if err := r.withTxn(ctx, func(ctx context.Context) error {
|
if err := r.withReadTxn(ctx, func(ctx context.Context) error {
|
||||||
ret, err = r.repository.SavedFilter.FindDefault(ctx, mode)
|
ret, err = r.repository.SavedFilter.FindDefault(ctx, mode)
|
||||||
return err
|
return err
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,7 @@ import (
|
||||||
|
|
||||||
func (r *queryResolver) FindScene(ctx context.Context, id *string, checksum *string) (*models.Scene, error) {
|
func (r *queryResolver) FindScene(ctx context.Context, id *string, checksum *string) (*models.Scene, error) {
|
||||||
var scene *models.Scene
|
var scene *models.Scene
|
||||||
if err := r.withTxn(ctx, func(ctx context.Context) error {
|
if err := r.withReadTxn(ctx, func(ctx context.Context) error {
|
||||||
qb := r.repository.Scene
|
qb := r.repository.Scene
|
||||||
var err error
|
var err error
|
||||||
if id != nil {
|
if id != nil {
|
||||||
|
|
@ -43,7 +43,7 @@ func (r *queryResolver) FindScene(ctx context.Context, id *string, checksum *str
|
||||||
func (r *queryResolver) FindSceneByHash(ctx context.Context, input SceneHashInput) (*models.Scene, error) {
|
func (r *queryResolver) FindSceneByHash(ctx context.Context, input SceneHashInput) (*models.Scene, error) {
|
||||||
var scene *models.Scene
|
var scene *models.Scene
|
||||||
|
|
||||||
if err := r.withTxn(ctx, func(ctx context.Context) error {
|
if err := r.withReadTxn(ctx, func(ctx context.Context) error {
|
||||||
qb := r.repository.Scene
|
qb := r.repository.Scene
|
||||||
if input.Checksum != nil {
|
if input.Checksum != nil {
|
||||||
scenes, err := qb.FindByChecksum(ctx, *input.Checksum)
|
scenes, err := qb.FindByChecksum(ctx, *input.Checksum)
|
||||||
|
|
@ -74,7 +74,7 @@ func (r *queryResolver) FindSceneByHash(ctx context.Context, input SceneHashInpu
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *queryResolver) FindScenes(ctx context.Context, sceneFilter *models.SceneFilterType, sceneIDs []int, filter *models.FindFilterType) (ret *FindScenesResultType, err error) {
|
func (r *queryResolver) FindScenes(ctx context.Context, sceneFilter *models.SceneFilterType, sceneIDs []int, filter *models.FindFilterType) (ret *FindScenesResultType, err error) {
|
||||||
if err := r.withTxn(ctx, func(ctx context.Context) error {
|
if err := r.withReadTxn(ctx, func(ctx context.Context) error {
|
||||||
var scenes []*models.Scene
|
var scenes []*models.Scene
|
||||||
var err error
|
var err error
|
||||||
|
|
||||||
|
|
@ -135,7 +135,7 @@ func (r *queryResolver) FindScenes(ctx context.Context, sceneFilter *models.Scen
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *queryResolver) FindScenesByPathRegex(ctx context.Context, filter *models.FindFilterType) (ret *FindScenesResultType, err error) {
|
func (r *queryResolver) FindScenesByPathRegex(ctx context.Context, filter *models.FindFilterType) (ret *FindScenesResultType, err error) {
|
||||||
if err := r.withTxn(ctx, func(ctx context.Context) error {
|
if err := r.withReadTxn(ctx, func(ctx context.Context) error {
|
||||||
|
|
||||||
sceneFilter := &models.SceneFilterType{}
|
sceneFilter := &models.SceneFilterType{}
|
||||||
|
|
||||||
|
|
@ -192,7 +192,7 @@ func (r *queryResolver) FindScenesByPathRegex(ctx context.Context, filter *model
|
||||||
func (r *queryResolver) ParseSceneFilenames(ctx context.Context, filter *models.FindFilterType, config manager.SceneParserInput) (ret *SceneParserResultType, err error) {
|
func (r *queryResolver) ParseSceneFilenames(ctx context.Context, filter *models.FindFilterType, config manager.SceneParserInput) (ret *SceneParserResultType, err error) {
|
||||||
parser := manager.NewSceneFilenameParser(filter, config)
|
parser := manager.NewSceneFilenameParser(filter, config)
|
||||||
|
|
||||||
if err := r.withTxn(ctx, func(ctx context.Context) error {
|
if err := r.withReadTxn(ctx, func(ctx context.Context) error {
|
||||||
result, count, err := parser.Parse(ctx, manager.SceneFilenameParserRepository{
|
result, count, err := parser.Parse(ctx, manager.SceneFilenameParserRepository{
|
||||||
Scene: r.repository.Scene,
|
Scene: r.repository.Scene,
|
||||||
Performer: r.repository.Performer,
|
Performer: r.repository.Performer,
|
||||||
|
|
@ -223,7 +223,7 @@ func (r *queryResolver) FindDuplicateScenes(ctx context.Context, distance *int)
|
||||||
if distance != nil {
|
if distance != nil {
|
||||||
dist = *distance
|
dist = *distance
|
||||||
}
|
}
|
||||||
if err := r.withTxn(ctx, func(ctx context.Context) error {
|
if err := r.withReadTxn(ctx, func(ctx context.Context) error {
|
||||||
ret, err = r.repository.Scene.FindDuplicates(ctx, dist)
|
ret, err = r.repository.Scene.FindDuplicates(ctx, dist)
|
||||||
return err
|
return err
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
func (r *queryResolver) FindSceneMarkers(ctx context.Context, sceneMarkerFilter *models.SceneMarkerFilterType, filter *models.FindFilterType) (ret *FindSceneMarkersResultType, err error) {
|
func (r *queryResolver) FindSceneMarkers(ctx context.Context, sceneMarkerFilter *models.SceneMarkerFilterType, filter *models.FindFilterType) (ret *FindSceneMarkersResultType, err error) {
|
||||||
if err := r.withTxn(ctx, func(ctx context.Context) error {
|
if err := r.withReadTxn(ctx, func(ctx context.Context) error {
|
||||||
sceneMarkers, total, err := r.repository.SceneMarker.Query(ctx, sceneMarkerFilter, filter)
|
sceneMarkers, total, err := r.repository.SceneMarker.Query(ctx, sceneMarkerFilter, filter)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,7 @@ func (r *queryResolver) FindStudio(ctx context.Context, id string) (ret *models.
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := r.withTxn(ctx, func(ctx context.Context) error {
|
if err := r.withReadTxn(ctx, func(ctx context.Context) error {
|
||||||
var err error
|
var err error
|
||||||
ret, err = r.repository.Studio.Find(ctx, idInt)
|
ret, err = r.repository.Studio.Find(ctx, idInt)
|
||||||
return err
|
return err
|
||||||
|
|
@ -25,7 +25,7 @@ func (r *queryResolver) FindStudio(ctx context.Context, id string) (ret *models.
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *queryResolver) FindStudios(ctx context.Context, studioFilter *models.StudioFilterType, filter *models.FindFilterType) (ret *FindStudiosResultType, err error) {
|
func (r *queryResolver) FindStudios(ctx context.Context, studioFilter *models.StudioFilterType, filter *models.FindFilterType) (ret *FindStudiosResultType, err error) {
|
||||||
if err := r.withTxn(ctx, func(ctx context.Context) error {
|
if err := r.withReadTxn(ctx, func(ctx context.Context) error {
|
||||||
studios, total, err := r.repository.Studio.Query(ctx, studioFilter, filter)
|
studios, total, err := r.repository.Studio.Query(ctx, studioFilter, filter)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
|
@ -45,7 +45,7 @@ func (r *queryResolver) FindStudios(ctx context.Context, studioFilter *models.St
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *queryResolver) AllStudios(ctx context.Context) (ret []*models.Studio, err error) {
|
func (r *queryResolver) AllStudios(ctx context.Context) (ret []*models.Studio, err error) {
|
||||||
if err := r.withTxn(ctx, func(ctx context.Context) error {
|
if err := r.withReadTxn(ctx, func(ctx context.Context) error {
|
||||||
ret, err = r.repository.Studio.All(ctx)
|
ret, err = r.repository.Studio.All(ctx)
|
||||||
return err
|
return err
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,7 @@ func (r *queryResolver) FindTag(ctx context.Context, id string) (ret *models.Tag
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := r.withTxn(ctx, func(ctx context.Context) error {
|
if err := r.withReadTxn(ctx, func(ctx context.Context) error {
|
||||||
ret, err = r.repository.Tag.Find(ctx, idInt)
|
ret, err = r.repository.Tag.Find(ctx, idInt)
|
||||||
return err
|
return err
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
|
|
@ -24,7 +24,7 @@ func (r *queryResolver) FindTag(ctx context.Context, id string) (ret *models.Tag
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *queryResolver) FindTags(ctx context.Context, tagFilter *models.TagFilterType, filter *models.FindFilterType) (ret *FindTagsResultType, err error) {
|
func (r *queryResolver) FindTags(ctx context.Context, tagFilter *models.TagFilterType, filter *models.FindFilterType) (ret *FindTagsResultType, err error) {
|
||||||
if err := r.withTxn(ctx, func(ctx context.Context) error {
|
if err := r.withReadTxn(ctx, func(ctx context.Context) error {
|
||||||
tags, total, err := r.repository.Tag.Query(ctx, tagFilter, filter)
|
tags, total, err := r.repository.Tag.Query(ctx, tagFilter, filter)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
|
@ -44,7 +44,7 @@ func (r *queryResolver) FindTags(ctx context.Context, tagFilter *models.TagFilte
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *queryResolver) AllTags(ctx context.Context) (ret []*models.Tag, err error) {
|
func (r *queryResolver) AllTags(ctx context.Context) (ret []*models.Tag, err error) {
|
||||||
if err := r.withTxn(ctx, func(ctx context.Context) error {
|
if err := r.withReadTxn(ctx, func(ctx context.Context) error {
|
||||||
ret, err = r.repository.Tag.All(ctx)
|
ret, err = r.repository.Tag.All(ctx)
|
||||||
return err
|
return err
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,7 @@ import (
|
||||||
func (r *queryResolver) SceneStreams(ctx context.Context, id *string) ([]*manager.SceneStreamEndpoint, error) {
|
func (r *queryResolver) SceneStreams(ctx context.Context, id *string) ([]*manager.SceneStreamEndpoint, error) {
|
||||||
// find the scene
|
// find the scene
|
||||||
var scene *models.Scene
|
var scene *models.Scene
|
||||||
if err := r.withTxn(ctx, func(ctx context.Context) error {
|
if err := r.withReadTxn(ctx, func(ctx context.Context) error {
|
||||||
idInt, _ := strconv.Atoi(*id)
|
idInt, _ := strconv.Atoi(*id)
|
||||||
var err error
|
var err error
|
||||||
scene, err = r.repository.Scene.Find(ctx, idInt)
|
scene, err = r.repository.Scene.Find(ctx, idInt)
|
||||||
|
|
|
||||||
|
|
@ -143,7 +143,7 @@ func (rs imageRoutes) ImageCtx(next http.Handler) http.Handler {
|
||||||
imageID, _ := strconv.Atoi(imageIdentifierQueryParam)
|
imageID, _ := strconv.Atoi(imageIdentifierQueryParam)
|
||||||
|
|
||||||
var image *models.Image
|
var image *models.Image
|
||||||
_ = txn.WithTxn(r.Context(), rs.txnManager, func(ctx context.Context) error {
|
_ = txn.WithReadTxn(r.Context(), rs.txnManager, func(ctx context.Context) error {
|
||||||
qb := rs.imageFinder
|
qb := rs.imageFinder
|
||||||
if imageID == 0 {
|
if imageID == 0 {
|
||||||
images, _ := qb.FindByChecksum(ctx, imageIdentifierQueryParam)
|
images, _ := qb.FindByChecksum(ctx, imageIdentifierQueryParam)
|
||||||
|
|
|
||||||
|
|
@ -41,7 +41,7 @@ func (rs movieRoutes) FrontImage(w http.ResponseWriter, r *http.Request) {
|
||||||
defaultParam := r.URL.Query().Get("default")
|
defaultParam := r.URL.Query().Get("default")
|
||||||
var image []byte
|
var image []byte
|
||||||
if defaultParam != "true" {
|
if defaultParam != "true" {
|
||||||
readTxnErr := txn.WithTxn(r.Context(), rs.txnManager, func(ctx context.Context) error {
|
readTxnErr := txn.WithReadTxn(r.Context(), rs.txnManager, func(ctx context.Context) error {
|
||||||
image, _ = rs.movieFinder.GetFrontImage(ctx, movie.ID)
|
image, _ = rs.movieFinder.GetFrontImage(ctx, movie.ID)
|
||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
|
|
@ -67,7 +67,7 @@ func (rs movieRoutes) BackImage(w http.ResponseWriter, r *http.Request) {
|
||||||
defaultParam := r.URL.Query().Get("default")
|
defaultParam := r.URL.Query().Get("default")
|
||||||
var image []byte
|
var image []byte
|
||||||
if defaultParam != "true" {
|
if defaultParam != "true" {
|
||||||
readTxnErr := txn.WithTxn(r.Context(), rs.txnManager, func(ctx context.Context) error {
|
readTxnErr := txn.WithReadTxn(r.Context(), rs.txnManager, func(ctx context.Context) error {
|
||||||
image, _ = rs.movieFinder.GetBackImage(ctx, movie.ID)
|
image, _ = rs.movieFinder.GetBackImage(ctx, movie.ID)
|
||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
|
|
@ -97,7 +97,7 @@ func (rs movieRoutes) MovieCtx(next http.Handler) http.Handler {
|
||||||
}
|
}
|
||||||
|
|
||||||
var movie *models.Movie
|
var movie *models.Movie
|
||||||
_ = txn.WithTxn(r.Context(), rs.txnManager, func(ctx context.Context) error {
|
_ = txn.WithReadTxn(r.Context(), rs.txnManager, func(ctx context.Context) error {
|
||||||
movie, _ = rs.movieFinder.Find(ctx, movieID)
|
movie, _ = rs.movieFinder.Find(ctx, movieID)
|
||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
|
|
|
||||||
|
|
@ -41,7 +41,7 @@ func (rs performerRoutes) Image(w http.ResponseWriter, r *http.Request) {
|
||||||
|
|
||||||
var image []byte
|
var image []byte
|
||||||
if defaultParam != "true" {
|
if defaultParam != "true" {
|
||||||
readTxnErr := txn.WithTxn(r.Context(), rs.txnManager, func(ctx context.Context) error {
|
readTxnErr := txn.WithReadTxn(r.Context(), rs.txnManager, func(ctx context.Context) error {
|
||||||
image, _ = rs.performerFinder.GetImage(ctx, performer.ID)
|
image, _ = rs.performerFinder.GetImage(ctx, performer.ID)
|
||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
|
|
@ -71,7 +71,7 @@ func (rs performerRoutes) PerformerCtx(next http.Handler) http.Handler {
|
||||||
}
|
}
|
||||||
|
|
||||||
var performer *models.Performer
|
var performer *models.Performer
|
||||||
_ = txn.WithTxn(r.Context(), rs.txnManager, func(ctx context.Context) error {
|
_ = txn.WithReadTxn(r.Context(), rs.txnManager, func(ctx context.Context) error {
|
||||||
var err error
|
var err error
|
||||||
performer, err = rs.performerFinder.Find(ctx, performerID)
|
performer, err = rs.performerFinder.Find(ctx, performerID)
|
||||||
return err
|
return err
|
||||||
|
|
|
||||||
|
|
@ -264,7 +264,7 @@ func (rs sceneRoutes) getChapterVttTitle(ctx context.Context, marker *models.Sce
|
||||||
}
|
}
|
||||||
|
|
||||||
var title string
|
var title string
|
||||||
if err := txn.WithTxn(ctx, rs.txnManager, func(ctx context.Context) error {
|
if err := txn.WithReadTxn(ctx, rs.txnManager, func(ctx context.Context) error {
|
||||||
qb := rs.tagFinder
|
qb := rs.tagFinder
|
||||||
primaryTag, err := qb.Find(ctx, marker.PrimaryTagID)
|
primaryTag, err := qb.Find(ctx, marker.PrimaryTagID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -293,7 +293,7 @@ func (rs sceneRoutes) getChapterVttTitle(ctx context.Context, marker *models.Sce
|
||||||
func (rs sceneRoutes) ChapterVtt(w http.ResponseWriter, r *http.Request) {
|
func (rs sceneRoutes) ChapterVtt(w http.ResponseWriter, r *http.Request) {
|
||||||
scene := r.Context().Value(sceneKey).(*models.Scene)
|
scene := r.Context().Value(sceneKey).(*models.Scene)
|
||||||
var sceneMarkers []*models.SceneMarker
|
var sceneMarkers []*models.SceneMarker
|
||||||
readTxnErr := txn.WithTxn(r.Context(), rs.txnManager, func(ctx context.Context) error {
|
readTxnErr := txn.WithReadTxn(r.Context(), rs.txnManager, func(ctx context.Context) error {
|
||||||
var err error
|
var err error
|
||||||
sceneMarkers, err = rs.sceneMarkerFinder.FindBySceneID(ctx, scene.ID)
|
sceneMarkers, err = rs.sceneMarkerFinder.FindBySceneID(ctx, scene.ID)
|
||||||
return err
|
return err
|
||||||
|
|
@ -349,7 +349,7 @@ func (rs sceneRoutes) Caption(w http.ResponseWriter, r *http.Request, lang strin
|
||||||
s := r.Context().Value(sceneKey).(*models.Scene)
|
s := r.Context().Value(sceneKey).(*models.Scene)
|
||||||
|
|
||||||
var captions []*models.VideoCaption
|
var captions []*models.VideoCaption
|
||||||
readTxnErr := txn.WithTxn(r.Context(), rs.txnManager, func(ctx context.Context) error {
|
readTxnErr := txn.WithReadTxn(r.Context(), rs.txnManager, func(ctx context.Context) error {
|
||||||
var err error
|
var err error
|
||||||
primaryFile := s.Files.Primary()
|
primaryFile := s.Files.Primary()
|
||||||
if primaryFile == nil {
|
if primaryFile == nil {
|
||||||
|
|
@ -423,7 +423,7 @@ func (rs sceneRoutes) SceneMarkerStream(w http.ResponseWriter, r *http.Request)
|
||||||
scene := r.Context().Value(sceneKey).(*models.Scene)
|
scene := r.Context().Value(sceneKey).(*models.Scene)
|
||||||
sceneMarkerID, _ := strconv.Atoi(chi.URLParam(r, "sceneMarkerId"))
|
sceneMarkerID, _ := strconv.Atoi(chi.URLParam(r, "sceneMarkerId"))
|
||||||
var sceneMarker *models.SceneMarker
|
var sceneMarker *models.SceneMarker
|
||||||
readTxnErr := txn.WithTxn(r.Context(), rs.txnManager, func(ctx context.Context) error {
|
readTxnErr := txn.WithReadTxn(r.Context(), rs.txnManager, func(ctx context.Context) error {
|
||||||
var err error
|
var err error
|
||||||
sceneMarker, err = rs.sceneMarkerFinder.Find(ctx, sceneMarkerID)
|
sceneMarker, err = rs.sceneMarkerFinder.Find(ctx, sceneMarkerID)
|
||||||
return err
|
return err
|
||||||
|
|
@ -450,7 +450,7 @@ func (rs sceneRoutes) SceneMarkerPreview(w http.ResponseWriter, r *http.Request)
|
||||||
scene := r.Context().Value(sceneKey).(*models.Scene)
|
scene := r.Context().Value(sceneKey).(*models.Scene)
|
||||||
sceneMarkerID, _ := strconv.Atoi(chi.URLParam(r, "sceneMarkerId"))
|
sceneMarkerID, _ := strconv.Atoi(chi.URLParam(r, "sceneMarkerId"))
|
||||||
var sceneMarker *models.SceneMarker
|
var sceneMarker *models.SceneMarker
|
||||||
readTxnErr := txn.WithTxn(r.Context(), rs.txnManager, func(ctx context.Context) error {
|
readTxnErr := txn.WithReadTxn(r.Context(), rs.txnManager, func(ctx context.Context) error {
|
||||||
var err error
|
var err error
|
||||||
sceneMarker, err = rs.sceneMarkerFinder.Find(ctx, sceneMarkerID)
|
sceneMarker, err = rs.sceneMarkerFinder.Find(ctx, sceneMarkerID)
|
||||||
return err
|
return err
|
||||||
|
|
@ -487,7 +487,7 @@ func (rs sceneRoutes) SceneMarkerScreenshot(w http.ResponseWriter, r *http.Reque
|
||||||
scene := r.Context().Value(sceneKey).(*models.Scene)
|
scene := r.Context().Value(sceneKey).(*models.Scene)
|
||||||
sceneMarkerID, _ := strconv.Atoi(chi.URLParam(r, "sceneMarkerId"))
|
sceneMarkerID, _ := strconv.Atoi(chi.URLParam(r, "sceneMarkerId"))
|
||||||
var sceneMarker *models.SceneMarker
|
var sceneMarker *models.SceneMarker
|
||||||
readTxnErr := txn.WithTxn(r.Context(), rs.txnManager, func(ctx context.Context) error {
|
readTxnErr := txn.WithReadTxn(r.Context(), rs.txnManager, func(ctx context.Context) error {
|
||||||
var err error
|
var err error
|
||||||
sceneMarker, err = rs.sceneMarkerFinder.Find(ctx, sceneMarkerID)
|
sceneMarker, err = rs.sceneMarkerFinder.Find(ctx, sceneMarkerID)
|
||||||
return err
|
return err
|
||||||
|
|
@ -528,7 +528,7 @@ func (rs sceneRoutes) SceneCtx(next http.Handler) http.Handler {
|
||||||
sceneID, _ := strconv.Atoi(sceneIdentifierQueryParam)
|
sceneID, _ := strconv.Atoi(sceneIdentifierQueryParam)
|
||||||
|
|
||||||
var scene *models.Scene
|
var scene *models.Scene
|
||||||
_ = txn.WithTxn(r.Context(), rs.txnManager, func(ctx context.Context) error {
|
_ = txn.WithReadTxn(r.Context(), rs.txnManager, func(ctx context.Context) error {
|
||||||
qb := rs.sceneFinder
|
qb := rs.sceneFinder
|
||||||
if sceneID == 0 {
|
if sceneID == 0 {
|
||||||
var scenes []*models.Scene
|
var scenes []*models.Scene
|
||||||
|
|
|
||||||
|
|
@ -41,7 +41,7 @@ func (rs studioRoutes) Image(w http.ResponseWriter, r *http.Request) {
|
||||||
|
|
||||||
var image []byte
|
var image []byte
|
||||||
if defaultParam != "true" {
|
if defaultParam != "true" {
|
||||||
readTxnErr := txn.WithTxn(r.Context(), rs.txnManager, func(ctx context.Context) error {
|
readTxnErr := txn.WithReadTxn(r.Context(), rs.txnManager, func(ctx context.Context) error {
|
||||||
image, _ = rs.studioFinder.GetImage(ctx, studio.ID)
|
image, _ = rs.studioFinder.GetImage(ctx, studio.ID)
|
||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
|
|
@ -71,7 +71,7 @@ func (rs studioRoutes) StudioCtx(next http.Handler) http.Handler {
|
||||||
}
|
}
|
||||||
|
|
||||||
var studio *models.Studio
|
var studio *models.Studio
|
||||||
_ = txn.WithTxn(r.Context(), rs.txnManager, func(ctx context.Context) error {
|
_ = txn.WithReadTxn(r.Context(), rs.txnManager, func(ctx context.Context) error {
|
||||||
var err error
|
var err error
|
||||||
studio, err = rs.studioFinder.Find(ctx, studioID)
|
studio, err = rs.studioFinder.Find(ctx, studioID)
|
||||||
return err
|
return err
|
||||||
|
|
|
||||||
|
|
@ -41,7 +41,7 @@ func (rs tagRoutes) Image(w http.ResponseWriter, r *http.Request) {
|
||||||
|
|
||||||
var image []byte
|
var image []byte
|
||||||
if defaultParam != "true" {
|
if defaultParam != "true" {
|
||||||
readTxnErr := txn.WithTxn(r.Context(), rs.txnManager, func(ctx context.Context) error {
|
readTxnErr := txn.WithReadTxn(r.Context(), rs.txnManager, func(ctx context.Context) error {
|
||||||
image, _ = rs.tagFinder.GetImage(ctx, tag.ID)
|
image, _ = rs.tagFinder.GetImage(ctx, tag.ID)
|
||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
|
|
@ -71,7 +71,7 @@ func (rs tagRoutes) TagCtx(next http.Handler) http.Handler {
|
||||||
}
|
}
|
||||||
|
|
||||||
var tag *models.Tag
|
var tag *models.Tag
|
||||||
_ = txn.WithTxn(r.Context(), rs.txnManager, func(ctx context.Context) error {
|
_ = txn.WithReadTxn(r.Context(), rs.txnManager, func(ctx context.Context) error {
|
||||||
var err error
|
var err error
|
||||||
tag, err = rs.tagFinder.Find(ctx, tagID)
|
tag, err = rs.tagFinder.Find(ctx, tagID)
|
||||||
return err
|
return err
|
||||||
|
|
|
||||||
|
|
@ -360,7 +360,7 @@ func (me *contentDirectoryService) handleBrowseMetadata(obj object, host string)
|
||||||
} else {
|
} else {
|
||||||
var scene *models.Scene
|
var scene *models.Scene
|
||||||
|
|
||||||
if err := txn.WithTxn(context.TODO(), me.txnManager, func(ctx context.Context) error {
|
if err := txn.WithReadTxn(context.TODO(), me.txnManager, func(ctx context.Context) error {
|
||||||
scene, err = me.repository.SceneFinder.Find(ctx, sceneID)
|
scene, err = me.repository.SceneFinder.Find(ctx, sceneID)
|
||||||
if scene != nil {
|
if scene != nil {
|
||||||
err = scene.LoadPrimaryFile(ctx, me.repository.FileFinder)
|
err = scene.LoadPrimaryFile(ctx, me.repository.FileFinder)
|
||||||
|
|
@ -443,7 +443,7 @@ func getRootObjects() []interface{} {
|
||||||
func (me *contentDirectoryService) getVideos(sceneFilter *models.SceneFilterType, parentID string, host string) []interface{} {
|
func (me *contentDirectoryService) getVideos(sceneFilter *models.SceneFilterType, parentID string, host string) []interface{} {
|
||||||
var objs []interface{}
|
var objs []interface{}
|
||||||
|
|
||||||
if err := txn.WithTxn(context.TODO(), me.txnManager, func(ctx context.Context) error {
|
if err := txn.WithReadTxn(context.TODO(), me.txnManager, func(ctx context.Context) error {
|
||||||
sort := "title"
|
sort := "title"
|
||||||
findFilter := &models.FindFilterType{
|
findFilter := &models.FindFilterType{
|
||||||
PerPage: &pageSize,
|
PerPage: &pageSize,
|
||||||
|
|
@ -486,7 +486,7 @@ func (me *contentDirectoryService) getVideos(sceneFilter *models.SceneFilterType
|
||||||
func (me *contentDirectoryService) getPageVideos(sceneFilter *models.SceneFilterType, parentID string, page int, host string) []interface{} {
|
func (me *contentDirectoryService) getPageVideos(sceneFilter *models.SceneFilterType, parentID string, page int, host string) []interface{} {
|
||||||
var objs []interface{}
|
var objs []interface{}
|
||||||
|
|
||||||
if err := txn.WithTxn(context.TODO(), me.txnManager, func(ctx context.Context) error {
|
if err := txn.WithReadTxn(context.TODO(), me.txnManager, func(ctx context.Context) error {
|
||||||
pager := scenePager{
|
pager := scenePager{
|
||||||
sceneFilter: sceneFilter,
|
sceneFilter: sceneFilter,
|
||||||
parentID: parentID,
|
parentID: parentID,
|
||||||
|
|
@ -527,7 +527,7 @@ func (me *contentDirectoryService) getAllScenes(host string) []interface{} {
|
||||||
func (me *contentDirectoryService) getStudios() []interface{} {
|
func (me *contentDirectoryService) getStudios() []interface{} {
|
||||||
var objs []interface{}
|
var objs []interface{}
|
||||||
|
|
||||||
if err := txn.WithTxn(context.TODO(), me.txnManager, func(ctx context.Context) error {
|
if err := txn.WithReadTxn(context.TODO(), me.txnManager, func(ctx context.Context) error {
|
||||||
studios, err := me.repository.StudioFinder.All(ctx)
|
studios, err := me.repository.StudioFinder.All(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
|
@ -566,7 +566,7 @@ func (me *contentDirectoryService) getStudioScenes(paths []string, host string)
|
||||||
func (me *contentDirectoryService) getTags() []interface{} {
|
func (me *contentDirectoryService) getTags() []interface{} {
|
||||||
var objs []interface{}
|
var objs []interface{}
|
||||||
|
|
||||||
if err := txn.WithTxn(context.TODO(), me.txnManager, func(ctx context.Context) error {
|
if err := txn.WithReadTxn(context.TODO(), me.txnManager, func(ctx context.Context) error {
|
||||||
tags, err := me.repository.TagFinder.All(ctx)
|
tags, err := me.repository.TagFinder.All(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
|
@ -605,7 +605,7 @@ func (me *contentDirectoryService) getTagScenes(paths []string, host string) []i
|
||||||
func (me *contentDirectoryService) getPerformers() []interface{} {
|
func (me *contentDirectoryService) getPerformers() []interface{} {
|
||||||
var objs []interface{}
|
var objs []interface{}
|
||||||
|
|
||||||
if err := txn.WithTxn(context.TODO(), me.txnManager, func(ctx context.Context) error {
|
if err := txn.WithReadTxn(context.TODO(), me.txnManager, func(ctx context.Context) error {
|
||||||
performers, err := me.repository.PerformerFinder.All(ctx)
|
performers, err := me.repository.PerformerFinder.All(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
|
@ -644,7 +644,7 @@ func (me *contentDirectoryService) getPerformerScenes(paths []string, host strin
|
||||||
func (me *contentDirectoryService) getMovies() []interface{} {
|
func (me *contentDirectoryService) getMovies() []interface{} {
|
||||||
var objs []interface{}
|
var objs []interface{}
|
||||||
|
|
||||||
if err := txn.WithTxn(context.TODO(), me.txnManager, func(ctx context.Context) error {
|
if err := txn.WithReadTxn(context.TODO(), me.txnManager, func(ctx context.Context) error {
|
||||||
movies, err := me.repository.MovieFinder.All(ctx)
|
movies, err := me.repository.MovieFinder.All(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
|
|
||||||
|
|
@ -439,7 +439,7 @@ func (me *Server) serveIcon(w http.ResponseWriter, r *http.Request) {
|
||||||
}
|
}
|
||||||
|
|
||||||
var scene *models.Scene
|
var scene *models.Scene
|
||||||
err := txn.WithTxn(r.Context(), me.txnManager, func(ctx context.Context) error {
|
err := txn.WithReadTxn(r.Context(), me.txnManager, func(ctx context.Context) error {
|
||||||
idInt, err := strconv.Atoi(sceneId)
|
idInt, err := strconv.Atoi(sceneId)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil
|
return nil
|
||||||
|
|
@ -579,7 +579,7 @@ func (me *Server) initMux(mux *http.ServeMux) {
|
||||||
mux.HandleFunc(resPath, func(w http.ResponseWriter, r *http.Request) {
|
mux.HandleFunc(resPath, func(w http.ResponseWriter, r *http.Request) {
|
||||||
sceneId := r.URL.Query().Get("scene")
|
sceneId := r.URL.Query().Get("scene")
|
||||||
var scene *models.Scene
|
var scene *models.Scene
|
||||||
err := txn.WithTxn(r.Context(), me.txnManager, func(ctx context.Context) error {
|
err := txn.WithReadTxn(r.Context(), me.txnManager, func(ctx context.Context) error {
|
||||||
sceneIdInt, err := strconv.Atoi(sceneId)
|
sceneIdInt, err := strconv.Atoi(sceneId)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil
|
return nil
|
||||||
|
|
|
||||||
|
|
@ -67,6 +67,10 @@ func (r *Repository) WithTxn(ctx context.Context, fn txn.TxnFunc) error {
|
||||||
return txn.WithTxn(ctx, r, fn)
|
return txn.WithTxn(ctx, r, fn)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (r *Repository) WithReadTxn(ctx context.Context, fn txn.TxnFunc) error {
|
||||||
|
return txn.WithReadTxn(ctx, r, fn)
|
||||||
|
}
|
||||||
|
|
||||||
func (r *Repository) WithDB(ctx context.Context, fn txn.TxnFunc) error {
|
func (r *Repository) WithDB(ctx context.Context, fn txn.TxnFunc) error {
|
||||||
return txn.WithDatabase(ctx, r, fn)
|
return txn.WithDatabase(ctx, r, fn)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -103,7 +103,7 @@ func (s *SceneServer) ServeScreenshot(scene *models.Scene, w http.ResponseWriter
|
||||||
}
|
}
|
||||||
|
|
||||||
var cover []byte
|
var cover []byte
|
||||||
readTxnErr := txn.WithTxn(r.Context(), s.TxnManager, func(ctx context.Context) error {
|
readTxnErr := txn.WithReadTxn(r.Context(), s.TxnManager, func(ctx context.Context) error {
|
||||||
cover, _ = s.SceneCoverGetter.GetCover(ctx, scene.ID)
|
cover, _ = s.SceneCoverGetter.GetCover(ctx, scene.ID)
|
||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
|
|
|
||||||
|
|
@ -73,7 +73,7 @@ func (j *autoTagJob) autoTagSpecific(ctx context.Context, progress *job.Progress
|
||||||
studioCount := len(studioIds)
|
studioCount := len(studioIds)
|
||||||
tagCount := len(tagIds)
|
tagCount := len(tagIds)
|
||||||
|
|
||||||
if err := j.txnManager.WithTxn(ctx, func(ctx context.Context) error {
|
if err := j.txnManager.WithReadTxn(ctx, func(ctx context.Context) error {
|
||||||
r := j.txnManager
|
r := j.txnManager
|
||||||
performerQuery := r.Performer
|
performerQuery := r.Performer
|
||||||
studioQuery := r.Studio
|
studioQuery := r.Studio
|
||||||
|
|
@ -497,7 +497,7 @@ func (t *autoTagFilesTask) processScenes(ctx context.Context, r Repository) erro
|
||||||
more := true
|
more := true
|
||||||
for more {
|
for more {
|
||||||
var scenes []*models.Scene
|
var scenes []*models.Scene
|
||||||
if err := t.txnManager.WithTxn(ctx, func(ctx context.Context) error {
|
if err := t.txnManager.WithReadTxn(ctx, func(ctx context.Context) error {
|
||||||
var err error
|
var err error
|
||||||
scenes, err = scene.Query(ctx, r.Scene, sceneFilter, findFilter)
|
scenes, err = scene.Query(ctx, r.Scene, sceneFilter, findFilter)
|
||||||
return err
|
return err
|
||||||
|
|
@ -554,7 +554,7 @@ func (t *autoTagFilesTask) processImages(ctx context.Context, r Repository) erro
|
||||||
more := true
|
more := true
|
||||||
for more {
|
for more {
|
||||||
var images []*models.Image
|
var images []*models.Image
|
||||||
if err := t.txnManager.WithTxn(ctx, func(ctx context.Context) error {
|
if err := t.txnManager.WithReadTxn(ctx, func(ctx context.Context) error {
|
||||||
var err error
|
var err error
|
||||||
images, err = image.Query(ctx, r.Image, imageFilter, findFilter)
|
images, err = image.Query(ctx, r.Image, imageFilter, findFilter)
|
||||||
return err
|
return err
|
||||||
|
|
@ -611,7 +611,7 @@ func (t *autoTagFilesTask) processGalleries(ctx context.Context, r Repository) e
|
||||||
more := true
|
more := true
|
||||||
for more {
|
for more {
|
||||||
var galleries []*models.Gallery
|
var galleries []*models.Gallery
|
||||||
if err := t.txnManager.WithTxn(ctx, func(ctx context.Context) error {
|
if err := t.txnManager.WithReadTxn(ctx, func(ctx context.Context) error {
|
||||||
var err error
|
var err error
|
||||||
galleries, _, err = r.Gallery.Query(ctx, galleryFilter, findFilter)
|
galleries, _, err = r.Gallery.Query(ctx, galleryFilter, findFilter)
|
||||||
return err
|
return err
|
||||||
|
|
@ -657,7 +657,7 @@ func (t *autoTagFilesTask) processGalleries(ctx context.Context, r Repository) e
|
||||||
|
|
||||||
func (t *autoTagFilesTask) process(ctx context.Context) {
|
func (t *autoTagFilesTask) process(ctx context.Context) {
|
||||||
r := t.txnManager
|
r := t.txnManager
|
||||||
if err := r.WithTxn(ctx, func(ctx context.Context) error {
|
if err := r.WithReadTxn(ctx, func(ctx context.Context) error {
|
||||||
total, err := t.getCount(ctx, t.txnManager)
|
total, err := t.getCount(ctx, t.txnManager)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
|
|
||||||
|
|
@ -109,7 +109,7 @@ func (j *GenerateJob) Execute(ctx context.Context, progress *job.Progress) {
|
||||||
Overwrite: j.overwrite,
|
Overwrite: j.overwrite,
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := j.txnManager.WithTxn(ctx, func(ctx context.Context) error {
|
if err := j.txnManager.WithReadTxn(ctx, func(ctx context.Context) error {
|
||||||
qb := j.txnManager.Scene
|
qb := j.txnManager.Scene
|
||||||
if len(j.input.SceneIDs) == 0 && len(j.input.MarkerIDs) == 0 {
|
if len(j.input.SceneIDs) == 0 && len(j.input.MarkerIDs) == 0 {
|
||||||
totals = j.queueTasks(ctx, g, queue)
|
totals = j.queueTasks(ctx, g, queue)
|
||||||
|
|
@ -137,7 +137,7 @@ func (j *GenerateJob) Execute(ctx context.Context, progress *job.Progress) {
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}); err != nil {
|
}); err != nil && ctx.Err() == nil {
|
||||||
logger.Error(err.Error())
|
logger.Error(err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -46,10 +46,9 @@ func (t *GenerateInteractiveHeatmapSpeedTask) Start(ctx context.Context) {
|
||||||
primaryFile.InteractiveSpeed = &median
|
primaryFile.InteractiveSpeed = &median
|
||||||
qb := t.TxnManager.File
|
qb := t.TxnManager.File
|
||||||
return qb.Update(ctx, primaryFile)
|
return qb.Update(ctx, primaryFile)
|
||||||
}); err != nil {
|
}); err != nil && ctx.Err() == nil {
|
||||||
logger.Error(err.Error())
|
logger.Error(err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *GenerateInteractiveHeatmapSpeedTask) shouldGenerate() bool {
|
func (t *GenerateInteractiveHeatmapSpeedTask) shouldGenerate() bool {
|
||||||
|
|
|
||||||
|
|
@ -42,7 +42,7 @@ func (t *GenerateMarkersTask) Start(ctx context.Context) {
|
||||||
|
|
||||||
if t.Marker != nil {
|
if t.Marker != nil {
|
||||||
var scene *models.Scene
|
var scene *models.Scene
|
||||||
if err := t.TxnManager.WithTxn(ctx, func(ctx context.Context) error {
|
if err := t.TxnManager.WithReadTxn(ctx, func(ctx context.Context) error {
|
||||||
var err error
|
var err error
|
||||||
scene, err = t.TxnManager.Scene.Find(ctx, int(t.Marker.SceneID.Int64))
|
scene, err = t.TxnManager.Scene.Find(ctx, int(t.Marker.SceneID.Int64))
|
||||||
if err == nil && scene != nil {
|
if err == nil && scene != nil {
|
||||||
|
|
@ -73,7 +73,7 @@ func (t *GenerateMarkersTask) Start(ctx context.Context) {
|
||||||
|
|
||||||
func (t *GenerateMarkersTask) generateSceneMarkers(ctx context.Context) {
|
func (t *GenerateMarkersTask) generateSceneMarkers(ctx context.Context) {
|
||||||
var sceneMarkers []*models.SceneMarker
|
var sceneMarkers []*models.SceneMarker
|
||||||
if err := t.TxnManager.WithTxn(ctx, func(ctx context.Context) error {
|
if err := t.TxnManager.WithReadTxn(ctx, func(ctx context.Context) error {
|
||||||
var err error
|
var err error
|
||||||
sceneMarkers, err = t.TxnManager.SceneMarker.FindBySceneID(ctx, t.Scene.ID)
|
sceneMarkers, err = t.TxnManager.SceneMarker.FindBySceneID(ctx, t.Scene.ID)
|
||||||
return err
|
return err
|
||||||
|
|
|
||||||
|
|
@ -44,8 +44,8 @@ func (t *GeneratePhashTask) Start(ctx context.Context) {
|
||||||
})
|
})
|
||||||
|
|
||||||
return qb.Update(ctx, t.File)
|
return qb.Update(ctx, t.File)
|
||||||
}); err != nil {
|
}); err != nil && ctx.Err() == nil {
|
||||||
logger.Error(err.Error())
|
logger.Errorf("Error setting phash: %v", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -91,7 +91,7 @@ func (t *GenerateScreenshotTask) Start(ctx context.Context) {
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}); err != nil {
|
}); err != nil && ctx.Err() == nil {
|
||||||
logger.Error(err.Error())
|
logger.Error(err.Error())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -50,7 +50,7 @@ func (t *StashBoxPerformerTagTask) stashBoxPerformerTag(ctx context.Context) {
|
||||||
|
|
||||||
if t.refresh {
|
if t.refresh {
|
||||||
var performerID string
|
var performerID string
|
||||||
txnErr := txn.WithTxn(ctx, instance.Repository, func(ctx context.Context) error {
|
txnErr := txn.WithReadTxn(ctx, instance.Repository, func(ctx context.Context) error {
|
||||||
stashids, _ := instance.Repository.Performer.GetStashIDs(ctx, t.performer.ID)
|
stashids, _ := instance.Repository.Performer.GetStashIDs(ctx, t.performer.ID)
|
||||||
for _, id := range stashids {
|
for _, id := range stashids {
|
||||||
if id.Endpoint == t.box.Endpoint {
|
if id.Endpoint == t.box.Endpoint {
|
||||||
|
|
|
||||||
|
|
@ -109,7 +109,7 @@ func (j *cleanJob) execute(ctx context.Context) error {
|
||||||
folderCount int
|
folderCount int
|
||||||
)
|
)
|
||||||
|
|
||||||
if err := txn.WithTxn(ctx, j.Repository, func(ctx context.Context) error {
|
if err := txn.WithReadTxn(ctx, j.Repository, func(ctx context.Context) error {
|
||||||
var err error
|
var err error
|
||||||
fileCount, err = j.Repository.CountAllInPaths(ctx, j.options.Paths)
|
fileCount, err = j.Repository.CountAllInPaths(ctx, j.options.Paths)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -169,7 +169,7 @@ func (j *cleanJob) assessFiles(ctx context.Context, toDelete *deleteSet) error {
|
||||||
progress := j.progress
|
progress := j.progress
|
||||||
|
|
||||||
more := true
|
more := true
|
||||||
if err := txn.WithTxn(ctx, j.Repository, func(ctx context.Context) error {
|
if err := txn.WithReadTxn(ctx, j.Repository, func(ctx context.Context) error {
|
||||||
for more {
|
for more {
|
||||||
if job.IsCancelled(ctx) {
|
if job.IsCancelled(ctx) {
|
||||||
return nil
|
return nil
|
||||||
|
|
@ -253,7 +253,7 @@ func (j *cleanJob) assessFolders(ctx context.Context, toDelete *deleteSet) error
|
||||||
progress := j.progress
|
progress := j.progress
|
||||||
|
|
||||||
more := true
|
more := true
|
||||||
if err := txn.WithTxn(ctx, j.Repository, func(ctx context.Context) error {
|
if err := txn.WithReadTxn(ctx, j.Repository, func(ctx context.Context) error {
|
||||||
for more {
|
for more {
|
||||||
if job.IsCancelled(ctx) {
|
if job.IsCancelled(ctx) {
|
||||||
return nil
|
return nil
|
||||||
|
|
|
||||||
|
|
@ -85,7 +85,6 @@ type scanJob struct {
|
||||||
|
|
||||||
startTime time.Time
|
startTime time.Time
|
||||||
fileQueue chan scanFile
|
fileQueue chan scanFile
|
||||||
dbQueue chan func(ctx context.Context) error
|
|
||||||
retryList []scanFile
|
retryList []scanFile
|
||||||
retrying bool
|
retrying bool
|
||||||
folderPathToID sync.Map
|
folderPathToID sync.Map
|
||||||
|
|
@ -148,9 +147,11 @@ func (s *scanJob) execute(ctx context.Context) {
|
||||||
s.startTime = time.Now()
|
s.startTime = time.Now()
|
||||||
|
|
||||||
s.fileQueue = make(chan scanFile, scanQueueSize)
|
s.fileQueue = make(chan scanFile, scanQueueSize)
|
||||||
s.dbQueue = make(chan func(ctx context.Context) error, scanQueueSize)
|
var wg sync.WaitGroup
|
||||||
|
wg.Add(1)
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
|
defer wg.Done()
|
||||||
if err := s.queueFiles(ctx, paths); err != nil {
|
if err := s.queueFiles(ctx, paths); err != nil {
|
||||||
if errors.Is(err, context.Canceled) {
|
if errors.Is(err, context.Canceled) {
|
||||||
return
|
return
|
||||||
|
|
@ -163,6 +164,8 @@ func (s *scanJob) execute(ctx context.Context) {
|
||||||
logger.Infof("Finished adding files to queue. %d files queued", s.count)
|
logger.Infof("Finished adding files to queue. %d files queued", s.count)
|
||||||
}()
|
}()
|
||||||
|
|
||||||
|
defer wg.Wait()
|
||||||
|
|
||||||
if err := s.processQueue(ctx); err != nil {
|
if err := s.processQueue(ctx); err != nil {
|
||||||
if errors.Is(err, context.Canceled) {
|
if errors.Is(err, context.Canceled) {
|
||||||
return
|
return
|
||||||
|
|
@ -329,6 +332,9 @@ func (s *scanJob) processQueue(ctx context.Context) error {
|
||||||
|
|
||||||
wg := sizedwaitgroup.New(parallelTasks)
|
wg := sizedwaitgroup.New(parallelTasks)
|
||||||
|
|
||||||
|
if err := func() error {
|
||||||
|
defer wg.Wait()
|
||||||
|
|
||||||
for f := range s.fileQueue {
|
for f := range s.fileQueue {
|
||||||
if err := ctx.Err(); err != nil {
|
if err := ctx.Err(); err != nil {
|
||||||
return err
|
return err
|
||||||
|
|
@ -342,8 +348,16 @@ func (s *scanJob) processQueue(ctx context.Context) error {
|
||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
|
|
||||||
wg.Wait()
|
return nil
|
||||||
|
}(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
s.retrying = true
|
s.retrying = true
|
||||||
|
|
||||||
|
if err := func() error {
|
||||||
|
defer wg.Wait()
|
||||||
|
|
||||||
for _, f := range s.retryList {
|
for _, f := range s.retryList {
|
||||||
if err := ctx.Err(); err != nil {
|
if err := ctx.Err(); err != nil {
|
||||||
return err
|
return err
|
||||||
|
|
@ -357,9 +371,10 @@ func (s *scanJob) processQueue(ctx context.Context) error {
|
||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
|
|
||||||
wg.Wait()
|
return nil
|
||||||
|
}(); err != nil {
|
||||||
close(s.dbQueue)
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -73,26 +73,6 @@ func (h *ScanHandler) validate() error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *ScanHandler) logInfo(ctx context.Context, format string, args ...interface{}) {
|
|
||||||
// log at the end so that if anything fails above due to a locked database
|
|
||||||
// error and the transaction must be retried, then we shouldn't get multiple
|
|
||||||
// logs of the same thing.
|
|
||||||
txn.AddPostCompleteHook(ctx, func(ctx context.Context) error {
|
|
||||||
logger.Infof(format, args...)
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h *ScanHandler) logError(ctx context.Context, format string, args ...interface{}) {
|
|
||||||
// log at the end so that if anything fails above due to a locked database
|
|
||||||
// error and the transaction must be retried, then we shouldn't get multiple
|
|
||||||
// logs of the same thing.
|
|
||||||
txn.AddPostCompleteHook(ctx, func(ctx context.Context) error {
|
|
||||||
logger.Errorf(format, args...)
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h *ScanHandler) Handle(ctx context.Context, f file.File, oldFile file.File) error {
|
func (h *ScanHandler) Handle(ctx context.Context, f file.File, oldFile file.File) error {
|
||||||
if err := h.validate(); err != nil {
|
if err := h.validate(); err != nil {
|
||||||
return err
|
return err
|
||||||
|
|
@ -132,7 +112,7 @@ func (h *ScanHandler) Handle(ctx context.Context, f file.File, oldFile file.File
|
||||||
GalleryIDs: models.NewRelatedIDs([]int{}),
|
GalleryIDs: models.NewRelatedIDs([]int{}),
|
||||||
}
|
}
|
||||||
|
|
||||||
h.logInfo(ctx, "%s doesn't exist. Creating new image...", f.Base().Path)
|
logger.Infof("%s doesn't exist. Creating new image...", f.Base().Path)
|
||||||
|
|
||||||
if _, err := h.associateGallery(ctx, newImage, imageFile); err != nil {
|
if _, err := h.associateGallery(ctx, newImage, imageFile); err != nil {
|
||||||
return err
|
return err
|
||||||
|
|
@ -162,12 +142,17 @@ func (h *ScanHandler) Handle(ctx context.Context, f file.File, oldFile file.File
|
||||||
}
|
}
|
||||||
|
|
||||||
if h.ScanConfig.IsGenerateThumbnails() {
|
if h.ScanConfig.IsGenerateThumbnails() {
|
||||||
|
// do this after the commit so that the transaction isn't held up
|
||||||
|
txn.AddPostCommitHook(ctx, func(ctx context.Context) error {
|
||||||
for _, s := range existing {
|
for _, s := range existing {
|
||||||
if err := h.ThumbnailGenerator.GenerateThumbnail(ctx, s, imageFile); err != nil {
|
if err := h.ThumbnailGenerator.GenerateThumbnail(ctx, s, imageFile); err != nil {
|
||||||
// just log if cover generation fails. We can try again on rescan
|
// just log if cover generation fails. We can try again on rescan
|
||||||
h.logError(ctx, "Error generating thumbnail for %s: %v", imageFile.Path, err)
|
logger.Errorf("Error generating thumbnail for %s: %v", imageFile.Path, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
|
@ -202,7 +187,7 @@ func (h *ScanHandler) associateExisting(ctx context.Context, existing []*models.
|
||||||
}
|
}
|
||||||
|
|
||||||
if !found {
|
if !found {
|
||||||
h.logInfo(ctx, "Adding %s to image %s", f.Path, i.DisplayName())
|
logger.Infof("Adding %s to image %s", f.Path, i.DisplayName())
|
||||||
|
|
||||||
if err := h.CreatorUpdater.AddFileID(ctx, i.ID, f.ID); err != nil {
|
if err := h.CreatorUpdater.AddFileID(ctx, i.ID, f.ID); err != nil {
|
||||||
return fmt.Errorf("adding file to image: %w", err)
|
return fmt.Errorf("adding file to image: %w", err)
|
||||||
|
|
@ -249,7 +234,7 @@ func (h *ScanHandler) getOrCreateFolderBasedGallery(ctx context.Context, f file.
|
||||||
UpdatedAt: now,
|
UpdatedAt: now,
|
||||||
}
|
}
|
||||||
|
|
||||||
h.logInfo(ctx, "Creating folder-based gallery for %s", filepath.Dir(f.Base().Path))
|
logger.Infof("Creating folder-based gallery for %s", filepath.Dir(f.Base().Path))
|
||||||
|
|
||||||
if err := h.GalleryFinder.Create(ctx, newGallery, nil); err != nil {
|
if err := h.GalleryFinder.Create(ctx, newGallery, nil); err != nil {
|
||||||
return nil, fmt.Errorf("creating folder based gallery: %w", err)
|
return nil, fmt.Errorf("creating folder based gallery: %w", err)
|
||||||
|
|
@ -273,7 +258,7 @@ func (h *ScanHandler) associateFolderImages(ctx context.Context, g *models.Galle
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, ii := range i {
|
for _, ii := range i {
|
||||||
h.logInfo(ctx, "Adding %s to gallery %s", ii.Path, g.Path)
|
logger.Infof("Adding %s to gallery %s", ii.Path, g.Path)
|
||||||
|
|
||||||
if _, err := h.CreatorUpdater.UpdatePartial(ctx, ii.ID, models.ImagePartial{
|
if _, err := h.CreatorUpdater.UpdatePartial(ctx, ii.ID, models.ImagePartial{
|
||||||
GalleryIDs: &models.UpdateIDs{
|
GalleryIDs: &models.UpdateIDs{
|
||||||
|
|
@ -307,7 +292,7 @@ func (h *ScanHandler) getOrCreateZipBasedGallery(ctx context.Context, zipFile fi
|
||||||
UpdatedAt: now,
|
UpdatedAt: now,
|
||||||
}
|
}
|
||||||
|
|
||||||
h.logInfo(ctx, "%s doesn't exist. Creating new gallery...", zipFile.Base().Path)
|
logger.Infof("%s doesn't exist. Creating new gallery...", zipFile.Base().Path)
|
||||||
|
|
||||||
if err := h.GalleryFinder.Create(ctx, newGallery, []file.ID{zipFile.Base().ID}); err != nil {
|
if err := h.GalleryFinder.Create(ctx, newGallery, []file.ID{zipFile.Base().ID}); err != nil {
|
||||||
return nil, fmt.Errorf("creating zip-based gallery: %w", err)
|
return nil, fmt.Errorf("creating zip-based gallery: %w", err)
|
||||||
|
|
@ -345,7 +330,7 @@ func (h *ScanHandler) associateGallery(ctx context.Context, newImage *models.Ima
|
||||||
if g != nil && !intslice.IntInclude(newImage.GalleryIDs.List(), g.ID) {
|
if g != nil && !intslice.IntInclude(newImage.GalleryIDs.List(), g.ID) {
|
||||||
ret = true
|
ret = true
|
||||||
newImage.GalleryIDs.Add(g.ID)
|
newImage.GalleryIDs.Add(g.ID)
|
||||||
h.logInfo(ctx, "Adding %s to gallery %s", f.Base().Path, g.Path)
|
logger.Infof("Adding %s to gallery %s", f.Base().Path, g.Path)
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret, nil
|
return ret, nil
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,7 @@ import (
|
||||||
|
|
||||||
type TxnManager struct{}
|
type TxnManager struct{}
|
||||||
|
|
||||||
func (*TxnManager) Begin(ctx context.Context) (context.Context, error) {
|
func (*TxnManager) Begin(ctx context.Context, exclusive bool) (context.Context, error) {
|
||||||
return ctx, nil
|
return ctx, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -25,6 +25,9 @@ func (*TxnManager) Rollback(ctx context.Context) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (*TxnManager) Complete(ctx context.Context) {
|
||||||
|
}
|
||||||
|
|
||||||
func (*TxnManager) AddPostCommitHook(ctx context.Context, hook txn.TxnFunc) {
|
func (*TxnManager) AddPostCommitHook(ctx context.Context, hook txn.TxnFunc) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,6 @@
|
||||||
package models
|
package models
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
|
||||||
|
|
||||||
"github.com/stashapp/stash/pkg/file"
|
"github.com/stashapp/stash/pkg/file"
|
||||||
"github.com/stashapp/stash/pkg/txn"
|
"github.com/stashapp/stash/pkg/txn"
|
||||||
)
|
)
|
||||||
|
|
@ -29,7 +27,3 @@ type Repository struct {
|
||||||
Tag TagReaderWriter
|
Tag TagReaderWriter
|
||||||
SavedFilter SavedFilterReaderWriter
|
SavedFilter SavedFilterReaderWriter
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *Repository) WithTxn(ctx context.Context, fn txn.TxnFunc) error {
|
|
||||||
return txn.WithTxn(ctx, r, fn)
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,7 @@ import (
|
||||||
"github.com/stashapp/stash/pkg/models"
|
"github.com/stashapp/stash/pkg/models"
|
||||||
"github.com/stashapp/stash/pkg/models/paths"
|
"github.com/stashapp/stash/pkg/models/paths"
|
||||||
"github.com/stashapp/stash/pkg/plugin"
|
"github.com/stashapp/stash/pkg/plugin"
|
||||||
|
"github.com/stashapp/stash/pkg/txn"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
|
@ -119,6 +120,8 @@ func (h *ScanHandler) Handle(ctx context.Context, f file.File, oldFile file.File
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// do this after the commit so that cover generation doesn't hold up the transaction
|
||||||
|
txn.AddPostCommitHook(ctx, func(ctx context.Context) error {
|
||||||
for _, s := range existing {
|
for _, s := range existing {
|
||||||
if err := h.CoverGenerator.GenerateCover(ctx, s, videoFile); err != nil {
|
if err := h.CoverGenerator.GenerateCover(ctx, s, videoFile); err != nil {
|
||||||
// just log if cover generation fails. We can try again on rescan
|
// just log if cover generation fails. We can try again on rescan
|
||||||
|
|
@ -131,6 +134,9 @@ func (h *ScanHandler) Handle(ctx context.Context, f file.File, oldFile file.File
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -95,7 +95,7 @@ func (s autotagScraper) viaScene(ctx context.Context, _client *http.Client, scen
|
||||||
const trimExt = false
|
const trimExt = false
|
||||||
|
|
||||||
// populate performers, studio and tags based on scene path
|
// populate performers, studio and tags based on scene path
|
||||||
if err := txn.WithTxn(ctx, s.txnManager, func(ctx context.Context) error {
|
if err := txn.WithReadTxn(ctx, s.txnManager, func(ctx context.Context) error {
|
||||||
path := scene.Path
|
path := scene.Path
|
||||||
if path == "" {
|
if path == "" {
|
||||||
return nil
|
return nil
|
||||||
|
|
@ -144,7 +144,7 @@ func (s autotagScraper) viaGallery(ctx context.Context, _client *http.Client, ga
|
||||||
var ret *ScrapedGallery
|
var ret *ScrapedGallery
|
||||||
|
|
||||||
// populate performers, studio and tags based on scene path
|
// populate performers, studio and tags based on scene path
|
||||||
if err := txn.WithTxn(ctx, s.txnManager, func(ctx context.Context) error {
|
if err := txn.WithReadTxn(ctx, s.txnManager, func(ctx context.Context) error {
|
||||||
path := gallery.Path
|
path := gallery.Path
|
||||||
performers, err := autotagMatchPerformers(ctx, path, s.performerReader, trimExt)
|
performers, err := autotagMatchPerformers(ctx, path, s.performerReader, trimExt)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
||||||
|
|
@ -350,7 +350,7 @@ func (c Cache) ScrapeID(ctx context.Context, scraperID string, id int, ty Scrape
|
||||||
|
|
||||||
func (c Cache) getScene(ctx context.Context, sceneID int) (*models.Scene, error) {
|
func (c Cache) getScene(ctx context.Context, sceneID int) (*models.Scene, error) {
|
||||||
var ret *models.Scene
|
var ret *models.Scene
|
||||||
if err := txn.WithTxn(ctx, c.txnManager, func(ctx context.Context) error {
|
if err := txn.WithReadTxn(ctx, c.txnManager, func(ctx context.Context) error {
|
||||||
var err error
|
var err error
|
||||||
ret, err = c.repository.SceneFinder.Find(ctx, sceneID)
|
ret, err = c.repository.SceneFinder.Find(ctx, sceneID)
|
||||||
return err
|
return err
|
||||||
|
|
@ -362,7 +362,7 @@ func (c Cache) getScene(ctx context.Context, sceneID int) (*models.Scene, error)
|
||||||
|
|
||||||
func (c Cache) getGallery(ctx context.Context, galleryID int) (*models.Gallery, error) {
|
func (c Cache) getGallery(ctx context.Context, galleryID int) (*models.Gallery, error) {
|
||||||
var ret *models.Gallery
|
var ret *models.Gallery
|
||||||
if err := txn.WithTxn(ctx, c.txnManager, func(ctx context.Context) error {
|
if err := txn.WithReadTxn(ctx, c.txnManager, func(ctx context.Context) error {
|
||||||
var err error
|
var err error
|
||||||
ret, err = c.repository.GalleryFinder.Find(ctx, galleryID)
|
ret, err = c.repository.GalleryFinder.Find(ctx, galleryID)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -47,7 +47,7 @@ func (c Cache) postScrape(ctx context.Context, content ScrapedContent) (ScrapedC
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c Cache) postScrapePerformer(ctx context.Context, p models.ScrapedPerformer) (ScrapedContent, error) {
|
func (c Cache) postScrapePerformer(ctx context.Context, p models.ScrapedPerformer) (ScrapedContent, error) {
|
||||||
if err := txn.WithTxn(ctx, c.txnManager, func(ctx context.Context) error {
|
if err := txn.WithReadTxn(ctx, c.txnManager, func(ctx context.Context) error {
|
||||||
tqb := c.repository.TagFinder
|
tqb := c.repository.TagFinder
|
||||||
|
|
||||||
tags, err := postProcessTags(ctx, tqb, p.Tags)
|
tags, err := postProcessTags(ctx, tqb, p.Tags)
|
||||||
|
|
@ -73,7 +73,7 @@ func (c Cache) postScrapePerformer(ctx context.Context, p models.ScrapedPerforme
|
||||||
|
|
||||||
func (c Cache) postScrapeMovie(ctx context.Context, m models.ScrapedMovie) (ScrapedContent, error) {
|
func (c Cache) postScrapeMovie(ctx context.Context, m models.ScrapedMovie) (ScrapedContent, error) {
|
||||||
if m.Studio != nil {
|
if m.Studio != nil {
|
||||||
if err := txn.WithTxn(ctx, c.txnManager, func(ctx context.Context) error {
|
if err := txn.WithReadTxn(ctx, c.txnManager, func(ctx context.Context) error {
|
||||||
return match.ScrapedStudio(ctx, c.repository.StudioFinder, m.Studio, nil)
|
return match.ScrapedStudio(ctx, c.repository.StudioFinder, m.Studio, nil)
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|
@ -106,7 +106,7 @@ func (c Cache) postScrapeScenePerformer(ctx context.Context, p models.ScrapedPer
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c Cache) postScrapeScene(ctx context.Context, scene ScrapedScene) (ScrapedContent, error) {
|
func (c Cache) postScrapeScene(ctx context.Context, scene ScrapedScene) (ScrapedContent, error) {
|
||||||
if err := txn.WithTxn(ctx, c.txnManager, func(ctx context.Context) error {
|
if err := txn.WithReadTxn(ctx, c.txnManager, func(ctx context.Context) error {
|
||||||
pqb := c.repository.PerformerFinder
|
pqb := c.repository.PerformerFinder
|
||||||
mqb := c.repository.MovieFinder
|
mqb := c.repository.MovieFinder
|
||||||
tqb := c.repository.TagFinder
|
tqb := c.repository.TagFinder
|
||||||
|
|
@ -160,7 +160,7 @@ func (c Cache) postScrapeScene(ctx context.Context, scene ScrapedScene) (Scraped
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c Cache) postScrapeGallery(ctx context.Context, g ScrapedGallery) (ScrapedContent, error) {
|
func (c Cache) postScrapeGallery(ctx context.Context, g ScrapedGallery) (ScrapedContent, error) {
|
||||||
if err := txn.WithTxn(ctx, c.txnManager, func(ctx context.Context) error {
|
if err := txn.WithReadTxn(ctx, c.txnManager, func(ctx context.Context) error {
|
||||||
pqb := c.repository.PerformerFinder
|
pqb := c.repository.PerformerFinder
|
||||||
tqb := c.repository.TagFinder
|
tqb := c.repository.TagFinder
|
||||||
sqb := c.repository.StudioFinder
|
sqb := c.repository.StudioFinder
|
||||||
|
|
|
||||||
|
|
@ -131,7 +131,7 @@ func (c Client) FindStashBoxSceneByFingerprints(ctx context.Context, sceneID int
|
||||||
func (c Client) FindStashBoxScenesByFingerprints(ctx context.Context, ids []int) ([][]*scraper.ScrapedScene, error) {
|
func (c Client) FindStashBoxScenesByFingerprints(ctx context.Context, ids []int) ([][]*scraper.ScrapedScene, error) {
|
||||||
var fingerprints [][]*graphql.FingerprintQueryInput
|
var fingerprints [][]*graphql.FingerprintQueryInput
|
||||||
|
|
||||||
if err := txn.WithTxn(ctx, c.txnManager, func(ctx context.Context) error {
|
if err := txn.WithReadTxn(ctx, c.txnManager, func(ctx context.Context) error {
|
||||||
qb := c.repository.Scene
|
qb := c.repository.Scene
|
||||||
|
|
||||||
for _, sceneID := range ids {
|
for _, sceneID := range ids {
|
||||||
|
|
@ -245,7 +245,7 @@ func (c Client) SubmitStashBoxFingerprints(ctx context.Context, sceneIDs []strin
|
||||||
|
|
||||||
var fingerprints []graphql.FingerprintSubmission
|
var fingerprints []graphql.FingerprintSubmission
|
||||||
|
|
||||||
if err := txn.WithTxn(ctx, c.txnManager, func(ctx context.Context) error {
|
if err := txn.WithReadTxn(ctx, c.txnManager, func(ctx context.Context) error {
|
||||||
qb := c.repository.Scene
|
qb := c.repository.Scene
|
||||||
|
|
||||||
for _, sceneID := range ids {
|
for _, sceneID := range ids {
|
||||||
|
|
@ -386,7 +386,7 @@ func (c Client) FindStashBoxPerformersByNames(ctx context.Context, performerIDs
|
||||||
|
|
||||||
var performers []*models.Performer
|
var performers []*models.Performer
|
||||||
|
|
||||||
if err := txn.WithTxn(ctx, c.txnManager, func(ctx context.Context) error {
|
if err := txn.WithReadTxn(ctx, c.txnManager, func(ctx context.Context) error {
|
||||||
qb := c.repository.Performer
|
qb := c.repository.Performer
|
||||||
|
|
||||||
for _, performerID := range ids {
|
for _, performerID := range ids {
|
||||||
|
|
@ -420,7 +420,7 @@ func (c Client) FindStashBoxPerformersByPerformerNames(ctx context.Context, perf
|
||||||
|
|
||||||
var performers []*models.Performer
|
var performers []*models.Performer
|
||||||
|
|
||||||
if err := txn.WithTxn(ctx, c.txnManager, func(ctx context.Context) error {
|
if err := txn.WithReadTxn(ctx, c.txnManager, func(ctx context.Context) error {
|
||||||
qb := c.repository.Performer
|
qb := c.repository.Performer
|
||||||
|
|
||||||
for _, performerID := range ids {
|
for _, performerID := range ids {
|
||||||
|
|
@ -705,7 +705,7 @@ func (c Client) sceneFragmentToScrapedScene(ctx context.Context, s *graphql.Scen
|
||||||
ss.Image = getFirstImage(ctx, c.getHTTPClient(), s.Images)
|
ss.Image = getFirstImage(ctx, c.getHTTPClient(), s.Images)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := txn.WithTxn(ctx, c.txnManager, func(ctx context.Context) error {
|
if err := txn.WithReadTxn(ctx, c.txnManager, func(ctx context.Context) error {
|
||||||
pqb := c.repository.Performer
|
pqb := c.repository.Performer
|
||||||
tqb := c.repository.Tag
|
tqb := c.repository.Tag
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,6 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"sync"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/fvbommel/sortorder"
|
"github.com/fvbommel/sortorder"
|
||||||
|
|
@ -73,7 +72,7 @@ type Database struct {
|
||||||
|
|
||||||
schemaVersion uint
|
schemaVersion uint
|
||||||
|
|
||||||
writeMu sync.Mutex
|
lockChan chan struct{}
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewDatabase() *Database {
|
func NewDatabase() *Database {
|
||||||
|
|
@ -87,6 +86,7 @@ func NewDatabase() *Database {
|
||||||
Image: NewImageStore(fileStore),
|
Image: NewImageStore(fileStore),
|
||||||
Gallery: NewGalleryStore(fileStore, folderStore),
|
Gallery: NewGalleryStore(fileStore, folderStore),
|
||||||
Performer: NewPerformerStore(),
|
Performer: NewPerformerStore(),
|
||||||
|
lockChan: make(chan struct{}, 1),
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret
|
return ret
|
||||||
|
|
@ -106,8 +106,8 @@ func (db *Database) Ready() error {
|
||||||
// necessary migrations must be run separately using RunMigrations.
|
// necessary migrations must be run separately using RunMigrations.
|
||||||
// Returns true if the database is new.
|
// Returns true if the database is new.
|
||||||
func (db *Database) Open(dbPath string) error {
|
func (db *Database) Open(dbPath string) error {
|
||||||
db.writeMu.Lock()
|
db.lockNoCtx()
|
||||||
defer db.writeMu.Unlock()
|
defer db.unlock()
|
||||||
|
|
||||||
db.dbPath = dbPath
|
db.dbPath = dbPath
|
||||||
|
|
||||||
|
|
@ -152,9 +152,36 @@ func (db *Database) Open(dbPath string) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// lock locks the database for writing.
|
||||||
|
// This method will block until the lock is acquired of the context is cancelled.
|
||||||
|
func (db *Database) lock(ctx context.Context) error {
|
||||||
|
select {
|
||||||
|
case <-ctx.Done():
|
||||||
|
return ctx.Err()
|
||||||
|
case db.lockChan <- struct{}{}:
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// lock locks the database for writing. This method will block until the lock is acquired.
|
||||||
|
func (db *Database) lockNoCtx() {
|
||||||
|
db.lockChan <- struct{}{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// unlock unlocks the database
|
||||||
|
func (db *Database) unlock() {
|
||||||
|
// will block the caller if the lock is not held, so check first
|
||||||
|
select {
|
||||||
|
case <-db.lockChan:
|
||||||
|
return
|
||||||
|
default:
|
||||||
|
panic("database is not locked")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (db *Database) Close() error {
|
func (db *Database) Close() error {
|
||||||
db.writeMu.Lock()
|
db.lockNoCtx()
|
||||||
defer db.writeMu.Unlock()
|
defer db.unlock()
|
||||||
|
|
||||||
if db.db != nil {
|
if db.db != nil {
|
||||||
if err := db.db.Close(); err != nil {
|
if err := db.db.Close(); err != nil {
|
||||||
|
|
|
||||||
|
|
@ -929,7 +929,6 @@ func Test_imageQueryBuilder_Destroy(t *testing.T) {
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
runWithRollbackTxn(t, tt.name, func(t *testing.T, ctx context.Context) {
|
runWithRollbackTxn(t, tt.name, func(t *testing.T, ctx context.Context) {
|
||||||
assert := assert.New(t)
|
assert := assert.New(t)
|
||||||
withRollbackTxn(func(ctx context.Context) error {
|
|
||||||
if err := qb.Destroy(ctx, tt.id); (err != nil) != tt.wantErr {
|
if err := qb.Destroy(ctx, tt.id); (err != nil) != tt.wantErr {
|
||||||
t.Errorf("imageQueryBuilder.Destroy() error = %v, wantErr %v", err, tt.wantErr)
|
t.Errorf("imageQueryBuilder.Destroy() error = %v, wantErr %v", err, tt.wantErr)
|
||||||
}
|
}
|
||||||
|
|
@ -939,8 +938,6 @@ func Test_imageQueryBuilder_Destroy(t *testing.T) {
|
||||||
|
|
||||||
assert.NotNil(err)
|
assert.NotNil(err)
|
||||||
assert.Nil(i)
|
assert.Nil(i)
|
||||||
return nil
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1398,7 +1398,6 @@ func Test_sceneQueryBuilder_Destroy(t *testing.T) {
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
runWithRollbackTxn(t, tt.name, func(t *testing.T, ctx context.Context) {
|
runWithRollbackTxn(t, tt.name, func(t *testing.T, ctx context.Context) {
|
||||||
assert := assert.New(t)
|
assert := assert.New(t)
|
||||||
withRollbackTxn(func(ctx context.Context) error {
|
|
||||||
if err := qb.Destroy(ctx, tt.id); (err != nil) != tt.wantErr {
|
if err := qb.Destroy(ctx, tt.id); (err != nil) != tt.wantErr {
|
||||||
t.Errorf("sceneQueryBuilder.Destroy() error = %v, wantErr %v", err, tt.wantErr)
|
t.Errorf("sceneQueryBuilder.Destroy() error = %v, wantErr %v", err, tt.wantErr)
|
||||||
}
|
}
|
||||||
|
|
@ -1408,8 +1407,6 @@ func Test_sceneQueryBuilder_Destroy(t *testing.T) {
|
||||||
|
|
||||||
assert.NotNil(err)
|
assert.NotNil(err)
|
||||||
assert.Nil(i)
|
assert.Nil(i)
|
||||||
return nil
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1477,26 +1474,23 @@ func Test_sceneQueryBuilder_Find(t *testing.T) {
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
runWithRollbackTxn(t, tt.name, func(t *testing.T, ctx context.Context) {
|
runWithRollbackTxn(t, tt.name, func(t *testing.T, ctx context.Context) {
|
||||||
assert := assert.New(t)
|
assert := assert.New(t)
|
||||||
withTxn(func(ctx context.Context) error {
|
|
||||||
got, err := qb.Find(ctx, tt.id)
|
got, err := qb.Find(ctx, tt.id)
|
||||||
if (err != nil) != tt.wantErr {
|
if (err != nil) != tt.wantErr {
|
||||||
t.Errorf("sceneQueryBuilder.Find() error = %v, wantErr %v", err, tt.wantErr)
|
t.Errorf("sceneQueryBuilder.Find() error = %v, wantErr %v", err, tt.wantErr)
|
||||||
return nil
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if got != nil {
|
if got != nil {
|
||||||
// load relationships
|
// load relationships
|
||||||
if err := loadSceneRelationships(ctx, *tt.want, got); err != nil {
|
if err := loadSceneRelationships(ctx, *tt.want, got); err != nil {
|
||||||
t.Errorf("loadSceneRelationships() error = %v", err)
|
t.Errorf("loadSceneRelationships() error = %v", err)
|
||||||
return nil
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
clearSceneFileIDs(got)
|
clearSceneFileIDs(got)
|
||||||
}
|
}
|
||||||
|
|
||||||
assert.Equal(tt.want, got)
|
assert.Equal(tt.want, got)
|
||||||
return nil
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1620,23 +1614,19 @@ func Test_sceneQueryBuilder_FindByChecksum(t *testing.T) {
|
||||||
|
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
runWithRollbackTxn(t, tt.name, func(t *testing.T, ctx context.Context) {
|
runWithRollbackTxn(t, tt.name, func(t *testing.T, ctx context.Context) {
|
||||||
withTxn(func(ctx context.Context) error {
|
|
||||||
assert := assert.New(t)
|
assert := assert.New(t)
|
||||||
got, err := qb.FindByChecksum(ctx, tt.checksum)
|
got, err := qb.FindByChecksum(ctx, tt.checksum)
|
||||||
if (err != nil) != tt.wantErr {
|
if (err != nil) != tt.wantErr {
|
||||||
t.Errorf("sceneQueryBuilder.FindByChecksum() error = %v, wantErr %v", err, tt.wantErr)
|
t.Errorf("sceneQueryBuilder.FindByChecksum() error = %v, wantErr %v", err, tt.wantErr)
|
||||||
return nil
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := postFindScenes(ctx, tt.want, got); err != nil {
|
if err := postFindScenes(ctx, tt.want, got); err != nil {
|
||||||
t.Errorf("loadSceneRelationships() error = %v", err)
|
t.Errorf("loadSceneRelationships() error = %v", err)
|
||||||
return nil
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
assert.Equal(tt.want, got)
|
assert.Equal(tt.want, got)
|
||||||
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1694,23 +1684,20 @@ func Test_sceneQueryBuilder_FindByOSHash(t *testing.T) {
|
||||||
|
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
runWithRollbackTxn(t, tt.name, func(t *testing.T, ctx context.Context) {
|
runWithRollbackTxn(t, tt.name, func(t *testing.T, ctx context.Context) {
|
||||||
withTxn(func(ctx context.Context) error {
|
|
||||||
got, err := qb.FindByOSHash(ctx, tt.oshash)
|
got, err := qb.FindByOSHash(ctx, tt.oshash)
|
||||||
if (err != nil) != tt.wantErr {
|
if (err != nil) != tt.wantErr {
|
||||||
t.Errorf("sceneQueryBuilder.FindByOSHash() error = %v, wantErr %v", err, tt.wantErr)
|
t.Errorf("sceneQueryBuilder.FindByOSHash() error = %v, wantErr %v", err, tt.wantErr)
|
||||||
return nil
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := postFindScenes(ctx, tt.want, got); err != nil {
|
if err := postFindScenes(ctx, tt.want, got); err != nil {
|
||||||
t.Errorf("loadSceneRelationships() error = %v", err)
|
t.Errorf("loadSceneRelationships() error = %v", err)
|
||||||
return nil
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if !reflect.DeepEqual(got, tt.want) {
|
if !reflect.DeepEqual(got, tt.want) {
|
||||||
t.Errorf("sceneQueryBuilder.FindByOSHash() = %v, want %v", got, tt.want)
|
t.Errorf("sceneQueryBuilder.FindByOSHash() = %v, want %v", got, tt.want)
|
||||||
}
|
}
|
||||||
return nil
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1768,23 +1755,19 @@ func Test_sceneQueryBuilder_FindByPath(t *testing.T) {
|
||||||
|
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
runWithRollbackTxn(t, tt.name, func(t *testing.T, ctx context.Context) {
|
runWithRollbackTxn(t, tt.name, func(t *testing.T, ctx context.Context) {
|
||||||
withTxn(func(ctx context.Context) error {
|
|
||||||
assert := assert.New(t)
|
assert := assert.New(t)
|
||||||
got, err := qb.FindByPath(ctx, tt.path)
|
got, err := qb.FindByPath(ctx, tt.path)
|
||||||
if (err != nil) != tt.wantErr {
|
if (err != nil) != tt.wantErr {
|
||||||
t.Errorf("sceneQueryBuilder.FindByPath() error = %v, wantErr %v", err, tt.wantErr)
|
t.Errorf("sceneQueryBuilder.FindByPath() error = %v, wantErr %v", err, tt.wantErr)
|
||||||
return nil
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := postFindScenes(ctx, tt.want, got); err != nil {
|
if err := postFindScenes(ctx, tt.want, got); err != nil {
|
||||||
t.Errorf("loadSceneRelationships() error = %v", err)
|
t.Errorf("loadSceneRelationships() error = %v", err)
|
||||||
return nil
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
assert.Equal(tt.want, got)
|
assert.Equal(tt.want, got)
|
||||||
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,7 @@ type key int
|
||||||
const (
|
const (
|
||||||
txnKey key = iota + 1
|
txnKey key = iota + 1
|
||||||
dbKey
|
dbKey
|
||||||
|
exclusiveKey
|
||||||
)
|
)
|
||||||
|
|
||||||
func (db *Database) WithDatabase(ctx context.Context) (context.Context, error) {
|
func (db *Database) WithDatabase(ctx context.Context) (context.Context, error) {
|
||||||
|
|
@ -28,7 +29,7 @@ func (db *Database) WithDatabase(ctx context.Context) (context.Context, error) {
|
||||||
return context.WithValue(ctx, dbKey, db.db), nil
|
return context.WithValue(ctx, dbKey, db.db), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (db *Database) Begin(ctx context.Context) (context.Context, error) {
|
func (db *Database) Begin(ctx context.Context, exclusive bool) (context.Context, error) {
|
||||||
if tx, _ := getTx(ctx); tx != nil {
|
if tx, _ := getTx(ctx); tx != nil {
|
||||||
// log the stack trace so we can see
|
// log the stack trace so we can see
|
||||||
logger.Error(string(debug.Stack()))
|
logger.Error(string(debug.Stack()))
|
||||||
|
|
@ -36,11 +37,23 @@ func (db *Database) Begin(ctx context.Context) (context.Context, error) {
|
||||||
return nil, fmt.Errorf("already in transaction")
|
return nil, fmt.Errorf("already in transaction")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if exclusive {
|
||||||
|
if err := db.lock(ctx); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
tx, err := db.db.BeginTxx(ctx, nil)
|
tx, err := db.db.BeginTxx(ctx, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
// begin failed, unlock
|
||||||
|
if exclusive {
|
||||||
|
db.unlock()
|
||||||
|
}
|
||||||
return nil, fmt.Errorf("beginning transaction: %w", err)
|
return nil, fmt.Errorf("beginning transaction: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ctx = context.WithValue(ctx, exclusiveKey, exclusive)
|
||||||
|
|
||||||
return context.WithValue(ctx, txnKey, tx), nil
|
return context.WithValue(ctx, txnKey, tx), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -50,6 +63,8 @@ func (db *Database) Commit(ctx context.Context) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
defer db.txnComplete(ctx)
|
||||||
|
|
||||||
if err := tx.Commit(); err != nil {
|
if err := tx.Commit(); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
@ -63,6 +78,8 @@ func (db *Database) Rollback(ctx context.Context) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
defer db.txnComplete(ctx)
|
||||||
|
|
||||||
if err := tx.Rollback(); err != nil {
|
if err := tx.Rollback(); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
@ -70,6 +87,12 @@ func (db *Database) Rollback(ctx context.Context) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (db *Database) txnComplete(ctx context.Context) {
|
||||||
|
if exclusive := ctx.Value(exclusiveKey).(bool); exclusive {
|
||||||
|
db.unlock()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func getTx(ctx context.Context) (*sqlx.Tx, error) {
|
func getTx(ctx context.Context) (*sqlx.Tx, error) {
|
||||||
tx, ok := ctx.Value(txnKey).(*sqlx.Tx)
|
tx, ok := ctx.Value(txnKey).(*sqlx.Tx)
|
||||||
if !ok || tx == nil {
|
if !ok || tx == nil {
|
||||||
|
|
|
||||||
243
pkg/sqlite/transaction_test.go
Normal file
243
pkg/sqlite/transaction_test.go
Normal file
|
|
@ -0,0 +1,243 @@
|
||||||
|
//go:build integration
|
||||||
|
// +build integration
|
||||||
|
|
||||||
|
package sqlite_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"sync"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stashapp/stash/pkg/models"
|
||||||
|
"github.com/stashapp/stash/pkg/txn"
|
||||||
|
)
|
||||||
|
|
||||||
|
// this test is left commented out as it is not deterministic.
|
||||||
|
// func TestConcurrentExclusiveTxn(t *testing.T) {
|
||||||
|
// const (
|
||||||
|
// workers = 8
|
||||||
|
// loops = 100
|
||||||
|
// innerLoops = 10
|
||||||
|
// sleepTime = 2 * time.Millisecond
|
||||||
|
// )
|
||||||
|
// ctx := context.Background()
|
||||||
|
|
||||||
|
// var wg sync.WaitGroup
|
||||||
|
// for k := 0; k < workers; k++ {
|
||||||
|
// wg.Add(1)
|
||||||
|
// go func(wk int) {
|
||||||
|
// for l := 0; l < loops; l++ {
|
||||||
|
// // change this to WithReadTxn to see locked database error
|
||||||
|
// if err := txn.WithTxn(ctx, db, func(ctx context.Context) error {
|
||||||
|
// for ll := 0; ll < innerLoops; ll++ {
|
||||||
|
// scene := &models.Scene{
|
||||||
|
// Title: "test",
|
||||||
|
// }
|
||||||
|
|
||||||
|
// if err := db.Scene.Create(ctx, scene, nil); err != nil {
|
||||||
|
// return err
|
||||||
|
// }
|
||||||
|
|
||||||
|
// if err := db.Scene.Destroy(ctx, scene.ID); err != nil {
|
||||||
|
// return err
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// time.Sleep(sleepTime)
|
||||||
|
|
||||||
|
// return nil
|
||||||
|
// }); err != nil {
|
||||||
|
// t.Errorf("worker %d loop %d: %v", wk, l, err)
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// wg.Done()
|
||||||
|
// }(k)
|
||||||
|
// }
|
||||||
|
|
||||||
|
// wg.Wait()
|
||||||
|
// }
|
||||||
|
|
||||||
|
func TestConcurrentReadTxn(t *testing.T) {
|
||||||
|
var wg sync.WaitGroup
|
||||||
|
ctx := context.Background()
|
||||||
|
c := make(chan struct{}, 1)
|
||||||
|
|
||||||
|
// first thread
|
||||||
|
wg.Add(2)
|
||||||
|
go func() {
|
||||||
|
defer wg.Done()
|
||||||
|
if err := txn.WithReadTxn(ctx, db, func(ctx context.Context) error {
|
||||||
|
scene := &models.Scene{
|
||||||
|
Title: "test",
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := db.Scene.Create(ctx, scene, nil); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// wait for other thread to start
|
||||||
|
c <- struct{}{}
|
||||||
|
<-c
|
||||||
|
|
||||||
|
if err := db.Scene.Destroy(ctx, scene.ID); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}); err != nil {
|
||||||
|
t.Errorf("unexpected error in first thread: %v", err)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
// second thread
|
||||||
|
go func() {
|
||||||
|
defer wg.Done()
|
||||||
|
_ = txn.WithReadTxn(ctx, db, func(ctx context.Context) error {
|
||||||
|
// wait for first thread
|
||||||
|
<-c
|
||||||
|
defer func() {
|
||||||
|
c <- struct{}{}
|
||||||
|
}()
|
||||||
|
|
||||||
|
scene := &models.Scene{
|
||||||
|
Title: "test",
|
||||||
|
}
|
||||||
|
|
||||||
|
// expect error when we try to do this, as the other thread has already
|
||||||
|
// modified this table
|
||||||
|
if err := db.Scene.Create(ctx, scene, nil); err != nil {
|
||||||
|
if !db.IsLocked(err) {
|
||||||
|
t.Errorf("unexpected error: %v", err)
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
} else {
|
||||||
|
t.Errorf("expected locked error in second thread")
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
}()
|
||||||
|
|
||||||
|
wg.Wait()
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestConcurrentExclusiveAndReadTxn(t *testing.T) {
|
||||||
|
var wg sync.WaitGroup
|
||||||
|
ctx := context.Background()
|
||||||
|
c := make(chan struct{}, 1)
|
||||||
|
|
||||||
|
// first thread
|
||||||
|
wg.Add(2)
|
||||||
|
go func() {
|
||||||
|
defer wg.Done()
|
||||||
|
if err := txn.WithTxn(ctx, db, func(ctx context.Context) error {
|
||||||
|
scene := &models.Scene{
|
||||||
|
Title: "test",
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := db.Scene.Create(ctx, scene, nil); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// wait for other thread to start
|
||||||
|
c <- struct{}{}
|
||||||
|
<-c
|
||||||
|
|
||||||
|
if err := db.Scene.Destroy(ctx, scene.ID); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}); err != nil {
|
||||||
|
t.Errorf("unexpected error in first thread: %v", err)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
// second thread
|
||||||
|
go func() {
|
||||||
|
defer wg.Done()
|
||||||
|
_ = txn.WithReadTxn(ctx, db, func(ctx context.Context) error {
|
||||||
|
// wait for first thread
|
||||||
|
<-c
|
||||||
|
defer func() {
|
||||||
|
c <- struct{}{}
|
||||||
|
}()
|
||||||
|
|
||||||
|
if _, err := db.Scene.Find(ctx, sceneIDs[sceneIdx1WithPerformer]); err != nil {
|
||||||
|
t.Errorf("unexpected error: %v", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
}()
|
||||||
|
|
||||||
|
wg.Wait()
|
||||||
|
}
|
||||||
|
|
||||||
|
// this test is left commented out as it is not deterministic.
|
||||||
|
// func TestConcurrentExclusiveAndReadTxns(t *testing.T) {
|
||||||
|
// const (
|
||||||
|
// writeWorkers = 4
|
||||||
|
// readWorkers = 4
|
||||||
|
// loops = 200
|
||||||
|
// innerLoops = 10
|
||||||
|
// sleepTime = 1 * time.Millisecond
|
||||||
|
// )
|
||||||
|
// ctx := context.Background()
|
||||||
|
|
||||||
|
// var wg sync.WaitGroup
|
||||||
|
// for k := 0; k < writeWorkers; k++ {
|
||||||
|
// wg.Add(1)
|
||||||
|
// go func(wk int) {
|
||||||
|
// for l := 0; l < loops; l++ {
|
||||||
|
// if err := txn.WithTxn(ctx, db, func(ctx context.Context) error {
|
||||||
|
// for ll := 0; ll < innerLoops; ll++ {
|
||||||
|
// scene := &models.Scene{
|
||||||
|
// Title: "test",
|
||||||
|
// }
|
||||||
|
|
||||||
|
// if err := db.Scene.Create(ctx, scene, nil); err != nil {
|
||||||
|
// return err
|
||||||
|
// }
|
||||||
|
|
||||||
|
// if err := db.Scene.Destroy(ctx, scene.ID); err != nil {
|
||||||
|
// return err
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// time.Sleep(sleepTime)
|
||||||
|
|
||||||
|
// return nil
|
||||||
|
// }); err != nil {
|
||||||
|
// t.Errorf("write worker %d loop %d: %v", wk, l, err)
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// wg.Done()
|
||||||
|
// }(k)
|
||||||
|
// }
|
||||||
|
|
||||||
|
// for k := 0; k < readWorkers; k++ {
|
||||||
|
// wg.Add(1)
|
||||||
|
// go func(wk int) {
|
||||||
|
// for l := 0; l < loops; l++ {
|
||||||
|
// if err := txn.WithReadTxn(ctx, db, func(ctx context.Context) error {
|
||||||
|
// for ll := 0; ll < innerLoops; ll++ {
|
||||||
|
// if _, err := db.Scene.Find(ctx, sceneIDs[ll%totalScenes]); err != nil {
|
||||||
|
// return err
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// time.Sleep(sleepTime)
|
||||||
|
|
||||||
|
// return nil
|
||||||
|
// }); err != nil {
|
||||||
|
// t.Errorf("read worker %d loop %d: %v", wk, l, err)
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// wg.Done()
|
||||||
|
// }(k)
|
||||||
|
// }
|
||||||
|
|
||||||
|
// wg.Wait()
|
||||||
|
// }
|
||||||
|
|
@ -6,7 +6,7 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
type Manager interface {
|
type Manager interface {
|
||||||
Begin(ctx context.Context) (context.Context, error)
|
Begin(ctx context.Context, exclusive bool) (context.Context, error)
|
||||||
Commit(ctx context.Context) error
|
Commit(ctx context.Context) error
|
||||||
Rollback(ctx context.Context) error
|
Rollback(ctx context.Context) error
|
||||||
|
|
||||||
|
|
@ -17,18 +17,43 @@ type DatabaseProvider interface {
|
||||||
WithDatabase(ctx context.Context) (context.Context, error)
|
WithDatabase(ctx context.Context) (context.Context, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type DatabaseProviderManager interface {
|
||||||
|
DatabaseProvider
|
||||||
|
Manager
|
||||||
|
}
|
||||||
|
|
||||||
type TxnFunc func(ctx context.Context) error
|
type TxnFunc func(ctx context.Context) error
|
||||||
|
|
||||||
// WithTxn executes fn in a transaction. If fn returns an error then
|
// WithTxn executes fn in a transaction. If fn returns an error then
|
||||||
// the transaction is rolled back. Otherwise it is committed.
|
// the transaction is rolled back. Otherwise it is committed.
|
||||||
|
// Transaction is exclusive. Only one thread may run a transaction
|
||||||
|
// using this function at a time. This function will wait until the
|
||||||
|
// lock is available before executing.
|
||||||
|
// This function should be used for making changes to the database.
|
||||||
func WithTxn(ctx context.Context, m Manager, fn TxnFunc) error {
|
func WithTxn(ctx context.Context, m Manager, fn TxnFunc) error {
|
||||||
const execComplete = true
|
const (
|
||||||
return withTxn(ctx, m, fn, execComplete)
|
execComplete = true
|
||||||
|
exclusive = true
|
||||||
|
)
|
||||||
|
return withTxn(ctx, m, fn, exclusive, execComplete)
|
||||||
}
|
}
|
||||||
|
|
||||||
func withTxn(ctx context.Context, m Manager, fn TxnFunc, execCompleteOnLocked bool) error {
|
// WithReadTxn executes fn in a transaction. If fn returns an error then
|
||||||
|
// the transaction is rolled back. Otherwise it is committed.
|
||||||
|
// Transaction is not exclusive and does not enforce read-only restrictions.
|
||||||
|
// Multiple threads can run transactions using this function concurrently,
|
||||||
|
// but concurrent writes may result in locked database error.
|
||||||
|
func WithReadTxn(ctx context.Context, m Manager, fn TxnFunc) error {
|
||||||
|
const (
|
||||||
|
execComplete = true
|
||||||
|
exclusive = false
|
||||||
|
)
|
||||||
|
return withTxn(ctx, m, fn, exclusive, execComplete)
|
||||||
|
}
|
||||||
|
|
||||||
|
func withTxn(ctx context.Context, m Manager, fn TxnFunc, exclusive bool, execCompleteOnLocked bool) error {
|
||||||
var err error
|
var err error
|
||||||
ctx, err = begin(ctx, m)
|
ctx, err = begin(ctx, m, exclusive)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
@ -59,9 +84,9 @@ func withTxn(ctx context.Context, m Manager, fn TxnFunc, execCompleteOnLocked bo
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func begin(ctx context.Context, m Manager) (context.Context, error) {
|
func begin(ctx context.Context, m Manager, exclusive bool) (context.Context, error) {
|
||||||
var err error
|
var err error
|
||||||
ctx, err = m.Begin(ctx)
|
ctx, err = m.Begin(ctx, exclusive)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
@ -102,6 +127,9 @@ func WithDatabase(ctx context.Context, p DatabaseProvider, fn TxnFunc) error {
|
||||||
return fn(ctx)
|
return fn(ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Retryer is a provides WithTxn function that retries the transaction
|
||||||
|
// if it fails with a locked database error.
|
||||||
|
// Transactions are run in exclusive mode.
|
||||||
type Retryer struct {
|
type Retryer struct {
|
||||||
Manager Manager
|
Manager Manager
|
||||||
// use value < 0 to retry forever
|
// use value < 0 to retry forever
|
||||||
|
|
@ -113,8 +141,11 @@ func (r Retryer) WithTxn(ctx context.Context, fn TxnFunc) error {
|
||||||
var attempt int
|
var attempt int
|
||||||
var err error
|
var err error
|
||||||
for attempt = 1; attempt <= r.Retries || r.Retries < 0; attempt++ {
|
for attempt = 1; attempt <= r.Retries || r.Retries < 0; attempt++ {
|
||||||
const execComplete = false
|
const (
|
||||||
err = withTxn(ctx, r.Manager, fn, execComplete)
|
execComplete = false
|
||||||
|
exclusive = true
|
||||||
|
)
|
||||||
|
err = withTxn(ctx, r.Manager, fn, exclusive, execComplete)
|
||||||
|
|
||||||
if err == nil {
|
if err == nil {
|
||||||
return nil
|
return nil
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,7 @@
|
||||||
* Changed Performer height to be numeric, and changed filtering accordingly. ([#3060](https://github.com/stashapp/stash/pull/3060))
|
* Changed Performer height to be numeric, and changed filtering accordingly. ([#3060](https://github.com/stashapp/stash/pull/3060))
|
||||||
|
|
||||||
### 🐛 Bug fixes
|
### 🐛 Bug fixes
|
||||||
|
* Fixed `database is locked` errors when performing operations while running a scan. ([#3153](https://github.com/stashapp/stash/pull/3153))
|
||||||
* Fixed database backup in incorrect directory during migration when database location is an absolute path. ([#3140](https://github.com/stashapp/stash/pull/3140))
|
* Fixed database backup in incorrect directory during migration when database location is an absolute path. ([#3140](https://github.com/stashapp/stash/pull/3140))
|
||||||
* Fixed gallery create post hook not being fired during gallery creation. ([#3134](https://github.com/stashapp/stash/pull/3134))
|
* Fixed gallery create post hook not being fired during gallery creation. ([#3134](https://github.com/stashapp/stash/pull/3134))
|
||||||
* Fixed autotag error when tagging a large amount of objects. ([#3106](https://github.com/stashapp/stash/pull/3106))
|
* Fixed autotag error when tagging a large amount of objects. ([#3106](https://github.com/stashapp/stash/pull/3106))
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue