-
Notifications
You must be signed in to change notification settings - Fork 5
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
fs
, memory
, s3
marker: take context cancellation into account
#76
base: main
Are you sure you want to change the base?
Conversation
fs
, memory
: take context cancellation into accountfs
, memory
, s3
marker: take context cancellation into account
@@ -14,7 +14,7 @@ import ( | |||
// anything and returns no error. | |||
func (b *Backend) setMarker(ctx context.Context, name, etag string, isDel bool) error { | |||
if !b.opt.UseUpdateMarker { | |||
return nil | |||
return ctx.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.
I am struggling a little to understand why ctx.Err() is returned here. The doc above says:
// In case the UseUpdateMarker option is false, this function doesn't do
// anything and returns no error
so returning nil seems to better match that description?
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.
Added two comments but none that prevents a merge from my side.
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.
Contexts exist to cancel or prevent long expensive operations, typically network operations.
The context package introduction puts it like this:
Package context defines the Context type, which carries deadlines, cancellation signals, and other request-scoped values across API boundaries and between processes. Incoming requests to a server should create a Context, and outgoing calls to servers should accept a Context.
None of the os.*
functions for filesystem access take any context, and checking it in the fs backend feels a bit artificial. For the memory backend it is definitely quite unconventional.
Is there a practical reason for adding all these boilerplate checks?
The idea behind that is to honour the Consider the following code: var storage simpleblob.Interface
// ...
ctx, cancel := context.WithCancel(context.Background())
cancel()
err := storage.Delete(ctx, "foo") To the question Has the blob named "foo" been deleted and do we have an error?, the answer is currently It depends on the backend, and this PR aims to make the answer be independent of the backend: An error was returned and the blob was not deleted. More generally, if I call |
Typically cancellation occurs asynchronously from the operation that is covered by the context. If you check at the start of a function and expect that to prevent execution, you are basically introducing a race condition. One cannot expect that just because a function takes a context as a parameter, the function will not do anything if the context is already cancelled. Context were originally an optimization to prevent unnecessary when a client connection was already closed for whatever reason. If the caller wants to ensure that the following code is not executed if the context is already closed, it needs to explicitly perform that check. You cannot expect every single function that receives a context to check it before continuing execution. The context is passed through the stack so that any deeper layer can use it for cancellation, but there is no requirement to do so. If it were, Go code would have to have such boilerplate checks all over the place. |
All function for backends
fs
andmemory
do not use theirctx
parameter. This adds checks forctx.Err()
at the beginning of those.As for
s3
, checkctx
from marker logic even if marker is disabled.