-
Notifications
You must be signed in to change notification settings - Fork 2.7k
chore(registry/storage/driver/s3-aws): refactor writer creation #4429
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?
Conversation
|
Only concern I have is the use of |
5ae4619 to
cadfbea
Compare
|
Thanks for running the tests! As suspected, there was some stuff which had to be changed regarding |
9aeacd6 to
d29ef83
Compare
|
Okay, I tried using |
3909019 to
d3462c6
Compare
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.
Thanks, very nice refactoring! I left some comments in line.
PTAL @Jamstah if you have any spare cycles 🙇♂️
| if key != *multi.Key { | ||
| continue | ||
| } | ||
| func (d *driver) inProgressUpload(ctx context.Context, path string) (uploadID *string, err error) { |
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.
Please don't use named returns unless it significantly improves the code (it often doesn't and makes readers of the code miss important logic). Besides, you don't even take advantage of them through empty returns: all the returns in this func use explicit var names.
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.
Named returns also serve as a form of documentation. The meaning of *string without the named return is unclear.
func (d *driver) inProgressUpload(ctx context.Context, path string) (uploadID *string, err error)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 meaning of *string without the named return is unclear.
Sure, but this is an unexported func, so one needs to read it anyway.
As I said, they generally make it "harder" to read the code, which is why we've been removing them from this codebase.
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.
Do you feel in this case the named return parameter makes the code harder to understand? I'm not sure I see the benefit of:
func (d *driver) inProgressUpload(ctx context.Context, path string) (*string, error) {
var (
uploadID *string
empty bool
)compared to
func (d *driver) inProgressUpload(ctx context.Context, path string) (uploadID *string, err error) {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.
I think we could compare our opinions on code documentation using named returns all day -- @milosgajdos is stating that precedent has been set in the repo to not use named returns so it makes sense to just follow suite here.
| } | ||
| } | ||
| return nil, storagedriver.PathNotFoundError{Path: path} | ||
| return nil, nil |
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.
This rubs me the wrong way due to how I expect to consume return values from functions e.g. I would not expect the return value to be nil if the returned error is nil as well -- this often leads to very unexpected surprises for API consumers, especially when consuming unexported functions that often miss comments.
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.
Do you have any other suggestions?
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.
Is there a reason why we no longer return return nil, storagedriver.PathNotFoundError{Path: path} like the original code did?
If there is no upload found in path then it would maybe make sense to return it and let the consumer of the API decide what to do in such situation (we'd obviously add a code comment explaining what's what)
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.
Hmm, yeah, sorry, I did have this in my original change but it somehow slipped when I switched it to using pages. I can fix that.
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.
Have resolved it in the latest change. I still don't see many other ways of expressing this condition, it's sort of nice for the zero value to have meaning? An extra return value to indicate whether it was found or not just feels redundant when it would essentially just be the value of *uploadID != nil anyway.
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.
Makes sense to me, thanks :) I'll add some comments.
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.
Done,
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.
So I'm wondering, if we should return something like this here instead of nil, nil @uhthomas. This will at least provide some signal to upstream API consumer of this function that the upload has not been found and prevent potential accidental nil memory access panics 🤷♂️
| return nil, nil | |
| return nil, storagedriver.Error{ | |
| DriverName: driverName, | |
| Detail: fmt.Errorf("no in-progress upload found for empty file at path %s", path), | |
| } |
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 nil upload ID is being used as a valid value. There is only one consumer of this function and it does not fail or propagate the error, instead, it will create a new upload instead. The Writer function would need to explicitly handle this error instead, and would be messy without something a bit more structured?
So instead of checking uploadID == nil it would need to instead check if the error is a storagedriver.Error and then check if err.Detail looks like "no in-progress upload found"? I'm not sure it even should be an error if there is no in progress upload, it's expected.
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.
There is only one consumer of this function
At the moment. Technically, it's not an error per se, I agree, I'm just trying to be a good citizen to future generations 😄
| return nil, nil | ||
| } | ||
|
|
||
| func (d *driver) listParts(ctx context.Context, path string, uploadID *string) (parts []*s3.Part, err error) { |
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.
Similar to my previous comment regarding named returns: let's avoid them if possible; saving an extra line of slice var declaration is not worth it here IMHO.
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.
+1
d3462c6 to
d225efe
Compare
|
@uhthomas can you also please stop squashing while the PR is being reviewed? It's hard to track changes that way. We'll squash it before the MR is merged. |
d225efe to
74a1a6b
Compare
Sorry - it's what I'm used to at work and for other open source projects. I just amend my commits and force push rather than creating a long tail of commits. The diffs are still visible in the PR history if needed. |
Sure, but please don't do it in this project. We can't be looking through the PR comment feed for commit history. The PR commit history tab is there for a reason. |
The logic is identical, but has been separated out and reorganised for clarity. Signed-off-by: Thomas Way <[email protected]>
74a1a6b to
052404a
Compare
| if uploadID != nil { | ||
| return uploadID, nil | ||
| } | ||
| return nil, storagedriver.PathNotFoundError{Path: path} |
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.
Just some questions about this behavior here - this is basically saying that if there is no multipart upload at the path, but there were results then a PathNotFoundError should be returned? Is it common for there to be multiple uploads at the path which don't exactly match the request key? Why is it fine if there aren't already in-progress uploads?
Should the logic change to:
if !empty && uploadID != nilMaybe I'm missing something? If I am, then I'd like to document it!
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.
Just some questions about this behavior here - this is basically saying that if there is no multipart upload at the path, but there were results then a PathNotFoundError should be returned?
IIRC this handles the situation where upload purging is cleaning up failed uploads 🤔
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.
LGTM. @thaJeztah @Jamstah PTAL 🙇♂️
|
Thank you again for your time :) I appreciate you reviewing this. |
| } | ||
| return true | ||
| }); err != nil { | ||
| return nil, fmt.Errorf("list multipart uploads pages: %w", err) |
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.
| return nil, fmt.Errorf("list multipart uploads pages: %w", err) | |
| return nil, fmt.Errorf("failed to list multipart uploads pages: %w", err) |
| if key != *multi.Key { | ||
| continue | ||
| } | ||
| func (d *driver) inProgressUpload(ctx context.Context, path string) (uploadID *string, err error) { |
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.
I think we could compare our opinions on code documentation using named returns all day -- @milosgajdos is stating that precedent has been set in the repo to not use named returns so it makes sense to just follow suite here.
The logic is identical, but has been separated out and reorganised for clarity.
Whilst working on #4424, I found it really hard to understand the intention of what was happening, how and why. Hopefully this makes it more legible and easier to maintain.