Indexer: Avoid adding the same entity simultaneously

This commit is contained in:
Michael Mayer 2020-12-13 15:43:01 +01:00
parent 801dc49dd7
commit 43e324700b
7 changed files with 53 additions and 8 deletions

View file

@ -2,6 +2,7 @@ package entity
import (
"strings"
"sync"
"time"
"github.com/gosimple/slug"
@ -9,6 +10,8 @@ import (
"github.com/photoprism/photoprism/pkg/txt"
)
var cameraMutex = sync.Mutex{}
// Camera model and make (as extracted from UpdateExif metadata)
type Camera struct {
ID uint `gorm:"primary_key" json:"ID" yaml:"ID"`
@ -169,6 +172,9 @@ func NewCamera(modelName string, makeName string) *Camera {
// Create inserts a new row to the database.
func (m *Camera) Create() error {
cameraMutex.Lock()
defer cameraMutex.Unlock()
return Db().Create(m).Error
}
@ -176,9 +182,9 @@ func (m *Camera) Create() error {
func FirstOrCreateCamera(m *Camera) *Camera {
result := Camera{}
if err := Db().Where("camera_model = ? AND camera_make = ?", m.CameraModel, m.CameraMake).First(&result).Error; err == nil {
if res := Db().Where("camera_model = ? AND camera_make = ?", m.CameraModel, m.CameraMake).First(&result); res.Error == nil {
return &result
} else if createErr := m.Create(); createErr == nil {
} else if err := m.Create(); err == nil {
if !m.Unknown() {
event.EntitiesCreated("cameras", []*Camera{m})
@ -188,10 +194,10 @@ func FirstOrCreateCamera(m *Camera) *Camera {
}
return m
} else if err := Db().Where("camera_model = ? AND camera_make = ?", m.CameraModel, m.CameraMake).First(&result).Error; err == nil {
} else if res := Db().Where("camera_model = ? AND camera_make = ?", m.CameraModel, m.CameraMake).First(&result); res.Error == nil {
return &result
} else {
log.Errorf("camera: %s (first or create %s)", createErr, m.String())
log.Errorf("camera: %s (create %s)", err.Error(), txt.Quote(m.String()))
}
return nil

View file

@ -2,6 +2,7 @@ package entity
import (
"strings"
"sync"
"time"
"github.com/photoprism/photoprism/internal/event"
@ -10,6 +11,8 @@ import (
"github.com/photoprism/photoprism/pkg/txt"
)
var cellMutex = sync.Mutex{}
// Cell represents a S2 cell with location data.
type Cell struct {
ID string `gorm:"type:VARBINARY(42);primary_key;auto_increment:false;" json:"ID" yaml:"ID"`
@ -95,6 +98,9 @@ func (m *Cell) Find(api string) error {
m.CellName = l.Name()
m.CellCategory = l.Category()
cellMutex.Lock()
defer cellMutex.Unlock()
if createErr := db.Create(m).Error; createErr == nil {
log.Debugf("location: added cell %s [%s]", m.ID, time.Since(start))
return nil

View file

@ -2,10 +2,13 @@ package entity
import (
"strings"
"sync"
"github.com/photoprism/photoprism/pkg/txt"
)
var keywordMutex = sync.Mutex{}
// Keyword used for full text search
type Keyword struct {
ID uint `gorm:"primary_key"`
@ -41,6 +44,9 @@ func (m *Keyword) Save() error {
// Create inserts a new row to the database.
func (m *Keyword) Create() error {
keywordMutex.Lock()
defer keywordMutex.Unlock()
return Db().Create(m).Error
}

View file

@ -1,6 +1,7 @@
package entity
import (
"sync"
"time"
"github.com/gosimple/slug"
@ -11,6 +12,8 @@ import (
"github.com/photoprism/photoprism/pkg/txt"
)
var labelMutex = sync.Mutex{}
type Labels []Label
// Label is used for photo, album and location categorization
@ -65,11 +68,17 @@ func NewLabel(name string, priority int) *Label {
// Save updates the existing or inserts a new label.
func (m *Label) Save() error {
labelMutex.Lock()
defer labelMutex.Unlock()
return Db().Save(m).Error
}
// Create inserts the label to the database.
func (m *Label) Create() error {
labelMutex.Lock()
defer labelMutex.Unlock()
return Db().Create(m).Error
}

View file

@ -2,6 +2,7 @@ package entity
import (
"strings"
"sync"
"time"
"github.com/gosimple/slug"
@ -9,6 +10,8 @@ import (
"github.com/photoprism/photoprism/pkg/txt"
)
var lensMutex = sync.Mutex{}
// Lens represents camera lens (as extracted from UpdateExif metadata)
type Lens struct {
ID uint `gorm:"primary_key" json:"ID" yaml:"ID"`
@ -81,6 +84,9 @@ func NewLens(modelName string, makeName string) *Lens {
// Create inserts a new row to the database.
func (m *Lens) Create() error {
lensMutex.Lock()
defer lensMutex.Unlock()
return Db().Create(m).Error
}
@ -88,9 +94,9 @@ func (m *Lens) Create() error {
func FirstOrCreateLens(m *Lens) *Lens {
result := Lens{}
if err := Db().Where("lens_slug = ?", m.LensSlug).First(&result).Error; err == nil {
if res := Db().Where("lens_slug = ?", m.LensSlug).First(&result); res.Error == nil {
return &result
} else if createErr := m.Create(); createErr == nil {
} else if err := m.Create(); err == nil {
if !m.Unknown() {
event.EntitiesCreated("lenses", []*Lens{m})
@ -100,10 +106,10 @@ func FirstOrCreateLens(m *Lens) *Lens {
}
return m
} else if err := Db().Where("lens_slug = ?", m.LensSlug).First(&result).Error; err == nil {
} else if res := Db().Where("lens_slug = ?", m.LensSlug).First(&result); res.Error == nil {
return &result
} else {
log.Errorf("lens: %s (first or create %s)", createErr, m.String())
log.Errorf("lens: %s (create %s)", err.Error(), txt.Quote(m.String()))
}
return nil

View file

@ -4,11 +4,14 @@ import (
"io/ioutil"
"os"
"path/filepath"
"sync"
"github.com/photoprism/photoprism/pkg/fs"
"gopkg.in/yaml.v2"
)
var photoYamlMutex = sync.Mutex{}
// Yaml returns photo data as YAML string.
func (m *Photo) Yaml() ([]byte, error) {
out, err := yaml.Marshal(m)
@ -33,6 +36,9 @@ func (m *Photo) SaveAsYaml(fileName string) error {
return err
}
photoYamlMutex.Lock()
defer photoYamlMutex.Unlock()
// Write YAML data to file.
if err := ioutil.WriteFile(fileName, data, os.ModePerm); err != nil {
return err

View file

@ -2,11 +2,14 @@ package entity
import (
"strings"
"sync"
"time"
"github.com/photoprism/photoprism/internal/maps"
)
var placeMutex = sync.Mutex{}
// Place used to associate photos to places
type Place struct {
ID string `gorm:"type:VARBINARY(42);primary_key;auto_increment:false;" json:"PlaceID" yaml:"PlaceID"`
@ -69,6 +72,9 @@ func (m *Place) Find() error {
// Create inserts a new row to the database.
func (m *Place) Create() error {
placeMutex.Lock()
defer placeMutex.Unlock()
return Db().Create(m).Error
}