Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Conversation

@uhthomas
Copy link
Contributor

@uhthomas uhthomas commented Aug 6, 2024

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.

@uhthomas
Copy link
Contributor Author

uhthomas commented Aug 6, 2024

Only concern I have is the use of key vs path (key := d.s3Path(path)). I can't see much consistency, though I imagine key is almost always correct to use.

@uhthomas uhthomas force-pushed the chore-s3-refactor-writer branch from 5ae4619 to cadfbea Compare August 6, 2024 10:08
@uhthomas
Copy link
Contributor Author

uhthomas commented Aug 6, 2024

Thanks for running the tests! As suspected, there was some stuff which had to be changed regarding key versus path. I've fixed that and have verified the failing test now works as expected locally.

@uhthomas uhthomas force-pushed the chore-s3-refactor-writer branch 4 times, most recently from 9aeacd6 to d29ef83 Compare August 6, 2024 11:19
@uhthomas
Copy link
Contributor Author

uhthomas commented Aug 6, 2024

Okay, I tried using key everywhere to avoid calling d.s3Path a bunch, but there are some edge cases and I'm not keen to change existing behavior. Should be good now.

@uhthomas uhthomas force-pushed the chore-s3-refactor-writer branch 3 times, most recently from 3909019 to d3462c6 Compare August 6, 2024 17:36
Copy link
Member

@milosgajdos milosgajdos left a 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) {
Copy link
Member

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.

Copy link
Contributor Author

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)

Copy link
Member

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.

Copy link
Contributor Author

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) {

Copy link
Collaborator

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
Copy link
Member

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.

Copy link
Contributor Author

@uhthomas uhthomas Aug 8, 2024

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?

Copy link
Member

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)

Copy link
Contributor Author

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.

d29ef83

Copy link
Contributor Author

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.

Copy link
Contributor Author

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.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done,

Copy link
Member

@milosgajdos milosgajdos Aug 29, 2024

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 🤷‍♂️

Suggested change
return nil, nil
return nil, storagedriver.Error{
DriverName: driverName,
Detail: fmt.Errorf("no in-progress upload found for empty file at path %s", path),
}

Copy link
Contributor Author

@uhthomas uhthomas Aug 29, 2024

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.

Copy link
Member

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) {
Copy link
Member

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.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1

@uhthomas uhthomas force-pushed the chore-s3-refactor-writer branch from d3462c6 to d225efe Compare August 8, 2024 14:51
@milosgajdos
Copy link
Member

@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.

@uhthomas uhthomas force-pushed the chore-s3-refactor-writer branch from d225efe to 74a1a6b Compare August 8, 2024 20:02
@uhthomas
Copy link
Contributor Author

uhthomas commented Aug 8, 2024

@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.

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.

@milosgajdos
Copy link
Member

Sorry - it's what I'm used to at work and for other open source projects

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]>
@uhthomas uhthomas force-pushed the chore-s3-refactor-writer branch from 74a1a6b to 052404a Compare August 9, 2024 18:06
if uploadID != nil {
return uploadID, nil
}
return nil, storagedriver.PathNotFoundError{Path: path}
Copy link
Contributor Author

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 != nil

Maybe I'm missing something? If I am, then I'd like to document it!

Copy link
Member

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 🤔

Copy link
Member

@milosgajdos milosgajdos left a 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 🙇‍♂️

@milosgajdos milosgajdos requested a review from squizzi August 9, 2024 18:33
@uhthomas
Copy link
Contributor Author

uhthomas commented Aug 9, 2024

Thank you again for your time :) I appreciate you reviewing this.

@milosgajdos milosgajdos requested a review from corhere August 14, 2024 15:11
}
return true
}); err != nil {
return nil, fmt.Errorf("list multipart uploads pages: %w", err)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
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) {
Copy link
Collaborator

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants