Lock updating info in lazyItem (#4401)

Don't allow concurrent reads/writes to info in
lazyItem so we can make stronger assumptions
about state

---

#### Does this PR need a docs update or release note?

- [ ]  Yes, it's included
- [ ] 🕐 Yes, but in a later PR
- [x]  No

#### Type of change

- [ ] 🌻 Feature
- [ ] 🐛 Bugfix
- [ ] 🗺️ Documentation
- [ ] 🤖 Supportability/Tests
- [ ] 💻 CI/Deployment
- [x] 🧹 Tech Debt/Cleanup

#### Test Plan

- [ ] 💪 Manual
- [x]  Unit test
- [x] 💚 E2E
This commit is contained in:
ashmrtn 2023-09-28 18:50:15 -07:00 committed by GitHub
parent 5258ef0f36
commit d5cdf37369
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -4,6 +4,7 @@ import (
"bytes" "bytes"
"context" "context"
"io" "io"
"sync"
"time" "time"
"github.com/alcionai/clues" "github.com/alcionai/clues"
@ -110,6 +111,7 @@ func NewLazyItem(
// made. // made.
type lazyItem struct { type lazyItem struct {
ctx context.Context ctx context.Context
mu sync.Mutex
id string id string
errs *fault.Bus errs *fault.Bus
itemGetter ItemDataGetter itemGetter ItemDataGetter
@ -127,12 +129,18 @@ type lazyItem struct {
delInFlight bool delInFlight bool
} }
func (i lazyItem) ID() string { func (i *lazyItem) ID() string {
return i.id return i.id
} }
func (i *lazyItem) ToReader() io.ReadCloser { func (i *lazyItem) ToReader() io.ReadCloser {
return lazy.NewLazyReadCloser(func() (io.ReadCloser, error) { return lazy.NewLazyReadCloser(func() (io.ReadCloser, error) {
// Don't allow getting Item info while trying to initialize said info.
// GetData could be a long running call, but in theory nothing should happen
// with the item until a reader is returned anyway.
i.mu.Lock()
defer i.mu.Unlock()
reader, info, delInFlight, err := i.itemGetter.GetData(i.ctx, i.errs) reader, info, delInFlight, err := i.itemGetter.GetData(i.ctx, i.errs)
if err != nil { if err != nil {
return nil, clues.Stack(err) return nil, clues.Stack(err)
@ -159,11 +167,14 @@ func (i *lazyItem) ToReader() io.ReadCloser {
}) })
} }
func (i lazyItem) Deleted() bool { func (i *lazyItem) Deleted() bool {
return false return false
} }
func (i lazyItem) Info() (details.ItemInfo, error) { func (i *lazyItem) Info() (details.ItemInfo, error) {
i.mu.Lock()
defer i.mu.Unlock()
if i.delInFlight { if i.delInFlight {
return details.ItemInfo{}, clues.Stack(ErrNotFound).WithClues(i.ctx) return details.ItemInfo{}, clues.Stack(ErrNotFound).WithClues(i.ctx)
} else if i.info == nil { } else if i.info == nil {
@ -174,6 +185,6 @@ func (i lazyItem) Info() (details.ItemInfo, error) {
return *i.info, nil return *i.info, nil
} }
func (i lazyItem) ModTime() time.Time { func (i *lazyItem) ModTime() time.Time {
return i.modTime return i.modTime
} }