-
Notifications
You must be signed in to change notification settings - Fork 251
Avoid re-creating pre-existing folders. #3295
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||
|---|---|---|---|---|---|---|---|---|
| @@ -1,6 +1,7 @@ | ||||||||
| package ste | ||||||||
|
|
||||||||
| import ( | ||||||||
| "errors" | ||||||||
| "fmt" | ||||||||
| "net/url" | ||||||||
| "strings" | ||||||||
|
|
@@ -31,17 +32,21 @@ func NewTransferFetcher(jobMgr IJobMgr) TransferFetcher { | |||||||
|
|
||||||||
| // NewFolderCreationTracker creates a folder creation tracker taking in a TransferFetcher (typically created by NewTransferFetcher) | ||||||||
| // A TransferFetcher is used in place of an IJobMgr to make testing easier to implement. | ||||||||
| func NewFolderCreationTracker(fpo common.FolderPropertyOption, fetcher TransferFetcher) FolderCreationTracker { | ||||||||
| switch fpo { | ||||||||
| case common.EFolderPropertiesOption.AllFolders(), | ||||||||
| common.EFolderPropertiesOption.AllFoldersExceptRoot(): | ||||||||
| func NewFolderCreationTracker(fpo common.FolderPropertyOption, fetcher TransferFetcher, fromTo common.FromTo) FolderCreationTracker { | ||||||||
| switch { | ||||||||
| // create a folder tracker when we're persisting properties | ||||||||
| case fpo == common.EFolderPropertiesOption.AllFolders(), | ||||||||
| fpo == common.EFolderPropertiesOption.AllFoldersExceptRoot(), | ||||||||
| // create a folder tracker for destinations where we don't want to spam the service with create requests | ||||||||
| // on folders that already exist | ||||||||
| fromTo.To().IsFile(), | ||||||||
| fromTo.To() == common.ELocation.BlobFS(): | ||||||||
| return &jpptFolderTracker{ // This prevents a dependency cycle. Reviewers: Are we OK with this? Can you think of a better way to do it? | ||||||||
| fetchTransfer: fetcher, | ||||||||
| mu: &sync.Mutex{}, | ||||||||
| contents: make(map[string]JpptFolderIndex), | ||||||||
| unregisteredButCreated: make(map[string]struct{}), | ||||||||
| fetchTransfer: fetcher, | ||||||||
| mu: &sync.Mutex{}, | ||||||||
| contents: make(map[string]*JpptFolderTrackerState), | ||||||||
| } | ||||||||
| case common.EFolderPropertiesOption.NoFolders(): | ||||||||
| case fpo == common.EFolderPropertiesOption.NoFolders(): | ||||||||
| // can't use simpleFolderTracker here, because when no folders are processed, | ||||||||
| // then StopTracking will never be called, so we'll just use more and more memory for the map | ||||||||
| return &nullFolderTracker{} | ||||||||
|
|
@@ -69,15 +74,10 @@ func (f *nullFolderTracker) StopTracking(folder string) { | |||||||
|
|
||||||||
| type jpptFolderTracker struct { | ||||||||
| // fetchTransfer is used instead of a IJobMgr reference to support testing | ||||||||
| fetchTransfer func(index JpptFolderIndex) *JobPartPlanTransfer | ||||||||
| mu *sync.Mutex | ||||||||
| contents map[string]JpptFolderIndex | ||||||||
| unregisteredButCreated map[string]struct{} | ||||||||
| } | ||||||||
| fetchTransfer func(index JpptFolderIndex) *JobPartPlanTransfer | ||||||||
| mu *sync.Mutex | ||||||||
|
|
||||||||
| type JpptFolderIndex struct { | ||||||||
| PartNum PartNumber | ||||||||
| TransferIndex uint32 | ||||||||
| contents map[string]*JpptFolderTrackerState | ||||||||
| } | ||||||||
|
|
||||||||
| func (f *jpptFolderTracker) RegisterPropertiesTransfer(folder string, partNum PartNumber, transferIndex uint32) { | ||||||||
|
|
@@ -88,16 +88,34 @@ func (f *jpptFolderTracker) RegisterPropertiesTransfer(folder string, partNum Pa | |||||||
| return // Never persist to dev-null | ||||||||
| } | ||||||||
|
|
||||||||
| f.contents[folder] = JpptFolderIndex{ | ||||||||
| state, present := f.contents[folder] | ||||||||
|
|
||||||||
| if !present { | ||||||||
| state = &JpptFolderTrackerState{} | ||||||||
| } | ||||||||
|
|
||||||||
| state.Index = &JpptFolderIndex{ | ||||||||
| PartNum: partNum, | ||||||||
| TransferIndex: transferIndex, | ||||||||
| } | ||||||||
|
|
||||||||
| // We created it before it was enumerated-- Let's register that now. | ||||||||
| if _, ok := f.unregisteredButCreated[folder]; ok { | ||||||||
| f.fetchTransfer(JpptFolderIndex{PartNum: partNum, TransferIndex: transferIndex}).SetTransferStatus(common.ETransferStatus.FolderCreated(), false) | ||||||||
| // if our transfer already has a created status, we should adopt that. | ||||||||
| if ts := f.fetchTransfer(*state.Index).TransferStatus(); ts == ts.FolderCreated() { | ||||||||
|
||||||||
| if ts := f.fetchTransfer(*state.Index).TransferStatus(); ts == ts.FolderCreated() { | |
| if ts := f.fetchTransfer(*state.Index).TransferStatus(); ts == common.ETransferStatus.FolderCreated() { |
Copilot
AI
Nov 17, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When a new state is created (line 153) for a folder that isn't already in f.contents, it needs to be stored in the map. After updating the state's Status field (lines 156-160), add f.contents[folder] = state before line 174 to persist the state. Without this, the state is lost and subsequent calls to CreateFolder for the same folder won't see the previous status, defeating the purpose of tracking folder creation.
| f.contents[folder] = state |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The comment is misleading. The error is returned after doCreation has already been called and attempted to create the folder. It signals that the folder already existed, not that creation should be skipped. Consider rewording to: "FolderCreationErrorAlreadyExists is a signalling error that should be returned by doCreation when the folder already exists, allowing the tracker to mark it as FolderExisted rather than FolderCreated."