Add filesystem based blob storage (#3187)

* Refactor transaction hooks. Add preCommit
* Add BlobStore
* Use blobStore for tag images
* Use blobStore for studio images
* Use blobStore for performer images
* Use blobStore for scene covers
* Don't generate screenshots in legacy directory
* Run post-hooks outside original transaction
* Use blobStore for movie images
* Remove unnecessary DestroyImage methods
* Add missing filter for scene cover
* Add covers to generate options
* Add generate cover option to UI
* Add screenshot migration
* Delete thumb files as part of screenshot migration
This commit is contained in:
WithoutPants
2023-03-17 10:52:49 +11:00
committed by GitHub
parent c3081700c0
commit 7cff71c35f
105 changed files with 2647 additions and 1086 deletions

View File

@@ -11,9 +11,10 @@ const (
)
type hookManager struct {
postCommitHooks []TxnFunc
postRollbackHooks []TxnFunc
postCompleteHooks []TxnFunc
preCommitHooks []TxnFunc
postCommitHooks []MustFunc
postRollbackHooks []MustFunc
postCompleteHooks []MustFunc
}
func (m *hookManager) register(ctx context.Context) context.Context {
@@ -28,39 +29,55 @@ func hookManagerCtx(ctx context.Context) *hookManager {
return m
}
func executeHooks(ctx context.Context, hooks []TxnFunc) {
func executeHooks(ctx context.Context, hooks []TxnFunc) error {
// we need to return the first error
for _, h := range hooks {
// ignore errors
_ = h(ctx)
if err := h(ctx); err != nil {
return err
}
}
return nil
}
func executeMustHooks(ctx context.Context, hooks []MustFunc) {
for _, h := range hooks {
h(ctx)
}
}
func executePostCommitHooks(ctx context.Context, outerCtx context.Context) {
m := hookManagerCtx(ctx)
executeHooks(outerCtx, m.postCommitHooks)
func (m *hookManager) executePostCommitHooks(ctx context.Context) {
executeMustHooks(ctx, m.postCommitHooks)
}
func executePostRollbackHooks(ctx context.Context, outerCtx context.Context) {
m := hookManagerCtx(ctx)
executeHooks(outerCtx, m.postRollbackHooks)
func (m *hookManager) executePostRollbackHooks(ctx context.Context) {
executeMustHooks(ctx, m.postRollbackHooks)
}
func executePostCompleteHooks(ctx context.Context, outerCtx context.Context) {
m := hookManagerCtx(ctx)
executeHooks(outerCtx, m.postCompleteHooks)
func (m *hookManager) executePreCommitHooks(ctx context.Context) error {
return executeHooks(ctx, m.preCommitHooks)
}
func AddPostCommitHook(ctx context.Context, hook TxnFunc) {
func (m *hookManager) executePostCompleteHooks(ctx context.Context) {
executeMustHooks(ctx, m.postCompleteHooks)
}
func AddPreCommitHook(ctx context.Context, hook TxnFunc) {
m := hookManagerCtx(ctx)
m.preCommitHooks = append(m.preCommitHooks, hook)
}
func AddPostCommitHook(ctx context.Context, hook MustFunc) {
m := hookManagerCtx(ctx)
m.postCommitHooks = append(m.postCommitHooks, hook)
}
func AddPostRollbackHook(ctx context.Context, hook TxnFunc) {
func AddPostRollbackHook(ctx context.Context, hook MustFunc) {
m := hookManagerCtx(ctx)
m.postRollbackHooks = append(m.postRollbackHooks, hook)
}
func AddPostCompleteHook(ctx context.Context, hook TxnFunc) {
func AddPostCompleteHook(ctx context.Context, hook MustFunc) {
m := hookManagerCtx(ctx)
m.postCompleteHooks = append(m.postCompleteHooks, hook)
}

View File

@@ -17,13 +17,14 @@ type DatabaseProvider interface {
WithDatabase(ctx context.Context) (context.Context, error)
}
type DatabaseProviderManager interface {
DatabaseProvider
Manager
}
// TxnFunc is a function that is used in transaction hooks.
// It should return an error if something went wrong.
type TxnFunc func(ctx context.Context) error
// MustFunc is a function that is used in transaction hooks.
// It does not return an error.
type MustFunc func(ctx context.Context)
// WithTxn executes fn in a transaction. If fn returns an error then
// the transaction is rolled back. Otherwise it is committed.
// Transaction is exclusive. Only one thread may run a transaction
@@ -51,35 +52,44 @@ func WithReadTxn(ctx context.Context, m Manager, fn TxnFunc) error {
return withTxn(ctx, m, fn, exclusive, execComplete)
}
func withTxn(outerCtx context.Context, m Manager, fn TxnFunc, exclusive bool, execCompleteOnLocked bool) error {
ctx, err := begin(outerCtx, m, exclusive)
func withTxn(ctx context.Context, m Manager, fn TxnFunc, exclusive bool, execCompleteOnLocked bool) error {
// post-hooks should be executed with the outside context
txnCtx, err := begin(ctx, m, exclusive)
if err != nil {
return err
}
hookMgr := hookManagerCtx(txnCtx)
defer func() {
if p := recover(); p != nil {
// a panic occurred, rollback and repanic
rollback(ctx, outerCtx, m)
rollback(txnCtx, m)
panic(p)
}
if err != nil {
// something went wrong, rollback
rollback(ctx, outerCtx, m)
rollback(txnCtx, m)
// execute post-hooks with outside context
hookMgr.executePostRollbackHooks(ctx)
if execCompleteOnLocked || !m.IsLocked(err) {
executePostCompleteHooks(ctx, outerCtx)
hookMgr.executePostCompleteHooks(ctx)
}
} else {
// all good, commit
err = commit(ctx, outerCtx, m)
executePostCompleteHooks(ctx, outerCtx)
err = commit(txnCtx, m)
// execute post-hooks with outside context
hookMgr.executePostCommitHooks(ctx)
hookMgr.executePostCompleteHooks(ctx)
}
}()
err = fn(ctx)
err = fn(txnCtx)
return err
}
@@ -96,21 +106,23 @@ func begin(ctx context.Context, m Manager, exclusive bool) (context.Context, err
return ctx, nil
}
func commit(ctx context.Context, outerCtx context.Context, m Manager) error {
func commit(ctx context.Context, m Manager) error {
hookMgr := hookManagerCtx(ctx)
if err := hookMgr.executePreCommitHooks(ctx); err != nil {
return err
}
if err := m.Commit(ctx); err != nil {
return err
}
executePostCommitHooks(ctx, outerCtx)
return nil
}
func rollback(ctx context.Context, outerCtx context.Context, m Manager) {
func rollback(ctx context.Context, m Manager) {
if err := m.Rollback(ctx); err != nil {
return
}
executePostRollbackHooks(ctx, outerCtx)
}
// WithDatabase executes fn with the context provided by p.WithDatabase.