[SERVER-1376] Yield in QueryPlanSet Created: 07/Jul/10  Updated: 12/Jul/16  Resolved: 08/Jul/10

Status: Closed
Project: Core Server
Component/s: None
Affects Version/s: None
Fix Version/s: 1.5.5

Type: Bug Priority: Critical - P2
Reporter: Eliot Horowitz (Inactive) Assignee: Aaron Staple
Resolution: Done Votes: 0
Labels: None
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified

Issue Links:
Depends
Operating System: ALL
Participants:

 Description   

if finding the first object is slow, update doesn't yield.

Constructors should be instantanous

only next() should iterate,

(gdb)
#0 std::vector<boost::shared_ptr<mongo::QueryOp>, std::allocator<boost::shared_ptr<mongo::QueryOp> > >::size (this=0x0) at stl_vector.h:399
#1 0x000000010009f9f2 in mongo::QueryPlanSet::Runner::run (this=0x101708e30) at db/queryoptimizer.cpp:551
#2 0x00000001000a1e65 in mongo::QueryPlanSet::runOp (this=0x101011f40, op=@0x101011710) at db/queryoptimizer.cpp:460
#3 0x00000001000a2175 in mongo::MultiPlanScanner::runOpOnce (this=0x101010b70, op=@0x101011710) at db/queryoptimizer.cpp:642
#4 0x000000010006fdd6 in mongo::MultiPlanScanner::runOpOnce<mongo::MultiCursor::CursorOp> (this=0x101010b70, op=@0x101011710) at queryoptimizer.h:266
#5 0x000000010006ccc5 in mongo::MultiCursor::nextClause (this=0x1010117b0) at queryoptimizer.h:366
#6 0x000000010006db75 in mongo::MultiCursor::MultiCursor (this=0x1010117b0, ns=0x101814a14 "mongo-test.perf", pattern=@0x1017097f0, order=@0x101709580, op=@0x101709620) at queryoptimizer.h:308
#7 0x0000000100148e8a in mongo::_updateObjects (god=false, ns=0x101814a14 "mongo-test.perf", updateobj=@0x101709930, patternOrig=@0x1017097f0, upsert=false, multi=false, logop=true, debug=@0x108000a70) at db/update.cpp:896
#8 0x000000010014a61b in mongo::updateObjects (ns=0x101814a14 "mongo-test.perf", updateobj=@0x101709930, patternOrig=@0x101709910, upsert=false, multi=false, logop=true, debug=@0x108000a70) at db/update.cpp:1109
#9 0x00000001001b2f01 in mongo::receivedUpdate (m=@0x101709df0, op=@0x108000820) at db/instance.cpp:455
#10 0x00000001001b4bd2 in mongo::assembleResponse (m=@0x101709df0, dbresponse=@0x101709d40, client=@0x108000318) at db/instance.cpp:323
#11 0x000000010023ded3 in mongo::connThread () at db/db.cpp:247
#12 0x00000001000de25d in boost::detail::thread_data<void ()>::run (this=0x108000420) at thread.hpp:56
#13 0x0000000100def404 in thread_proxy ()
#14 0x00007fff8280d456 in _pthread_start ()



 Comments   
Comment by Eliot Horowitz (Inactive) [ 07/Jul/10 ]

Ok that's a bug

Let's bite the bullet and move to that part to UserQueryOp

Comment by Aaron Staple [ 07/Jul/10 ]

I might be missing something, but it looks like there may be an issue with UserQueryOp - multiple UserQueryOps are going to be alive at the same time, each with their own cursors. But not all of them are necessarily going to have client cursors when one of the UserQueryOps yields.

If we fix this by making QueryPlanSet in charge of administering yielding, the same solution will work for Update and Delete. Will take more than an hour to do it.

Comment by Eliot Horowitz (Inactive) [ 07/Jul/10 ]

Do queries work the same way or are those different?

I added yielding in UserQueryOp itself, so perhaps different.

Comment by Eliot Horowitz (Inactive) [ 07/Jul/10 ]

How hard is it to make QueryPLanSet yield?

If its more than an hour, lets have remove and update use "best guess"

Comment by Eliot Horowitz (Inactive) [ 07/Jul/10 ]

Ok - lets make an option to QueryPlanSet to yield.

Want an option, because some things could have cached items so need be aware of it.
and a way to find out if it did in fact yield.

Comment by Aaron Staple [ 07/Jul/10 ]

An alternative quick and dirty fix is to have update use a "best guess" plan.

Let me know what you want me to do.

Comment by Aaron Staple [ 07/Jul/10 ]

So, both before and after MultiCursor on an update we did the following:

1) find first match using all plans in parallel
2) continue finding subsequent matches using the best plan

By the time the update implementation has a cursor, 1 has already happened. Making QueryPlanSet, etc yield is a relatively general solution.

Comment by Eliot Horowitz (Inactive) [ 07/Jul/10 ]

Oh - is the issue that's its trying different plans?

Comment by Aaron Staple [ 07/Jul/10 ]

Yielding in UpdateOp is tricky because we'll need to have all the different UpdateOps keep a temp client cursor. I can add an option to QueryPlanSet, etc, to allow yielding while the different plans are running. Will be a bit of work.

Comment by Eliot Horowitz (Inactive) [ 07/Jul/10 ]

Why does the scan have to happen there?

Shouldn't next be instaneous?
I must be missing something...

Don't want to fix in UpdateOp as this similar logic in many places.

Comment by Aaron Staple [ 07/Jul/10 ]

This behavior is the same as we had without the multi cursor. Before MultiCursor we did:

QueryPlanSet qps( ns, patternOrig, BSONObj() );
UpdateOp original;
shared_ptr< UpdateOp > u = qps.runOp( original );

That runOp found the first match, so it could take a while and there was no yielding happening. I could make the constructor for MultiCursor instantaneous, but then when you did init() or next() you would still do a long scan without yielding. I think we can fix this by adding a yield to UpdateOp.

Generated at Thu Feb 08 02:56:51 UTC 2024 using Jira 9.7.1#970001-sha1:2222b88b221c4928ef0de3161136cc90c8356a66.