Closed tunguski closed 6 years ago
Can you please try with latest snapshot build?
We fixed an issue related to a not thread safe class...
Could you specify what version should I use in docker-compose to do that? If it is manual process is there instruction?
I've built branch 3.0.x (7adcae0497683057f83f0ed37b8372fd6dbd4d48), added result to docker-compose (after small modification in Dockerfile - removed downloading, take artifact from local file).
It is possible that this problem is fixed as I couldn't reproduce the bug. Still it is only a manual testing and I cannot confirm reliably.
There is one more thing that seems problematic. Some requests report duplicate key. It is strange as I do only PUTs assuming that it is UPSERT. The problem seems to be corelated as it is only once in a while and next GET requests work fine.
Here is a sample log I've encountered:
restheart | 22:50:12.863 [XNIO-1 task-1] INFO o.r.handlers.RequestLoggerHandler - GET http://localhost:8888/testdb/games/ttt from /172.18.0.1:58206 => status=200 elapsed=3ms contentLength=4487 username=admin roles=[users, admins]
restheart | 22:50:12.875 [XNIO-1 task-3] INFO o.r.handlers.RequestLoggerHandler - PUT http://localhost:8888/testdb/games/ttt from /172.18.0.1:58210 => status=200 elapsed=6ms contentLength=0 username=admin roles=[users, admins]
restheart | 22:50:12.883 [XNIO-1 task-4] INFO o.r.handlers.RequestLoggerHandler - GET http://localhost:8888/testdb/games/ttt from /172.18.0.1:58214 => status=200 elapsed=2ms contentLength=4487 username=admin roles=[users, admins]
restheart | 22:50:13.145 [XNIO-1 task-6] INFO o.r.handlers.RequestLoggerHandler - GET http://localhost:8888/testdb/games/ttt from /172.18.0.1:58226 => status=200 elapsed=4ms contentLength=4487 username=admin roles=[users, admins]
restheart | 22:50:13.146 [XNIO-1 task-5] INFO o.r.handlers.RequestLoggerHandler - GET http://localhost:8888/testdb/games/ttt from /172.18.0.1:58230 => status=200 elapsed=3ms contentLength=4487 username=admin roles=[users, admins]
restheart | 22:50:13.160 [XNIO-1 task-8] ERROR org.restheart.handlers.ErrorHandler - Error handling the request
restheart | com.mongodb.MongoCommandException: Command failed with error 11000: 'E11000 duplicate key error collection: testdb.games index: _id_ dup key: { : "ttt" }' on server mongodb:27017. The full response is { "ok" : 0.0, "errmsg" : "E11000 duplicate key error collection: testdb.games index: _id_ dup key: { : \"ttt\" }", "code" : 11000, "codeName" : "DuplicateKey" }
restheart | at com.mongodb.connection.ProtocolHelper.getCommandFailureException(ProtocolHelper.java:115)
restheart | at com.mongodb.connection.CommandProtocol.execute(CommandProtocol.java:114)
restheart | at com.mongodb.connection.DefaultServer$DefaultServerProtocolExecutor.execute(DefaultServer.java:168)
restheart | at com.mongodb.connection.DefaultServerConnection.executeProtocol(DefaultServerConnection.java:289)
restheart | at com.mongodb.connection.DefaultServerConnection.command(DefaultServerConnection.java:176)
restheart | at com.mongodb.operation.CommandOperationHelper.executeWrappedCommandProtocol(CommandOperationHelper.java:216)
restheart | at com.mongodb.operation.CommandOperationHelper.executeWrappedCommandProtocol(CommandOperationHelper.java:153)
restheart | at com.mongodb.operation.FindAndUpdateOperation$1.call(FindAndUpdateOperation.java:335)
restheart | at com.mongodb.operation.OperationHelper.withConnectionSource(OperationHelper.java:422)
restheart | at com.mongodb.operation.OperationHelper.withConnection(OperationHelper.java:413)
restheart | at com.mongodb.operation.FindAndUpdateOperation.execute(FindAndUpdateOperation.java:331)
restheart | at com.mongodb.Mongo.execute(Mongo.java:845)
restheart | at com.mongodb.Mongo$2.execute(Mongo.java:828)
restheart | at com.mongodb.MongoCollectionImpl.findOneAndUpdate(MongoCollectionImpl.java:435)
restheart | at org.restheart.db.DAOUtils.updateDocument(DAOUtils.java:163)
restheart | at org.restheart.db.DAOUtils.updateDocument(DAOUtils.java:100)
restheart | at org.restheart.db.DocumentDAO.upsertDocument(DocumentDAO.java:109)
restheart | at org.restheart.handlers.document.PutDocumentHandler.handleRequest(PutDocumentHandler.java:116)
restheart | at org.restheart.handlers.PipedHttpHandler.next(PipedHttpHandler.java:136)
restheart | at org.restheart.handlers.metadata.BeforeWriteCheckMetadataHandler.handleRequest(BeforeWriteCheckMetadataHandler.java:79)
restheart | at org.restheart.handlers.PipedHttpHandler.next(PipedHttpHandler.java:136)
restheart | at org.restheart.handlers.metadata.AbstractTransformerMetadataHandler.handleRequest(AbstractTransformerMetadataHandler.java:63)
restheart | at org.restheart.handlers.RequestDispacherHandler.handleRequest(RequestDispacherHandler.java:468)
restheart | at org.restheart.handlers.injectors.CollectionPropsInjectorHandler.handleRequest(CollectionPropsInjectorHandler.java:98)
restheart | at org.restheart.handlers.PipedHttpHandler.next(PipedHttpHandler.java:136)
restheart | at org.restheart.handlers.injectors.DbPropsInjectorHandler.handleRequest(DbPropsInjectorHandler.java:92)
restheart | at org.restheart.handlers.PipedHttpHandler.next(PipedHttpHandler.java:136)
restheart | at org.restheart.handlers.injectors.AccountInjectorHandler.handleRequest(AccountInjectorHandler.java:56)
restheart | at org.restheart.handlers.PipedHttpHandler.next(PipedHttpHandler.java:136)
restheart | at org.restheart.security.handlers.AccessManagerHandler.handleRequest(AccessManagerHandler.java:55)
restheart | at org.restheart.handlers.PipedHttpHandler.next(PipedHttpHandler.java:136)
restheart | at org.restheart.security.handlers.AuthTokenInjecterHandler.handleRequest(AuthTokenInjecterHandler.java:70)
restheart | at org.restheart.handlers.PipedHttpHandler.next(PipedHttpHandler.java:136)
restheart | at org.restheart.security.handlers.AuthenticationCallHandler.handleRequest(AuthenticationCallHandler.java:54)
restheart | at org.restheart.handlers.PipedHttpHandler.next(PipedHttpHandler.java:136)
restheart | at org.restheart.security.handlers.AuthenticationConstraintHandler.handleRequest(AuthenticationConstraintHandler.java:55)
restheart | at org.restheart.handlers.PipedHttpHandler.next(PipedHttpHandler.java:136)
restheart | at org.restheart.security.handlers.AuthenticationMechanismsHandler.handleRequest(AuthenticationMechanismsHandler.java:61)
restheart | at org.restheart.handlers.PipedHttpHandler.next(PipedHttpHandler.java:136)
restheart | at org.restheart.security.handlers.SecurityInitialHandler.handleRequest(SecurityInitialHandler.java:85)
restheart | at org.restheart.handlers.PipedHttpHandler.next(PipedHttpHandler.java:136)
restheart | at org.restheart.security.handlers.SecurityHandler.handleRequest(SecurityHandler.java:50)
restheart | at org.restheart.security.handlers.SecurityHandlerDispacher.handleRequest(SecurityHandlerDispacher.java:60)
restheart | at org.restheart.handlers.PipedHttpHandler.next(PipedHttpHandler.java:136)
restheart | at org.restheart.handlers.injectors.BodyInjectorHandler.handleRequest(BodyInjectorHandler.java:334)
restheart | at org.restheart.handlers.PipedHttpHandler.next(PipedHttpHandler.java:136)
restheart | at org.restheart.handlers.OptionsHandler.handleRequest(OptionsHandler.java:58)
restheart | at org.restheart.handlers.PipedHttpHandler.next(PipedHttpHandler.java:136)
restheart | at org.restheart.handlers.injectors.RequestContextInjectorHandler.handleRequest(RequestContextInjectorHandler.java:647)
restheart | at org.restheart.handlers.PipedHttpHandler.next(PipedHttpHandler.java:136)
restheart | at org.restheart.security.handlers.CORSHandler.handleRequest(CORSHandler.java:88)
restheart | at org.restheart.handlers.RequestLoggerHandler.handleRequest(RequestLoggerHandler.java:87)
restheart | at org.restheart.handlers.PipedHttpHandler.handleRequest(PipedHttpHandler.java:89)
restheart | at io.undertow.server.handlers.PathHandler.handleRequest(PathHandler.java:94)
restheart | at io.undertow.server.handlers.HttpContinueAcceptingHandler.handleRequest(HttpContinueAcceptingHandler.java:78)
restheart | at org.restheart.handlers.ErrorHandler.handleRequest(ErrorHandler.java:69)
restheart | at io.undertow.server.handlers.encoding.EncodingHandler.handleRequest(EncodingHandler.java:66)
restheart | at org.restheart.handlers.GzipEncodingHandler.handleRequest(GzipEncodingHandler.java:74)
restheart | at io.undertow.server.Connectors.executeRootHandler(Connectors.java:210)
restheart | at io.undertow.server.HttpServerExchange$1.run(HttpServerExchange.java:809)
restheart | at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
restheart | at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
restheart | at java.lang.Thread.run(Thread.java:745)
restheart | 22:50:13.160 [XNIO-1 task-7] INFO o.r.handlers.RequestLoggerHandler - PUT http://localhost:8888/testdb/games/ttt from /172.18.0.1:58236 => status=201 elapsed=5ms contentLength=0 username=admin roles=[users, admins]
restheart | 22:50:13.163 [XNIO-1 task-8] INFO o.r.handlers.RequestLoggerHandler - PUT http://localhost:8888/testdb/games/ttt from /172.18.0.1:58238 => status=500 elapsed=8ms contentLength=415 username=admin roles=[users, admins]
restheart | 22:50:13.438 [XNIO-1 task-2] INFO o.r.handlers.RequestLoggerHandler - GET http://localhost:8888/testdb/games/ttt from /172.18.0.1:58254 => status=200 elapsed=2ms contentLength=4487 username=admin roles=[users, admins]
If you are testing with concurrent PUT requests, you might incur in this issues.
As you know, mongodb cannot guarantee atomicity, see write-operations-atomicity in mongodb documentations.
a PUT in restheart actually involves few db operations and concurrent requests might lead to ghost writes. in practical terms, if you really need to update the same document concurrently at milliseconds speed, you might want to use ETAG check feature provided by RESTHeart, see ETAG in RESTHeart documentation
Yes, you are right. Thanks for helpful suggestions!
I've switched to official 3.0.1 version and I see the same problem (404) all the time.
One additional question: what does "contentLength=-1" mean in case of restheart?
restheart | 08:59:44.567 [XNIO-1 task-1] INFO o.r.handlers.RequestLoggerHandler - GET http://localhost:8888/testdb/games/bbb from /172.18.0.1:44456 => status=200 elapsed=5ms contentLength=-1 username=admin roles=[users, admins]
restheart | 08:59:44.585 [XNIO-1 task-6] INFO o.r.handlers.RequestLoggerHandler - PUT http://localhost:8888/testdb/games/bbb from /172.18.0.1:44460 => status=200 elapsed=6ms contentLength=0 username=admin roles=[users, admins]
restheart | 08:59:44.799 [XNIO-1 task-4] INFO o.r.handlers.RequestLoggerHandler - GET http://localhost:8888/testdb/games/bbb from /172.18.0.1:44472 => status=200 elapsed=22ms contentLength=-1 username=admin roles=[users, admins]
restheart | 08:59:44.843 [XNIO-1 task-5] INFO o.r.handlers.RequestLoggerHandler - PUT http://localhost:8888/testdb/games/bbb from /172.18.0.1:44480 => status=200 elapsed=7ms contentLength=0 username=admin roles=[users, admins]
restheart | 08:59:45.062 [XNIO-1 task-2] INFO o.r.handlers.RequestLoggerHandler - GET http://localhost:8888/testdb/games/bbb from /172.18.0.1:44488 => status=200 elapsed=9ms contentLength=-1 username=admin roles=[users, admins]
restheart | 08:59:45.107 [XNIO-1 task-7] INFO o.r.handlers.RequestLoggerHandler - GET http://localhost:8888/testdb/games/bbb from /172.18.0.1:44500 => status=404 elapsed=0ms contentLength=104 username=admin roles=[users, admins]
restheart | 08:59:45.110 [XNIO-1 task-3] INFO o.r.handlers.RequestLoggerHandler - GET http://localhost:8888/testdb/games/bbb from /172.18.0.1:44504 => status=404 elapsed=1ms contentLength=104 username=admin roles=[users, admins]
restheart | 08:59:45.113 [XNIO-1 task-8] INFO o.r.handlers.RequestLoggerHandler - PUT http://localhost:8888/testdb/games/bbb from /172.18.0.1:44496 => status=200 elapsed=8ms contentLength=0 username=admin roles=[users, admins]
restheart | 08:59:45.360 [XNIO-1 task-1] INFO o.r.handlers.RequestLoggerHandler - GET http://localhost:8888/testdb/games/bbb from /172.18.0.1:44552 => status=200 elapsed=13ms contentLength=-1 username=admin roles=[users, admins]
Hi @tunguski,
I thought about it and created the following task in our backlog https://softinstigate.atlassian.net/browse/RH-240
as I wrote, this issue happens because:
and when multiple concurrent write requests are executed against the same document concurrently
The solution proposed in the jira task will address the problem...we are
ps
in the log, contentLength comes from exchange.getRequestContentLength()
. it is the content length of the request. a GET does not have content at all so it is -1
Hi @ujibang , Thanks for your response! To be sure - I've reopened this issue because of 404's during GET's where (as I assume) there is no point in time in which document does not exist in db. I totally accept 500 "duplicate document" response - I should not post it in same issue, sorry.
So even as it may be connected to PUT's, I wanted to confirm that this 404's mean working as expected. If I would get 500's only I would treat it as my problem.
Those 404's on GET worry me. Still as I did not experiment with mongo and a few ms intervals before, I can imagine that is totally outside of Resthart scope.
If this is the behaviour that mongo presents without restheart then I'd treat it as a correct result. But if mongo would return document in that case, I'd treat it as a bug.
Having said that I want to emphasize that I don't have enough experience to make any statement. If you'll find it an expected behaviour, feel free to close this issue.
Thanks for all your work!
@ujibang can we close this?
I close this because we have write request serialization in the roadmap. https://softinstigate.atlassian.net/browse/RH-240
also note that mongodb 4.0 is going to introduce Multi-document Transactions (see https://docs.mongodb.com/manual/upcoming/). This will better address this issue.
I'm testing restheart using restheart-docker. My simple app is GETting and PUTing same document all the time. There is no explicit remove operation in this workflow.
The problem is that from time to time I get 404. I cannot understand what's wrong. I'm not sure is it a bug or I'm missing something here. Could someone help me resolve this issue please? I will be happy to provide any input that may help. Below I've described environment and sample log that I see as the output.
There is one 404 in the middle of log. Next GET request is returning proper document for some reason. PUT requests always provide document with single field modified (last user access date). There is no other app connecting to that mongo, no manual requests too.
Thanks in advance!
Environment:
Example restheart log: