diff --git a/store/opentracinglayer/opentracinglayer.go b/store/opentracinglayer/opentracinglayer.go index 5460df76ca..55e5c90b7d 100644 --- a/store/opentracinglayer/opentracinglayer.go +++ b/store/opentracinglayer/opentracinglayer.go @@ -3146,6 +3146,24 @@ func (s *OpenTracingLayerFileInfoStore) GetForUser(userID string) ([]*model.File return result, err } +func (s *OpenTracingLayerFileInfoStore) GetFromMaster(id string) (*model.FileInfo, error) { + origCtx := s.Root.Store.Context() + span, newCtx := tracing.StartSpanWithParentByContext(s.Root.Store.Context(), "FileInfoStore.GetFromMaster") + s.Root.Store.SetContext(newCtx) + defer func() { + s.Root.Store.SetContext(origCtx) + }() + + defer span.Finish() + result, err := s.FileInfoStore.GetFromMaster(id) + if err != nil { + span.LogFields(spanlog.Error(err)) + ext.Error.Set(span, true) + } + + return result, err +} + func (s *OpenTracingLayerFileInfoStore) GetWithOptions(page int, perPage int, opt *model.GetFileInfosOptions) ([]*model.FileInfo, error) { origCtx := s.Root.Store.Context() span, newCtx := tracing.StartSpanWithParentByContext(s.Root.Store.Context(), "FileInfoStore.GetWithOptions") diff --git a/store/retrylayer/retrylayer.go b/store/retrylayer/retrylayer.go index 36ef22531b..daf80048b9 100644 --- a/store/retrylayer/retrylayer.go +++ b/store/retrylayer/retrylayer.go @@ -3370,6 +3370,26 @@ func (s *RetryLayerFileInfoStore) GetForUser(userID string) ([]*model.FileInfo, } +func (s *RetryLayerFileInfoStore) GetFromMaster(id string) (*model.FileInfo, error) { + + tries := 0 + for { + result, err := s.FileInfoStore.GetFromMaster(id) + if err == nil { + return result, nil + } + if !isRepeatableError(err) { + return result, err + } + tries++ + if tries >= 3 { + err = errors.Wrap(err, "giving up after 3 consecutive repeatable transaction failures") + return result, err + } + } + +} + func (s *RetryLayerFileInfoStore) GetWithOptions(page int, perPage int, opt *model.GetFileInfosOptions) ([]*model.FileInfo, error) { tries := 0 diff --git a/store/searchlayer/file_info_layer.go b/store/searchlayer/file_info_layer.go index eb3c31bcc4..9b758174ea 100644 --- a/store/searchlayer/file_info_layer.go +++ b/store/searchlayer/file_info_layer.go @@ -105,7 +105,7 @@ func (s SearchFileInfoStore) Save(info *model.FileInfo) (*model.FileInfo, error) func (s SearchFileInfoStore) SetContent(fileID, content string) error { err := s.FileInfoStore.SetContent(fileID, content) if err == nil { - nfile, err2 := s.FileInfoStore.Get(fileID) + nfile, err2 := s.FileInfoStore.GetFromMaster(fileID) if err2 == nil { nfile.Content = content s.indexFile(nfile) @@ -117,7 +117,7 @@ func (s SearchFileInfoStore) SetContent(fileID, content string) error { func (s SearchFileInfoStore) AttachToPost(fileId, postId, creatorId string) error { err := s.FileInfoStore.AttachToPost(fileId, postId, creatorId) if err == nil { - nFileInfo, err2 := s.FileInfoStore.Get(fileId) + nFileInfo, err2 := s.FileInfoStore.GetFromMaster(fileId) if err2 == nil { s.indexFile(nFileInfo) } diff --git a/store/sqlstore/file_info_store.go b/store/sqlstore/file_info_store.go index f8b42b2dbf..5856b7557b 100644 --- a/store/sqlstore/file_info_store.go +++ b/store/sqlstore/file_info_store.go @@ -138,7 +138,7 @@ func (fs SqlFileInfoStore) Upsert(info *model.FileInfo) (*model.FileInfo, error) return info, nil } -func (fs SqlFileInfoStore) Get(id string) (*model.FileInfo, error) { +func (fs SqlFileInfoStore) get(id string, fromMaster bool) (*model.FileInfo, error) { info := &model.FileInfo{} query := fs.getQueryBuilder(). @@ -152,7 +152,12 @@ func (fs SqlFileInfoStore) Get(id string) (*model.FileInfo, error) { return nil, errors.Wrap(err, "file_info_tosql") } - if err := fs.GetReplica().SelectOne(info, queryString, args...); err != nil { + db := fs.GetReplica() + if fromMaster { + db = fs.GetMaster() + } + + if err := db.SelectOne(info, queryString, args...); err != nil { if err == sql.ErrNoRows { return nil, store.NewErrNotFound("FileInfo", id) } @@ -161,6 +166,14 @@ func (fs SqlFileInfoStore) Get(id string) (*model.FileInfo, error) { return info, nil } +func (fs SqlFileInfoStore) Get(id string) (*model.FileInfo, error) { + return fs.get(id, false) +} + +func (fs SqlFileInfoStore) GetFromMaster(id string) (*model.FileInfo, error) { + return fs.get(id, true) +} + func (fs SqlFileInfoStore) GetWithOptions(page, perPage int, opt *model.GetFileInfosOptions) ([]*model.FileInfo, error) { if perPage < 0 { return nil, store.NewErrLimitExceeded("perPage", perPage, "value used in pagination while getting FileInfos") diff --git a/store/store.go b/store/store.go index 38c69e23d1..7c55a63eea 100644 --- a/store/store.go +++ b/store/store.go @@ -586,6 +586,7 @@ type FileInfoStore interface { Save(info *model.FileInfo) (*model.FileInfo, error) Upsert(info *model.FileInfo) (*model.FileInfo, error) Get(id string) (*model.FileInfo, error) + GetFromMaster(id string) (*model.FileInfo, error) GetByIds(ids []string) ([]*model.FileInfo, error) GetByPath(path string) (*model.FileInfo, error) GetForPost(postID string, readFromMaster, includeDeleted, allowFromCache bool) ([]*model.FileInfo, error) diff --git a/store/storetest/mocks/FileInfoStore.go b/store/storetest/mocks/FileInfoStore.go index 8e828618fe..c0a95731ef 100644 --- a/store/storetest/mocks/FileInfoStore.go +++ b/store/storetest/mocks/FileInfoStore.go @@ -213,6 +213,29 @@ func (_m *FileInfoStore) GetForUser(userID string) ([]*model.FileInfo, error) { return r0, r1 } +// GetFromMaster provides a mock function with given fields: id +func (_m *FileInfoStore) GetFromMaster(id string) (*model.FileInfo, error) { + ret := _m.Called(id) + + var r0 *model.FileInfo + if rf, ok := ret.Get(0).(func(string) *model.FileInfo); ok { + r0 = rf(id) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*model.FileInfo) + } + } + + var r1 error + if rf, ok := ret.Get(1).(func(string) error); ok { + r1 = rf(id) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + // GetWithOptions provides a mock function with given fields: page, perPage, opt func (_m *FileInfoStore) GetWithOptions(page int, perPage int, opt *model.GetFileInfosOptions) ([]*model.FileInfo, error) { ret := _m.Called(page, perPage, opt) diff --git a/store/timerlayer/timerlayer.go b/store/timerlayer/timerlayer.go index b7ce884bc8..736fb81145 100644 --- a/store/timerlayer/timerlayer.go +++ b/store/timerlayer/timerlayer.go @@ -2882,6 +2882,22 @@ func (s *TimerLayerFileInfoStore) GetForUser(userID string) ([]*model.FileInfo, return result, err } +func (s *TimerLayerFileInfoStore) GetFromMaster(id string) (*model.FileInfo, error) { + start := timemodule.Now() + + result, err := s.FileInfoStore.GetFromMaster(id) + + elapsed := float64(timemodule.Since(start)) / float64(timemodule.Second) + if s.Root.Metrics != nil { + success := "false" + if err == nil { + success = "true" + } + s.Root.Metrics.ObserveStoreMethodDuration("FileInfoStore.GetFromMaster", success, elapsed) + } + return result, err +} + func (s *TimerLayerFileInfoStore) GetWithOptions(page int, perPage int, opt *model.GetFileInfosOptions) ([]*model.FileInfo, error) { start := timemodule.Now()