-
Notifications
You must be signed in to change notification settings - Fork 119
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
Race condition in creating directories on PUT #114
Comments
Note that the same problem exists in
Multiple concurrent MKCOL requests targeting the same missing collection could all see a Interestingly, the code here returns status code 405 Method Not Allowed (which I see now is actually the correct code). Therefore, I believe the correct solution here is to add a new throwable exception in the |
I think that would be exceeding the scope of milton's functionality. Milton isnt responsible for transaction handling/isolation etc. Concurrency is intended to be handled in webdav through locking. Most operating system clients use an elaborate sequence of actions to ensure concurrency, eg create a zero byte file with a temp name, lock it, upload to it, then move it to the desired name. In addition there is a feature defined in the webdav spec referred to as the 'lock null' process where a resource can be locked before it exists. Milton fully supports lock-null, but i understand Mac Finder is the only OS client which supports it. |
I think if you have an implementation with concurrency problems the best way to handle it is
|
Thanks for the reply, but I believe we are talking somewhat at cross-purposes. I appreciate that WebDAV support locking; however here I am interested in how Milton supports multiple clients, each issuing a single PUT request. To give you a concrete example: I discovered this problem when attempting to use JMeter to benchmark performance characteristics. My simple test-case has JMeter with a threadgroup (=> simulating multiple clients), where each is uploading a unique file: thread-1 uploads to Each client issues a PUT request at (more or less) the same time, as the test-case starts. This means that the jetty server will process these PUT requests will concurrently, using different threads. The directory Thanks for the hint about lock-null -- I'll check that dCache supports this. However, we have clients that do not lock all resources in the path ( I also don't believe your second solution really solves the problem for a few reasons:
My proposed solution is relatively simple and backwards compatible: update the MakeCollectionableResource interface to allow the method to throw an exception if the resource already exists. |
I think i do understand what you mean. But the example above is invalid. For your JMeter script to be correct it should use locking as dav clients are required to do. Milton's semantics are correct, in that if a resource exists we respond with a 405 as above. Milton tries to take on the burden of complying with protocol requirements rather then imposing that on implmentation developers. So we want to retain the current functionality where we check to see if a resource exists before calling the createCollection method. I dont believe that persisting state across clusters is impractical. There are many good tools for doing this. In fact you need to do this with locks (including lock-null), and you should do it for nonces, for milton to work correctly in a clustered environment. So to summarise
|
Also, you can configure the milton stack to use your own MkColHandler, which could remove the check to see whether the resource exists. Milton is designed to be pluggable for this reason. |
Motivation: When processing a PUT request, milton checks whether parent paths exist and creates them if not. Unfortunately, this process is racy: concurrent PUTs that target the same missing directory risk concurrent createCollection method calls with the same target. If this happens all but one createCollection call will fail, resulting in the corresponding PUT requests failing. The problem is described here: miltonio/milton2#114 Modification: Add a work-around where dCache pretends the createCollection call is successful, allowing the PUT request to succeed. Result: Fix a problem where all but one requests fail, if multiple concurrent PUT requests have directories in the path that do not already exist. Target: master Requires-notes: yes Requires-book: no Request: 5.0 Request: 4.2 Request: 4.1 Request: 4.0 Request: 3.2 Patch: https://rb.dcache.org/r/11480/ Acked-by: Olufemi Adeyemi
Motivation: When processing a PUT request, milton checks whether parent paths exist and creates them if not. Unfortunately, this process is racy: concurrent PUTs that target the same missing directory risk concurrent createCollection method calls with the same target. If this happens all but one createCollection call will fail, resulting in the corresponding PUT requests failing. The problem is described here: miltonio/milton2#114 Modification: Add a work-around where dCache pretends the createCollection call is successful, allowing the PUT request to succeed. Result: Fix a problem where all but one requests fail, if multiple concurrent PUT requests have directories in the path that do not already exist. Target: master Requires-notes: yes Requires-book: no Request: 5.0 Request: 4.2 Request: 4.1 Request: 4.0 Request: 3.2 Patch: https://rb.dcache.org/r/11480/ Acked-by: Olufemi Adeyemi
Motivation: When processing a PUT request, milton checks whether parent paths exist and creates them if not. Unfortunately, this process is racy: concurrent PUTs that target the same missing directory risk concurrent createCollection method calls with the same target. If this happens all but one createCollection call will fail, resulting in the corresponding PUT requests failing. The problem is described here: miltonio/milton2#114 Modification: Add a work-around where dCache pretends the createCollection call is successful, allowing the PUT request to succeed. Result: Fix a problem where all but one requests fail, if multiple concurrent PUT requests have directories in the path that do not already exist. Target: master Requires-notes: yes Requires-book: no Request: 5.0 Request: 4.2 Request: 4.1 Request: 4.0 Request: 3.2 Patch: https://rb.dcache.org/r/11480/ Acked-by: Olufemi Adeyemi
Motivation: When processing a PUT request, milton checks whether parent paths exist and creates them if not. Unfortunately, this process is racy: concurrent PUTs that target the same missing directory risk concurrent createCollection method calls with the same target. If this happens all but one createCollection call will fail, resulting in the corresponding PUT requests failing. The problem is described here: miltonio/milton2#114 Modification: Add a work-around where dCache pretends the createCollection call is successful, allowing the PUT request to succeed. Result: Fix a problem where all but one requests fail, if multiple concurrent PUT requests have directories in the path that do not already exist. Target: master Requires-notes: yes Requires-book: no Request: 5.0 Request: 4.2 Request: 4.1 Request: 4.0 Request: 3.2 Patch: https://rb.dcache.org/r/11480/ Acked-by: Olufemi Adeyemi
Motivation: When processing a PUT request, milton checks whether parent paths exist and creates them if not. Unfortunately, this process is racy: concurrent PUTs that target the same missing directory risk concurrent createCollection method calls with the same target. If this happens all but one createCollection call will fail, resulting in the corresponding PUT requests failing. The problem is described here: miltonio/milton2#114 Modification: Add a work-around where dCache pretends the createCollection call is successful, allowing the PUT request to succeed. Result: Fix a problem where all but one requests fail, if multiple concurrent PUT requests have directories in the path that do not already exist. Target: master Requires-notes: yes Requires-book: no Request: 5.0 Request: 4.2 Request: 4.1 Request: 4.0 Request: 3.2 Patch: https://rb.dcache.org/r/11480/ Acked-by: Olufemi Adeyemi
Motivation: When processing a PUT request, milton checks whether parent paths exist and creates them if not. Unfortunately, this process is racy: concurrent PUTs that target the same missing directory risk concurrent createCollection method calls with the same target. If this happens all but one createCollection call will fail, resulting in the corresponding PUT requests failing. The problem is described here: miltonio/milton2#114 Modification: Add a work-around where dCache pretends the createCollection call is successful, allowing the PUT request to succeed. Result: Fix a problem where all but one requests fail, if multiple concurrent PUT requests have directories in the path that do not already exist. Target: master Requires-notes: yes Requires-book: no Request: 5.0 Request: 4.2 Request: 4.1 Request: 4.0 Request: 3.2 Patch: https://rb.dcache.org/r/11480/ Acked-by: Olufemi Adeyemi
PutHandler
contains the following code:The problem is that, if there are many concurrent requests targeting the same non-existing path then it is possible for a collection that does not exist for
parent.child(path.getName())
to be created by the timemkcol.createCollection(path.getName())
is called.RFC 4918 is a little vague on how MKCOL should react if the entity already exists: it says the request must fail, but does not indicate with which status code. I believe 400 Bad Request (i.e.,
BadRequestException
) is the expected response, despite not being listed in RFC 4918 § 9.3.1. TheMakeCollectionableResource
interface supportsBadRequestException
but the JavaDoc doesn't describe the expectation (i.e., when this exception is to be thrown).Assuming
BadRequestException
is the expected reaction, one way of fixing this would be to catch this exception and retry theparent.child(path.getName())
request.The text was updated successfully, but these errors were encountered: