Compare commits

...

333 Commits
master ... v1.6

Author SHA1 Message Date
Eliot Horowitz
ca84e8ebf7 cap connection pool size 2011-03-05 21:30:37 -05:00
Eliot Horowitz
3047651c7f debugging for slow server status 2011-02-28 18:41:44 -05:00
Eliot Horowitz
a1810524d6 detect clock skew in DistributedLock SERVER-2584 2011-02-17 19:56:29 -05:00
Eliot Horowitz
de11476677 when map/reduce has no output data, rename anyway SERVER-2394 2011-01-22 01:33:27 -05:00
Eliot Horowitz
5865515aa1 move logOpForSharding message 2011-01-21 18:57:29 -05:00
Alberto Lerner
eaf37fcd7f close quote in message 2011-01-21 17:23:21 -05:00
Alberto Lerner
136ad26166 logOp would emit messages if being called when no active migration is ongoing 2011-01-21 17:17:20 -05:00
Eliot Horowitz
5cfe1eb716 release ClientCursor in removeRange since sometimes the cursor itself is deleted SERVER-2319 2011-01-02 20:30:15 -05:00
Alberto Lerner
5ab2e7d77a a failure in migrate can be because of chunk boundaries being stale 2010-12-29 13:12:47 -05:00
Alberto Lerner
ada376198a SERVER-1979 check max key before accepting a move request 2010-12-29 12:43:14 -05:00
Eliot Horowitz
2f0f69fb65 test timeouts 2010-12-25 02:28:21 -05:00
Eliot Horowitz
87912f1b19 fix test compile 2010-12-25 02:19:03 -05:00
Eliot Horowitz
c71a9ee13b fix test compile 2010-12-25 02:02:59 -05:00
Eliot Horowitz
113c5e3108 fix follow up extent sizing when an int overflow SERVER-2287 2010-12-24 13:33:39 -05:00
Eliot Horowitz
efee57d51b dummy smokeDur target 2010-12-22 00:24:34 -05:00
Eliot Horowitz
aa9b13636f Merge branch 'v1.6' of github.com:mongodb/mongo into v1.6 2010-12-22 00:22:14 -05:00
Eliot Horowitz
8351914c35 post 1.6.5 2010-12-08 09:33:20 -05:00
Eliot Horowitz
0eb017e9b2 BUMP 1.6.5 2010-12-07 17:16:42 -05:00
Dwight
74df9ddc88 crlf 2010-11-27 23:41:50 -05:00
Eliot Horowitz
65ee827e74 post 1.6.5-rc1 2010-11-21 09:45:50 -05:00
Mathias Stearn
ad8c021c54 support sub-second timeouts SERVER-1515 2010-11-20 02:37:38 -05:00
dwight
3f469b5557 typo rs 2010-11-20 01:08:56 -05:00
dwight
eb66a29554 rs fix initial sync oplog application it was grabbing the whole oplog which can be problematic and inefficient 165 2010-11-20 01:02:26 -05:00
Eliot Horowitz
119dba996e Revert "rs fix initial sync oplog application it was grabbing the whole oplog which can be problematic and inefficient 165"
This reverts commit 17338d81b0.
2010-11-20 00:45:54 -05:00
Kristina Chodorow
269c53e84b check for better primary before voting yea SERVER-1987 2010-11-20 00:34:19 -05:00
Kristina Chodorow
e1570627aa display ts for debugging MINOR 2010-11-20 00:31:57 -05:00
Kristina Chodorow
64fd91d00f honor rs config timeout SERVER-2045 2010-11-20 00:16:58 -05:00
Eliot Horowitz
cdbc4eba59 BUMP 1.6.5-rc1 2010-11-20 00:03:20 -05:00
Dwight
c0044d58a7 make ScopedConn idiot-proof (safe from me) 2010-11-20 00:01:20 -05:00
Dwight
30e604c3cc SERVER-2021 rs ScopedConn bug(2) 165 172 2010-11-20 00:00:54 -05:00
Kristina Chodorow
3d0d33f1a9 set empty config asap on startup SERVER-1847 2010-11-20 00:00:49 -05:00
dwight
e6161d10ce rs fix a race condition type bug at mongod startup with electSelf 165 2010-11-19 23:31:37 -05:00
dwight
17338d81b0 rs fix initial sync oplog application it was grabbing the whole oplog which can be problematic and inefficient 165 2010-11-19 23:30:46 -05:00
Eliot Horowitz
e624de4c51 increase timeout on killing 2010-11-19 19:51:04 -05:00
Eliot Horowitz
41bbcdab00 BUMP 1.6.5-rc0 2010-11-19 13:54:24 -05:00
dwight
07f27e6d8f idiot compiler 2010-11-19 13:52:53 -05:00
dwight
94559a6985 SERVER-1671 pair1.js failing 2010-11-19 13:35:47 -05:00
Kristina Chodorow
6d97633a36 add debugging to tests that failed in 1.6
Conflicts:

	jstests/repl/mastermaster1.js
2010-11-15 12:14:54 -05:00
Justin Dearing
d7b885a44f Better cleanup on nt service install.
All the values for --serviceFoo are removed, and the value of --logPath is quoted.

Became apparent while testing SERVER-1590.
2010-11-09 10:56:09 -05:00
Alberto Lerner
6280a73201 SERVER-2068 make sure to use the same thread name 2010-11-08 10:59:21 -05:00
Eliot Horowitz
2dd7f54687 test for SERVER-2068 2010-11-08 10:59:07 -05:00
Eliot Horowitz
8956ac99d0 when cleaning a chunk after migrating, don't store those deletes in the xfer list SERVER-2068 2010-11-08 10:58:41 -05:00
Alberto Lerner
bdf4a9adfe SERVER-1068 test deletions regardless of command line args 2010-11-08 10:58:22 -05:00
Alberto Lerner
6f827308eb SERVER-2068 check on the TO side of a chunk migration before applying deletions 2010-11-08 10:58:03 -05:00
Alberto Lerner
ea90c5d354 SERVER-1858 add chunk info to moveChunk.from and moveChunk.to changelog entries 2010-11-08 10:52:41 -05:00
Kristina Chodorow
7d31376cc3 more tests for SERVER-1347 2010-11-03 17:30:44 -04:00
Kristina Chodorow
0c92fea8d7 fix set with large ints SERVER-1347 2010-11-03 17:30:33 -04:00
Mathias Stearn
e1ef4d5c55 fix lexNumCmp with magic end of marker
Conflicts:

	db/update.cpp
2010-11-03 17:30:07 -04:00
Mathias Stearn
6c5553c4c9 Support more mixed-case cmd names in mongos SERVER-2053 2010-11-02 17:13:15 -04:00
Eliot Horowitz
9514cc8ce7 post 1.6.4 2010-10-26 22:57:40 -04:00
Mathias Stearn
4f5c02f8d9 Plug memory leak SERVER-1827 2010-10-26 15:51:25 -04:00
Alberto Lerner
0737ad6909 SERVER-1979 check max key before requesting a move 2010-10-26 15:51:25 -04:00
Eliot Horowitz
b41a9f678c BUMP 1.6.4 2010-10-26 15:05:55 -04:00
Mathias Stearn
1dcc81e34e mongo_vstudio.cpp update 2010-10-26 01:19:18 -04:00
Mathias Stearn
e9429566d7 SERVER-1615 rs.reconfig() js helper
Conflicts:

	shell/mongo_vstudio.cpp
2010-10-26 01:19:18 -04:00
Mathias Stearn
954574cff3 add rs.remove helper SERVER-1676
Conflicts:

	shell/mongo_vstudio.cpp
2010-10-26 01:19:18 -04:00
Kristina Chodorow
1f57383462 add doc link for bad repl source SERVER-978 2010-10-26 00:32:52 -04:00
Mathias Stearn
ee5a18c6ce Don't use AI_ADDRCONFIG. SERVER-1579 2010-10-25 18:45:03 -04:00
Mathias Stearn
8d79226466 Faster $box queries SERVER-1392 2010-10-20 19:14:08 -04:00
Eliot Horowitz
ebb7c7f705 yield lock during removeRange SERVER-1521 2010-10-13 10:37:17 -04:00
Aaron
13d28aae02 SERVER-1883 expand nested array fields when testing document for match with previous or clause 2010-10-11 23:49:23 -07:00
Aaron
6f0c76a552 SERVER-1883 in or de duping, correctly retrieve nested field for match document 2010-10-11 23:49:10 -07:00
Alberto Lerner
136024a59f Merge branch 'v1.6' of github.com:mongodb/mongo into v1.6 2010-10-08 17:04:11 -04:00
Alberto Lerner
2905ea2e19 better error message 2010-10-08 17:03:39 -04:00
Eliot Horowitz
37063ffd26 better asserts 2010-10-07 22:54:40 -04:00
Mathias Stearn
a39f3a59e9 typo 2010-10-01 13:20:54 -04:00
Eliot Horowitz
4e9c160741 trying to make feature3 more reliable 2010-09-27 09:43:04 -04:00
Eliot Horowitz
6e47ce2fe7 debugging for shardign/features3 2010-09-27 09:41:22 -04:00
Alberto Lerner
d260bd6086 SERVER-1849 allow recreating a recently dropped collection 2010-09-27 08:36:25 -04:00
Alberto Lerner
ae8f18e921 SERVER-1836 don't mention droped colleciton in printShardingStatus 2010-09-27 08:33:42 -04:00
Eliot Horowitz
0d2fbaf50a post 1.6.3 2010-09-23 14:04:43 -04:00
Eliot Horowitz
278bd2ac2f BUMP 1.6.3 2010-09-23 10:32:26 -04:00
Eliot Horowitz
0f4ecabbe4 better serverStatus logging 2010-09-18 23:42:06 -04:00
Eliot Horowitz
268a8a39df fix Future SERVER-1602 2010-09-17 23:55:41 -04:00
Eliot Horowitz
417dd24161 turn down logging level on meta data version mismatch 2010-09-17 11:49:59 -04:00
Eliot Horowitz
45d71a8464 temp safer hashing till remove client id 2010-09-17 01:26:03 -04:00
Eliot Horowitz
61259ea0a3 yield on medianKey 2010-09-15 22:05:16 -04:00
Eliot Horowitz
4b18b7d113 collection.getMongo 2010-09-15 17:20:23 -04:00
Eliot Horowitz
53c38f0c8c test for SERVER-1755 2010-09-15 17:18:47 -04:00
dwight
f6c66f106c minor help text 2010-09-15 15:01:18 -04:00
Kyle Banker
cfeb9c90fd SERVER-1598 rs getlasterror default test refinement 2010-09-15 15:00:54 -04:00
dwight
5ecb7b97d2 rs better fatal handling 2010-09-15 14:57:55 -04:00
dwight
20b546ae70 crlf 2010-09-15 14:57:47 -04:00
dwight
46df3e603c rs honor RS_FATAL in sync thread 2010-09-15 14:57:40 -04:00
dwight
5dfac589ee cleaning 2010-09-15 14:57:34 -04:00
dwight
95cffc932f rs cleaning 2010-09-15 14:57:15 -04:00
Eliot Horowitz
66d2187dc9 flush stream after printing back trace 2010-09-15 14:54:21 -04:00
dwight
072042ff1c extraneous newline in logging 2010-09-15 14:53:41 -04:00
dwight
d9a5ccd444 less extraneous shutdown logging 2010-09-15 14:53:32 -04:00
dwight
c0a629af4e lowercase 2010-09-15 14:53:26 -04:00
dwight
a215c88d23 lowercase 2010-09-15 14:53:20 -04:00
dwight
b4007cc561 a little more test 2010-09-15 14:52:21 -04:00
dwight
e317820a56 better test logging; log less pdfile 2010-09-15 14:52:12 -04:00
dwight
559e348e42 log success 2010-09-15 14:51:29 -04:00
dwight
8448c4bdc1 turn off disconnect for now rs 2010-09-15 14:51:22 -04:00
dwight
f808dc9cdc make rs test tolerate dropped connections 2010-09-15 14:51:14 -04:00
dwight
cdd8ed4392 rs close sockets when relinquish primary so clients arent surprised 2010-09-15 14:51:02 -04:00
Dwight
5c512c70a0 cleaning formatting 2010-09-15 14:51:00 -04:00
Dwight
0c434ca442 do not background index when applying a create index operation 2010-09-15 14:50:58 -04:00
Dwight
2bd429278f rs temp rollback 2010-09-15 14:45:13 -04:00
Dwight
4c677b4759 clean up logging. now that we show the thread the indentation wasnt useful 2010-09-15 14:41:05 -04:00
dwight
5191e5f0f5 rawOut more 2010-09-15 14:40:53 -04:00
dwight
b6f400ef69 dont heap allocate in rawOut function when avoidable 2010-09-15 14:40:43 -04:00
Aaron
bb7759ebf8 SERVER-1701 don't try killing master in slave delay test 2010-09-15 14:27:15 -04:00
Dwight
760fd054e3 crazy buildbot warnings 2010-09-15 14:26:42 -04:00
Dwight
c533ddf169 rs potential fix for sync1.js intermittents 163 2010-09-15 14:26:32 -04:00
Dwight
59aa16c9da rs bug fixed was refusing to leave ROLLBACK state after successful rollback on some edge cases 164 2010-09-15 14:26:05 -04:00
dwight
5f26f5b4ab maybe this will make repl10.js run consistently 2010-09-15 14:25:57 -04:00
dwight
89561cea61 more logging for repl10.js 2010-09-15 14:25:49 -04:00
dwight
cdca1fa67d debugging flag was on by mistake which si very bad 2010-09-15 14:25:42 -04:00
dwight
a21c781af0 better debugging for sync1.js 2010-09-15 14:25:36 -04:00
dwight
9e1347233b remove CR 2010-09-15 14:25:30 -04:00
dwight
b02155fdb5 more logging to debugh sync1.js [2] 2010-09-15 14:25:24 -04:00
dwight
7e94f7b712 more logging to debugh sync1.js 2010-09-15 14:25:18 -04:00
dwight
0a455c0978 rs add a new test case 2010-09-15 14:25:12 -04:00
Dwight
598dc75240 make classes noncopyable to be safe. compile db_10.sln 2010-09-15 14:23:00 -04:00
dwight
6c795a18b9 rs checkpoint work 2010-09-15 14:20:00 -04:00
Eliot Horowitz
9f1f49e60b test faster 2010-09-15 14:19:50 -04:00
Eliot Horowitz
7a36dfe910 fix nested CurOp cleaning SERVER-1610 2010-09-15 14:19:42 -04:00
Aaron
955cb04268 SERVER-1610 test 2010-09-15 14:19:42 -04:00
Eliot Horowitz
eb06f74673 some log cleaning 2010-09-15 14:18:42 -04:00
Alberto Lerner
ce4693ad09 compile 2010-09-15 14:14:27 -04:00
dwight
ad4eae22db makemessagingport findable from the Client object 2010-09-15 14:14:22 -04:00
Eliot Horowitz
ba964b908b have to copy BinData in sm in case BSONObj is temp SERVER-1694 2010-09-15 14:12:43 -04:00
Dwight
534d062d76 compile hmmm 2010-09-15 14:06:20 -04:00
Dwight
e95fda9ab8 replset4 less chatty 2010-09-15 14:06:15 -04:00
Dwight
6d0e9e7cdd more config validation at rs startup 2010-09-15 14:06:07 -04:00
Dwight
4c0e61c922 check for extraneous fields in replset member config subobjects 2010-09-15 14:06:02 -04:00
Kyle Banker
8af8d5c04e increase oplog size and better debugging for replset2.js test 2010-09-15 14:03:56 -04:00
Dwight
524eec4c68 replset2 was defining a variable twice -might have been harmless, but fixed 2010-09-15 14:03:12 -04:00
Dwight
eb1a934896 try to add more debugging to snapshot2.js.\ 2010-09-15 14:03:02 -04:00
Dwight
d92825979d more logging snapshot2.js 2010-09-15 14:02:53 -04:00
Eliot Horowitz
56260ff39d increase allowable kill time 2010-09-15 14:01:40 -04:00
Eliot Horowitz
24f373dc27 when using a special index, don't record because may screw up later SERVER-1669 2010-09-15 14:01:29 -04:00
Dwight
01228574ab prettier output for test 2010-09-15 13:59:37 -04:00
Kristina Chodorow
2b229bfa80 test fix 2010-09-15 13:59:26 -04:00
Kristina Chodorow
96371079d8 better var names in test 2010-09-15 13:59:21 -04:00
Dwight
5c5de2a56d SERVER-1612 rs better logging 163 2010-09-15 12:06:16 -04:00
Eliot Horowitz
185713ea36 i think major is a keyword 2010-09-15 12:04:33 -04:00
Eliot Horowitz
09e5bce602 increase shell pipe buffer 2010-09-15 12:04:28 -04:00
Eliot Horowitz
1732fe4bdd don't fail writes when after a split SERVER-1473 2010-09-15 12:04:23 -04:00
Eliot Horowitz
d299a732d5 add if op is write to shardVersionOk definition prep for SERVER-1473 2010-09-15 12:04:19 -04:00
Eliot Horowitz
6b5292d021 opIsWrite( int op ) prep for SERVER-1473 2010-09-15 12:04:13 -04:00
Eliot Horowitz
656fb5d308 remove inf. loop in test 2010-09-15 12:01:58 -04:00
Mathias Stearn
546403b83c typo 2010-09-15 12:01:31 -04:00
Dwight
290973e49a rs rollbac kbetter test 2010-09-15 12:00:11 -04:00
Dwight
05c3b4d8e4 rs more rollback testing 2010-09-15 12:00:04 -04:00
Dwight
a043fc1b7a rs test and fix rollback of deleteindex command 163 2010-09-15 11:59:57 -04:00
Dwight
7ed2ca4ae6 rs rollback work 162 163 2010-09-15 11:59:51 -04:00
Eliot Horowitz
7b0733b872 try to make replacepeer2 more reliable 2010-09-15 11:47:24 -04:00
Dwight
b810c290aa replset2 try to fix 2010-09-15 11:47:15 -04:00
Eliot Horowitz
8d97af4829 justOne for v8 2010-09-15 11:46:40 -04:00
Dwight
e9c6dd49ae more const 2010-09-15 11:46:14 -04:00
Kristina Chodorow
bb57c7b545 update rs test 2010-09-15 11:45:55 -04:00
Eliot Horowitz
c0f01316be fix test 2010-09-15 11:43:23 -04:00
Eliot Horowitz
b777de943f shell support for justOne for removes SERVER-1653 2010-09-15 11:43:16 -04:00
Eliot Horowitz
404e66bc85 new test for SERVER-1652 2010-09-15 11:43:01 -04:00
Alberto Lerner
b4a811fd01 fix typo 2010-09-15 11:42:35 -04:00
dwight
2172f62c33 better error msg 2010-09-15 11:40:14 -04:00
Dwight
25261d2b2b rs on relinquish, go to SECONDARY not RECOVERING. 2010-09-15 11:39:05 -04:00
Dwight
6c83a46495 rs hbmsg is too dumb and sticks forever. making it only show for a short time in the display. needs to be smarter one day. 2010-09-15 11:38:57 -04:00
Dwight
bccaaa9c17 err cleaning 2010-09-15 11:38:46 -04:00
Mike Dirolf
caef13fc81 minor: recursive -> nested 2010-09-15 11:38:20 -04:00
Dwight
7b3339ae9a better error message on corruptioun 2010-09-15 11:37:55 -04:00
Dwight
914d81bd12 more logging to see where this test fails 2010-09-15 11:37:40 -04:00
Eliot Horowitz
a2248dc0b4 fix test 2010-09-15 11:37:24 -04:00
Eliot Horowitz
6ebcef0200 fix compile 2010-09-15 11:37:14 -04:00
Dwight
ddcf03445a rs slaveDelay 162 2010-09-15 11:37:00 -04:00
Dwight
33517de687 rs slaveDelay 162? 2010-09-15 11:36:55 -04:00
Eliot Horowitz
d18284ddc7 fix error codes 2010-09-15 11:34:04 -04:00
Dwight
8414f8b66f hidden rs attribute maybe 162 finished 2010-09-15 11:33:18 -04:00
Dwight
05e38f6271 hidden rs attribute maybe 162 2010-09-15 11:33:12 -04:00
Eliot Horowitz
fb8bbac5d1 lower log verbosity when timing out cursors with $where 2010-09-15 11:33:03 -04:00
Eliot Horowitz
c84d2e1b66 clean up cursor exception handling 2010-09-15 11:32:47 -04:00
dwight
833d720d2d rs towards slaveDelay 162 2010-09-15 11:32:28 -04:00
dwight
b70c0d7f07 line endings 2010-09-15 11:32:21 -04:00
Alberto Lerner
32dab38dac make test more robust 2010-09-15 11:32:08 -04:00
dwight
c665b2d59e try to fix sync1.js 2010-09-15 11:31:45 -04:00
Dwight
1bf1802939 rs rollback better logging for errors 162 2010-09-15 11:31:16 -04:00
Dwight
ed0310bb6f rs dont be in lock while sleeping after an error 162 2010-09-15 11:31:09 -04:00
Dwight
e0f4e8fa11 log cleaning 2010-09-15 11:30:59 -04:00
dwight
49c62c630e log more connticketholder 2010-09-15 11:30:44 -04:00
Dwight
0fb0054bc0 clean logging 2010-09-15 11:30:24 -04:00
Dwight
a498e97f5f rs fix a bug that seems to have been benign but caused confusing logging 162 2010-09-15 11:30:14 -04:00
dwight
3d758307ca rs better logging 2010-09-15 11:29:59 -04:00
Aaron
117c589982 add comments for btree skipping code 2010-09-15 11:29:01 -04:00
Dwight
07294457f5 reIndex command going forward only reindexes the target node, not entire repl set 2010-09-15 11:28:47 -04:00
Eliot Horowitz
fc2281d043 fix test 2010-09-15 11:27:41 -04:00
Eliot Horowitz
ec643451f5 test cleaning/debugging 2010-09-15 11:27:33 -04:00
Dwight
ccaa3b6c55 tweak test 2010-09-15 11:22:40 -04:00
Eliot Horowitz
9c481f7bbe fix compile 2010-09-15 11:19:48 -04:00
Aaron
4b78560deb SERVER-1626 add test 2010-09-15 11:19:37 -04:00
Dwight
d80362c555 rs rollback edge cases 162 2010-09-15 11:19:18 -04:00
dwight
ad3ae36a40 rs proper rollbackid maintenance 162 2010-09-15 11:18:37 -04:00
dwight
d832e39d72 rs rollback 162 work 2010-09-15 11:18:27 -04:00
dwight
4b714a0b6d rs rollback work 162 2010-09-15 11:17:38 -04:00
dwight
e0595a5837 todo note on copyindexes option support lacking in clonecollection 2010-09-15 11:17:32 -04:00
dwight
a033a4645b rs rollback work 162 2010-09-15 11:16:35 -04:00
dwight
4e398824a3 cleaning 2010-09-15 11:16:22 -04:00
dwight
96c9f99504 rs rollback work 162 2010-09-15 11:16:13 -04:00
dwight
78ad0339dc rs log better 2010-09-15 11:13:17 -04:00
dwight
b624760d65 patch: problem with initial sync in 1.6.0 from an idle master. BUG CS-112 2010-09-15 11:13:11 -04:00
dwight
287bb91a7a rs make test better 2010-09-15 11:09:03 -04:00
dwight
eeb99ee970 dbtop more readable 2010-09-15 11:06:25 -04:00
dwight
51405ddcff rs some config validation 2010-09-15 11:05:50 -04:00
Alberto Lerner
e59f0335c7 Give the pinger thread a name. 2010-09-15 11:04:52 -04:00
dwight
71bedc0c8e mutexdebugger fix 2010-09-15 11:03:27 -04:00
dwight
82ef5dd32f turn on test 2010-09-15 11:03:08 -04:00
dwight
bc8021e593 fix getlasterrdefaults rs 2010-09-15 11:03:03 -04:00
Kyle Banker
62ea5606d0 SERVER-1595 minor: rs test fix 2010-09-15 11:02:33 -04:00
Alberto Lerner
ed3fe3f011 Thread sleep doesn't give any upper bound guarantee (test failed sporadicaly). 2010-09-15 10:59:24 -04:00
dwight
c60bbc9a39 rs test 2010-09-15 10:59:05 -04:00
Kyle Banker
a69bfe2c25 SERVER-1598 test getLastErrorDefaults 2010-09-15 10:53:04 -04:00
Kyle Banker
e228949faa SERVER-1564 2010-09-15 10:52:49 -04:00
Kyle Banker
22dd4e68b4 minor: test cleanup 2010-09-15 10:51:15 -04:00
dwight
6444722999 comment 2010-09-15 10:50:21 -04:00
dwight
04a61434dd rs SERVER-1598 getlasterrordefaults 2010-09-15 10:49:57 -04:00
Aaron
52081d1b81 SERVER-1493 extents shouldn't be bigger than files when smallfiles 2010-09-15 10:49:33 -04:00
Mathias Stearn
f068efcf5e better help for mongostat 2010-09-15 10:49:15 -04:00
dwight
db296d0ef8 SERVER-1577 stay primary on some config changes 2010-09-15 10:49:05 -04:00
Kyle Banker
c9d23ed9f7 SERVER-1595 test fix: when removing a replset node, make sure that _id for nodes remains the same 2010-09-15 10:48:56 -04:00
dwight
bc3b8aa4ac rs better logging for rolblack 2010-09-15 10:48:48 -04:00
dwight
2f91eaad44 more logging in rollback 2 2010-09-15 10:48:20 -04:00
dwight
6fb9fbe207 towards SERVER-1577 reconf without losing primary status 2010-09-15 10:48:08 -04:00
dwight
047ccb6d07 remove comment 2010-09-15 10:47:18 -04:00
dwight
ff818c4f61 rs move error checking logic to the right place 161 2010-09-15 10:46:49 -04:00
dwight
e888370242 better logging rs 2010-09-15 10:44:44 -04:00
Alberto Lerner
d0b03a1030 warnings 2010-09-15 10:43:20 -04:00
dwight
2fe3e06391 towards SERVER-1577 reconf without losing primary status transiently 2010-09-15 10:42:35 -04:00
Eliot Horowitz
d37c43f623 fix datasize tests 2010-09-14 22:03:38 -04:00
Eliot Horowitz
1393545a61 start cleaning clientId handling - fixes dups case 2010-09-14 21:50:39 -04:00
Eliot Horowitz
668e149311 try to fix osx 32-bit 2010-09-14 17:35:52 -04:00
Eliot Horowitz
d5793fa9a8 dataSize has an estimate option, chunk uses this SERVER-1545 2010-09-14 15:03:30 -04:00
Alberto Lerner
bf3f03bd89 Merge branch 'v1.6' of github.com:mongodb/mongo into v1.6 2010-09-12 12:09:35 -04:00
Alberto Lerner
70406d6afb SERVER-1781 reset a chunk's modified flag after the chunk info was saved 2010-09-12 12:08:15 -04:00
Wojciech Piekutowski
2f89b7af2e NumberLong shell output changed to NumberLong(111111111111) or NumberLong(11111) (when absolute value < 2^30) SERVER-1659
Signed-off-by: Eliot Horowitz <eliot@10gen.com>
2010-09-08 12:42:09 -04:00
Eliot Horowitz
017247b3dd some safety checks for migrate and will obey killOp 2010-09-07 19:03:19 -04:00
Mathias Stearn
caa2025d77 Replace stdout with logfile SERVER-1727 2010-09-07 14:56:43 -04:00
Mathias Stearn
0dfea63e88 OpenVZ warning SERVER-1668 2010-09-07 14:55:20 -04:00
Eliot Horowitz
97b74a1f33 better handling of closing shard clients if underlying shard connection has died SERVER-1747 2010-09-07 13:50:01 -04:00
Eliot Horowitz
0c2d72f109 don't clean up sharding hooks when closing connections during shutdown, not needed since all will go away 2010-09-07 13:00:30 -04:00
Eliot Horowitz
ded8b8a3a4 don't check shard version twice for update and delete 2010-09-07 12:12:22 -04:00
Eliot Horowitz
81d318339f fix error message 2010-09-07 12:12:16 -04:00
Eliot Horowitz
cbed9de254 better error message 2010-09-07 12:12:08 -04:00
Eliot Horowitz
16de891bba prep 1.6.3 2010-09-01 13:29:35 -04:00
Eliot Horowitz
aef371ecf5 BUMP 1.6.2 2010-09-01 08:50:38 -04:00
Kristina Chodorow
5b66c47327 fix sharding tests 2010-08-31 23:41:17 -04:00
Alberto Lerner
0260ce050b SERVER-1607 more replica set checks before adding shard 2010-08-31 21:21:18 -04:00
Alberto Lerner
3c1fa57776 SERVER-1607 replica set checks before adding a shard 2010-08-31 21:21:06 -04:00
Kristina Chodorow
19a0f996fa tests SERVER-1665 2010-08-31 21:20:58 -04:00
Alberto Lerner
0fda3ce40f SERVER-1607 expose replica set of a ConnectionString 2010-08-31 21:20:16 -04:00
Alberto Lerner
4a9135c3b6 SERVER-1607 isMaster returns the name of the replica set, if appropriate 2010-08-31 21:17:31 -04:00
Eliot Horowitz
0af2db40cf fix test for v1.6 2010-08-31 21:16:07 -04:00
Dwight
f93b0d654f move tests that close the database to slownightly so they dont interfere with other tests running at the same time 2010-08-31 20:18:05 -04:00
Alberto Lerner
9ff3ddc944 SERVER-1611 allow localhost in a replica-set-based shard 2010-08-31 17:38:05 -04:00
Eliot Horowitz
cd47c92322 fix segfault on repl set slave before inited SERVER-1656 1.6 version 2010-08-31 17:36:10 -04:00
Eliot Horowitz
2b869d6dfa no size_t append in 1.6 2010-08-31 17:33:58 -04:00
Dwight
c9feeb823d fix bugs with query yielding 162 2010-08-31 17:28:08 -04:00
Dwight
38da020af0 elim ambiguous call warning/error 2010-08-31 17:27:28 -04:00
dwight
79b5c8023b const is safer 2010-08-31 17:27:14 -04:00
dwight
baa4cb9c04 clientcursor finish last commit 2010-08-31 17:27:04 -04:00
dwight
66befc517c clean up diags clientcursor after changes 2010-08-31 17:26:56 -04:00
dwight
e070747d94 fix an old but serious bug with cursors 162 2010-08-31 17:26:45 -04:00
Eliot Horowitz
921dbd018b major delete issue with multiple dbs 2010-08-31 17:26:42 -04:00
Eliot Horowitz
964b3436ef remove warning when advancing a cursor to the end 2010-08-31 17:25:26 -04:00
Eliot Horowitz
0840daf31a track number of timed out cursors and display in cursorinfo and serverStatus 2010-08-31 17:25:16 -04:00
Dwight
a3dd77e7ec lower risk of collection name collisions 2010-08-31 17:22:30 -04:00
Eliot Horowitz
4a65b51c57 assert when would inf. loop, but probably caused by something else, still looking 2010-08-31 17:21:23 -04:00
Eliot Horowitz
bdfefa42c5 add if debug is on to buildinfo 2010-08-31 17:17:52 -04:00
Eliot Horowitz
625b4c4378 fix docs for pidfilepath SERVER-1706 2010-08-31 17:16:23 -04:00
Eliot Horowitz
4099bc52cc mongo::Query instead of Query for define 2010-08-31 17:15:44 -04:00
Eliot Horowitz
5c6f0dcfbd better debugging for drop errors 2010-08-31 17:15:31 -04:00
Eliot Horowitz
b620e3327e don't log create collection if on replication side SERVER-1707 2010-08-31 11:18:51 -04:00
Kristina Chodorow
92d5eb42af use replica set name for shard id SERVER-1665 2010-08-28 12:01:22 -04:00
Eliot Horowitz
aaae92dedb make web console get query in a thread safe way SERVER-1692 2010-08-26 13:54:32 -04:00
Eliot Horowitz
0e78196fd5 use smuassert instead of uassert SERVER-1661 2010-08-23 13:37:13 -04:00
Eliot Horowitz
6122c120c3 sharded m/r supports scope SERVER-1663 2010-08-23 13:20:50 -04:00
Eliot Horowitz
7b02bf761d fix m/r sort SERVER-1652 2010-08-21 21:24:09 -04:00
Eliot Horowitz
00e9040236 sayPiggyBack for replica set connection SERVER-1647 2010-08-20 14:12:40 -04:00
Eliot Horowitz
f0d0aad23d fix change log 2010-08-20 11:53:19 -04:00
Eliot Horowitz
f6aad0935e remove mechanism to put mongos -> mongod connections in last error id mode 2010-08-19 10:14:01 -04:00
Eliot Horowitz
7093e6e585 1.6.2 prep 2010-08-17 16:02:25 -04:00
Eliot Horowitz
c5f5f9a4f3 stabilize test 2010-08-17 12:28:19 -04:00
Alberto Lerner
19b587d925 Depend less an a time estimate. 2010-08-17 11:49:07 -04:00
Eliot Horowitz
31d81b823d BUMP 1.6.1 2010-08-17 10:04:43 -04:00
Eliot Horowitz
e280c561f1 make sharding/rs test faster 2010-08-17 09:57:17 -04:00
Eliot Horowitz
1a30dad111 turn off test that is different on windows 2010-08-17 09:34:29 -04:00
Eliot Horowitz
3770916e05 SERVER-1626 initial sync bug fix
Conflicts:

	db/repl.cpp
2010-08-16 17:07:08 -04:00
Eliot Horowitz
67159d2583 BackgroundJob::wait bug SERVER-1628
Conflicts:

	util/background.cpp
2010-08-16 17:04:22 -04:00
dwight
81da9cda7f faster 2010-08-16 17:03:38 -04:00
dwight
415c264123 SERVER-1614 2010-08-16 17:02:33 -04:00
Dwight
4454a8a0a0 fix help title 2010-08-16 16:57:23 -04:00
Eliot Horowitz
d1c3edcf33 writeback is ok on slave 2010-08-16 15:48:08 -04:00
Eliot Horowitz
1948efc6a4 cursor paranoia 2010-08-16 14:30:11 -04:00
Eliot Horowitz
c3855123b5 even more migrate debugging 2010-08-16 14:29:59 -04:00
Eliot Horowitz
2976396903 return connection to pool 2010-08-16 14:29:48 -04:00
Eliot Horowitz
aa5d314ae9 compile 2010-08-16 14:29:39 -04:00
Eliot Horowitz
d3b427b96f better transfer error logging 2010-08-16 14:29:29 -04:00
Eliot Horowitz
3de268fcae change error reporting order for robustness 2010-08-16 14:28:53 -04:00
Eliot Horowitz
54239a3676 fix select() timing for os x SERVER-1596 2010-08-16 14:28:12 -04:00
Eliot Horowitz
1d7dfe2868 try to fix select timing on windows SERVER-1596 2010-08-16 14:28:02 -04:00
Eliot Horowitz
f1f53ef3c1 possible chunk matcher fix 2010-08-16 14:27:43 -04:00
Eliot Horowitz
356eeb5a62 make BSONElement::toString 20x faster for double 2010-08-16 14:27:29 -04:00
Eliot Horowitz
2800a96e56 clean up chunk version handling - prep for SERVER-1473 2010-08-16 14:26:12 -04:00
Mathias Stearn
0c8f696e79 be smarter about sleeping 2010-08-16 14:25:59 -04:00
Alberto Lerner
b58d62a194 Bug fix: logChange() does't throw (can be called from destructors 2010-08-16 14:16:58 -04:00
Eliot Horowitz
2ba8ac25f1 CS-112 initial sync problem with traditional replication
Conflicts:

	db/repl.cpp
2010-08-12 16:12:02 -04:00
Mathias Stearn
edb14c522b move log flush code to after errnoWithDescription 2010-08-11 14:43:26 -04:00
Mathias Stearn
af35eebfb6 check return from fwrite SERVER-1578 2010-08-11 14:43:16 -04:00
Mathias Stearn
edffe867a5 distinct should yield even if non-matching. SERVER-1597 2010-08-09 14:45:12 -04:00
Mathias Stearn
0e8ef6bca0 Yield in distinct SERVER-1597 2010-08-09 14:45:03 -04:00
Mathias Stearn
b59584f3dd Support large files in GridFS SERVER-1408 2010-08-09 13:38:43 -04:00
Eliot Horowitz
3cc86177ce fix getMore with sharding+rs in edge case SERVER-1584 2010-08-06 13:25:52 -04:00
Alberto Lerner
dcfab78c4b DistributedLock::unlock() handles partition from config DB 2010-08-05 13:41:01 -04:00
Eliot Horowitz
ba166df412 post 1.6.0 2010-08-05 11:34:06 -04:00
Eliot Horowitz
2c7f164b65 BUMP 1.6.0 2010-08-05 09:32:06 -04:00
Alberto Lerner
53d1c8bbad Bug fix: DefaultDBPort is perfectly valid when transitioning from a non-sharded mongod 2010-08-05 00:16:50 -04:00
Eliot Horowitz
e4fcc800f7 fix serverStatus for replica sets SERVER-1570 2010-08-04 16:03:32 -04:00
Eliot Horowitz
7abf0580ca when restarting repl set don't blow away directories
Conflicts:

	shell/servers.js
2010-08-04 16:00:06 -04:00
Eliot Horowitz
ae1e0804da fix upsert with $atomic SERVER-1568 2010-08-04 15:15:30 -04:00
Mathias Stearn
50b7bbe934 Low-verbosity sharded explain() SERVER-1562 2010-08-04 13:30:47 -04:00
Eliot Horowitz
fd26b536e9 clean up data files after sharding/replset tests 2010-08-04 12:33:13 -04:00
Dwight
6f6aa20e92 trying to fix SERVER-1483 2010-08-04 12:13:38 -04:00
Dwight
55937a8f3e sort members in replSetGetStatus output for easy reading 2010-08-04 12:11:18 -04:00
Richard Kreuter
8947d06986 Remove C++ driver from RPM specfile. 2010-08-04 11:54:00 -04:00
Dwight
8c095b2cb2 make error msgs better 2010-08-04 11:53:56 -04:00
Dwight
2e6aeb0229 extraneous logging 2010-08-04 11:53:52 -04:00
Dwight
cb661f73fd allow a member down during a config change 2010-08-04 11:53:44 -04:00
Eliot Horowitz
63f894763d fix sorting if sort field not included in projection SERVER-1561 2010-08-04 11:53:36 -04:00
Eliot Horowitz
2c3d88336e allow get last errors blocking on w to be killed 2010-08-04 10:20:16 -04:00
Eliot Horowitz
c542dbd78a when access namespace for the first time, prep all connections SERVER-1560 2010-08-04 10:17:17 -04:00
Eliot Horowitz
b5ce278c18 fix type SERVER-1563 2010-08-04 09:39:16 -04:00
Eliot Horowitz
a432ac592e 1.6.0-pre- marker 2010-08-03 22:18:44 -04:00
175 changed files with 6007 additions and 3400 deletions

View File

@ -1243,7 +1243,7 @@ elif not onlyServer:
shellEnv["CPPPATH"].remove( "/usr/64/include" )
shellEnv["LIBPATH"].remove( "/usr/64/lib" )
shellEnv.Append( CPPPATH=filterExists(["/sw/include" , "/opt/local/include"]) )
shellEnv.Append( LIBPATH=filterExists(["/sw/lib/", "/opt/local/lib" , "/usr/lib"]) )
shellEnv.Append( LIBPATH=filterExists(["/sw/lib/", "/opt/local/lib" , "/usr/lib", "/usr/local/lib" ]) )
l = shellEnv["LIBS"]
@ -1361,6 +1361,9 @@ smokeEnv.AlwaysBuild( "addMongodReqNoJsTargets" )
smokeEnv.Alias( "smokeAllNoJs", [ "smoke", "mongosTest", "addMongodReqNoJsTargets" ] )
smokeEnv.AlwaysBuild( "smokeAllNoJs" )
# dummy smokeDur for 1.6
smokeEnv.Alias( "smokeDur" , "util/concurrency/" )
def recordPerformance( env, target, source ):
from buildscripts import benchmark_tools
global perftest

View File

@ -511,7 +511,7 @@ private:
}
}
/** Retrieve int value for the element safely. Zero returned if not a number. */
/** Retrieve int value for the element safely. Zero returned if not a number. Converted to int if another numeric type. */
inline int BSONElement::numberInt() const {
switch( type() ) {
case NumberDouble:

View File

@ -387,16 +387,7 @@ namespace mongo {
}
break;
case NumberDouble:
{
stringstream tmp;
tmp.precision( 16 );
tmp << number();
string n = tmp.str();
s << n;
// indicate this is a double:
if( strchr(n.c_str(), '.') == 0 && strchr(n.c_str(), 'E') == 0 && strchr(n.c_str(), 'N') == 0 )
s << ".0";
}
s.appendDoubleNice( number() );
break;
case NumberLong:
s << _numberLong();

View File

@ -40,7 +40,7 @@ namespace mongo {
BSON object format:
\code
code
<unsigned totalSize> {<byte BSONType><cstring FieldName><Data>}* EOO
totalSize includes itself.

View File

@ -164,6 +164,7 @@ namespace mongo {
#define SBNUM(val,maxSize,macro) \
int prev = _buf.l; \
int z = sprintf( _buf.grow(maxSize) , macro , (val) ); \
assert( z >= 0 ); \
_buf.l = prev + z; \
return *this;
@ -197,6 +198,17 @@ namespace mongo {
}
#undef SBNUM
void appendDoubleNice( double x ){
int prev = _buf.l;
char * start = _buf.grow( 32 );
int z = sprintf( start , "%.16g" , x );
assert( z >= 0 );
_buf.l = prev + z;
if( strchr(start, '.') == 0 && strchr(start, 'E') == 0 && strchr(start, 'N') == 0 ){
write( ".0" , 2 );
}
}
void write( const char* buf, int len){
memcpy( _buf.grow( len ) , buf , len );
}

View File

@ -87,8 +87,17 @@ namespace mongo {
delete c;
return;
}
scoped_lock L(_mutex);
_pools[host].pool.push(c);
{
scoped_lock L(_mutex);
if ( _pools[host].pool.size() < 50 ) {
_pools[host].pool.push(c);
return;
}
}
// if we get here it means we didn't add for some reason
delete c;
}
void addHook( DBConnectionHook * hook );
void appendInfo( BSONObjBuilder& b );

View File

@ -502,7 +502,7 @@ namespace mongo {
if ( !p->connect(*server) ) {
stringstream ss;
ss << "couldn't connect to server " << _serverString << '}';
ss << "couldn't connect to server " << _serverString;
errmsg = ss.str();
failed = true;
return false;
@ -1063,6 +1063,18 @@ namespace mongo {
return checkMaster()->findOne(a,b,c,d);
}
bool DBClientReplicaSet::isMember( const DBConnector * conn ) const {
if ( conn == this )
return true;
for ( unsigned i=0; i<_conns.size(); i++ )
if ( _conns[i]->isMember( conn ) )
return true;
return false;
}
bool serverAlive( const string &uri ) {
DBClientConnection c( false, 0, 20 ); // potentially the connection to server could fail while we're checking if it's alive - so use timeouts
string err;

View File

@ -106,10 +106,11 @@ namespace mongo {
_finishInit();
}
ConnectionString( ConnectionType type , const vector<HostAndPort>& servers )
: _type( type ) , _servers( servers ){
_finishInit();
}
// TODO Delete if nobody is using
//ConnectionString( ConnectionType type , const vector<HostAndPort>& servers )
// : _type( type ) , _servers( servers ){
// _finishInit();
//}
ConnectionString( ConnectionType type , const string& s , const string& setName = "" ){
_type = type;
@ -156,6 +157,14 @@ namespace mongo {
static ConnectionString parse( const string& url , string& errmsg );
string getSetName() const{
return _setName;
}
vector<HostAndPort> getServers() const {
return _servers;
}
private:
ConnectionString(){
@ -314,7 +323,7 @@ namespace mongo {
/** Typically one uses the QUERY(...) macro to construct a Query object.
Example: QUERY( "age" << 33 << "school" << "UCLA" )
*/
#define QUERY(x) Query( BSON(x) )
#define QUERY(x) mongo::Query( BSON(x) )
/**
interface that handles communication with the db
@ -329,6 +338,8 @@ namespace mongo {
/* used by QueryOption_Exhaust. To use that your subclass must implement this. */
virtual void recv( Message& m ) { assert(false); }
virtual string getServerAddress() const = 0;
};
/**
@ -739,8 +750,6 @@ namespace mongo {
*/
virtual void update( const string &ns , Query query , BSONObj obj , bool upsert = false , bool multi = false );
virtual string getServerAddress() const = 0;
virtual bool isFailed() const = 0;
virtual void killCursor( long long cursorID ) = 0;
@ -758,6 +767,9 @@ namespace mongo {
virtual void say( Message& toSend ) = 0;
virtual ConnectionString::ConnectionType type() const = 0;
/** @return true if conn is either equal to or contained in this connection */
virtual bool isMember( const DBConnector * conn ) const = 0;
}; // DBClientBase
class DBClientReplicaSet;
@ -784,7 +796,7 @@ namespace mongo {
void _checkConnection();
void checkConnection() { if( failed ) _checkConnection(); }
map< string, pair<string,string> > authCache;
int _timeout;
double _timeout;
bool _connect( string& errmsg );
public:
@ -795,7 +807,7 @@ namespace mongo {
@param timeout tcp timeout in seconds - this is for read/write, not connect.
Connect timeout is fixed, but short, at 5 seconds.
*/
DBClientConnection(bool _autoReconnect=false, DBClientReplicaSet* cp=0, int timeout=0) :
DBClientConnection(bool _autoReconnect=false, DBClientReplicaSet* cp=0, double timeout=0) :
clientSet(cp), failed(false), autoReconnect(_autoReconnect), lastReconnectTry(0), _timeout(timeout) { }
/** Connect to a Mongo database server.
@ -892,11 +904,16 @@ namespace mongo {
virtual bool call( Message &toSend, Message &response, bool assertOk = true );
virtual ConnectionString::ConnectionType type() const { return ConnectionString::MASTER; }
virtual bool isMember( const DBConnector * conn ) const { return this == conn; };
virtual void checkResponse( const char *data, int nReturned );
protected:
friend class SyncClusterConnection;
virtual void recv( Message& m );
virtual void sayPiggyBack( Message &toSend );
virtual void checkResponse( const char *data, int nReturned );
};
/** Use this class to connect to a replica set of servers. The class will manage
@ -987,9 +1004,12 @@ namespace mongo {
virtual ConnectionString::ConnectionType type() const { return ConnectionString::SET; }
virtual bool isMember( const DBConnector * conn ) const;
virtual void checkResponse( const char *data, int nReturned ) { checkMaster()->checkResponse( data , nReturned ); }
protected:
virtual void sayPiggyBack( Message &toSend ) { assert(false); }
virtual void checkResponse( const char *data, int nReturned ) { assert(false); }
virtual void sayPiggyBack( Message &toSend ) { checkMaster()->say( toSend ); }
bool isFailed() const {
return _currentMaster == 0 || _currentMaster->isFailed();

View File

@ -193,7 +193,7 @@ namespace mongo {
void DBClientCursor::attach( AScopedConnection * conn ){
assert( _scopedHost.size() == 0 );
assert( connector == conn->get() );
assert( conn->get()->isMember( connector ) );
_scopedHost = conn->getHost();
conn->done();
connector = 0;

View File

@ -47,6 +47,8 @@ namespace mongo {
}
void distLockPingThread( ConnectionString addr ){
setThreadName( "LockPinger" );
static int loops = 0;
while( ! inShutdown() ){
try {
@ -109,9 +111,6 @@ namespace mongo {
bool DistributedLock::lock_try( string why , BSONObj * other ){
// check for recrusive
assert( getState() == 0 );
ScopedDbConnection conn( _conn );
BSONObjBuilder queryBuilder;
@ -136,7 +135,17 @@ namespace mongo {
return false;
}
Date_t elapsed = jsTime() - lastPing["ping"].Date(); // in ms
unsigned long long now = jsTime();
unsigned long long pingTime = lastPing["ping"].Date();
if ( now < pingTime ) {
// clock skew
warning() << "dist_lock has detected clock skew of " << ( pingTime - now ) << "ms" << endl;
conn.done();
return false;
}
unsigned long long elapsed = now - pingTime;
elapsed = elapsed / ( 1000 * 60 ); // convert to minutes
if ( elapsed <= _takeoverMinutes ){
@ -208,18 +217,33 @@ namespace mongo {
if ( ! gotLock )
return false;
_state.set( 1 );
return true;
}
void DistributedLock::unlock(){
ScopedDbConnection conn( _conn );
conn->update( _ns , _id, BSON( "$set" << BSON( "state" << 0 ) ) );
log(1) << "dist_lock unlock: " << conn->findOne( _ns , _id ) << endl;
conn.done();
const int maxAttempts = 3;
int attempted = 0;
while ( ++attempted <= maxAttempts ) {
try {
ScopedDbConnection conn( _conn );
conn->update( _ns , _id, BSON( "$set" << BSON( "state" << 0 ) ) );
log(1) << "dist_lock unlock: " << conn->findOne( _ns , _id ) << endl;
conn.done();
return;
_state.set( 0 );
} catch ( std::exception& e) {
log( LL_WARNING ) << "dist_lock " << _name << " failed to contact config server in unlock attempt "
<< attempted << ": " << e.what() << endl;
sleepsecs(1 << attempted);
}
}
log( LL_WARNING ) << "dist_lock couldn't consumate unlock request. " << "Lock " << _name
<< " will be taken over after " << _takeoverMinutes << " minutes timeout" << endl;
}
}

View File

@ -36,14 +36,6 @@ namespace mongo {
*/
DistributedLock( const ConnectionString& conn , const string& name , unsigned takeoverMinutes = 10 );
int getState(){
return _state.get();
}
bool isLocked(){
return _state.get() != 0;
}
bool lock_try( string why , BSONObj * other = 0 );
void unlock();
@ -54,8 +46,6 @@ namespace mongo {
string _ns;
BSONObj _id;
ThreadLocalValue<int> _state;
};
class dist_lock_try {

View File

@ -66,7 +66,6 @@ namespace mongo {
}
BSONObj GridFS::storeFile( const char* data , size_t length , const string& remoteName , const string& contentType){
massert( 10279 , "large files not yet implemented", length <= 0xffffffff);
char const * const end = data + length;
OID id;
@ -127,8 +126,6 @@ namespace mongo {
if (fd != stdin)
fclose( fd );
massert( 10280 , "large files not yet implemented", length <= 0xffffffff);
return insertFile((remoteName.empty() ? fileName : remoteName), id, length, contentType);
}

View File

@ -328,6 +328,38 @@ namespace mongo {
void ParallelSortClusteredCursor::_finishCons(){
_numServers = _servers.size();
_cursors = 0;
if ( ! _sortKey.isEmpty() && ! _fields.isEmpty() ){
// we need to make sure the sort key is in the project
bool isNegative = false;
BSONObjBuilder b;
{
BSONObjIterator i( _fields );
while ( i.more() ){
BSONElement e = i.next();
b.append( e );
if ( ! e.trueValue() )
isNegative = true;
}
}
{
BSONObjIterator i( _sortKey );
while ( i.more() ){
BSONElement e = i.next();
BSONElement f = _fields.getField( e.fieldName() );
if ( isNegative ){
uassert( 13431 , "have to have sort key in projection and removing it" , f.eoo() );
}
else if ( f.eoo() ){
// add to projection
b.append( e );
}
}
}
_fields = b.obj();
}
}
void ParallelSortClusteredCursor::_init(){
@ -420,37 +452,31 @@ namespace mongo {
}
bool Future::CommandResult::join(){
while ( ! _done )
sleepmicros( 50 );
_thr->join();
assert( _done );
return _ok;
}
void Future::commandThread(){
assert( _grab );
shared_ptr<CommandResult> res = *_grab;
_grab = 0;
ScopedDbConnection conn( res->_server );
res->_ok = conn->runCommand( res->_db , res->_cmd , res->_res );
void Future::commandThread( shared_ptr<CommandResult> res ){
setThreadName( "future" );
try {
ScopedDbConnection conn( res->_server );
res->_ok = conn->runCommand( res->_db , res->_cmd , res->_res );
conn.done();
}
catch ( std::exception& e ){
error() << "Future::commandThread exception: " << e.what() << endl;
res->_ok = false;
}
res->_done = true;
conn.done();
}
shared_ptr<Future::CommandResult> Future::spawnCommand( const string& server , const string& db , const BSONObj& cmd ){
shared_ptr<Future::CommandResult> res;
res.reset( new Future::CommandResult( server , db , cmd ) );
_grab = &res;
boost::thread thr( Future::commandThread );
while ( _grab )
sleepmicros(2);
shared_ptr<Future::CommandResult> res( new Future::CommandResult( server , db , cmd ) );
res->_thr.reset( new boost::thread( boost::bind( Future::commandThread , res ) ) );
return res;
}
shared_ptr<Future::CommandResult> * Future::_grab;
}

View File

@ -274,7 +274,7 @@ namespace mongo {
string _db;
BSONObj _cmd;
boost::thread _thr;
scoped_ptr<boost::thread> _thr;
BSONObj _res;
bool _done;
@ -283,12 +283,9 @@ namespace mongo {
friend class Future;
};
static void commandThread();
static void commandThread( shared_ptr<CommandResult> res );
static shared_ptr<CommandResult> spawnCommand( const string& server , const string& db , const BSONObj& cmd );
private:
static shared_ptr<CommandResult> * _grab;
};

View File

@ -369,4 +369,16 @@ namespace mongo {
// should never need to do this
assert(0);
}
bool SyncClusterConnection::isMember( const DBConnector * conn ) const {
if ( conn == this )
return true;
for ( unsigned i=0; i<_conns.size(); i++ )
if ( _conns[i]->isMember( conn ) )
return true;
return false;
}
}

View File

@ -90,6 +90,8 @@ namespace mongo {
virtual ConnectionString::ConnectionType type() const { return ConnectionString::SYNC; }
virtual bool isMember( const DBConnector * conn ) const;
private:
SyncClusterConnection( SyncClusterConnection& prev );
string _toString() const;

View File

@ -35,16 +35,18 @@
namespace mongo {
Client* Client::syncThread;
mongo::mutex Client::clientsMutex("clientsMutex");
set<Client*> Client::clients; // always be in clientsMutex when manipulating this
boost::thread_specific_ptr<Client> currentClient;
Client::Client(const char *desc) :
Client::Client(const char *desc, MessagingPort *p) :
_context(0),
_shutdown(false),
_desc(desc),
_god(0),
_lastOp(0)
_lastOp(0),
_mp(p)
{
_curOp = new CurOp( this );
scoped_lock bl(clientsMutex);
@ -52,15 +54,21 @@ namespace mongo {
}
Client::~Client() {
delete _curOp;
_god = 0;
if ( _context )
cout << "ERROR: Client::~Client _context should be NULL: " << _desc << endl;
if ( !_shutdown )
cout << "ERROR: Client::shutdown not called: " << _desc << endl;
}
error() << "Client::~Client _context should be null but is not; client:" << _desc << endl;
if ( ! _shutdown ) {
error() << "Client::shutdown not called: " << _desc << endl;
}
scoped_lock bl(clientsMutex);
if ( ! _shutdown )
clients.erase(this);
delete _curOp;
}
void Client::_dropns( const string& ns ){
Top::global.collectionDropped( ns );
@ -75,7 +83,7 @@ namespace mongo {
dropCollection( ns , err , b );
}
catch ( ... ){
log() << "error dropping temp collection: " << ns << endl;
warning() << "error dropping temp collection: " << ns << endl;
}
}
@ -196,12 +204,18 @@ namespace mongo {
if ( doauth )
_auth( lockState );
if ( _client->_curOp->getOp() != dbGetMore ){ // getMore's are special and should be handled else where
switch ( _client->_curOp->getOp() ){
case dbGetMore: // getMore's are special and should be handled else where
case dbUpdate: // update & delete check shard version in instance.cpp, so don't check here as well
case dbDelete:
break;
default: {
string errmsg;
if ( ! shardVersionOk( _ns , errmsg ) ){
if ( ! shardVersionOk( _ns , lockState > 0 , errmsg ) ){
msgasserted( StaleConfigInContextCode , (string)"[" + _ns + "] shard version not ok in Client::Context: " + errmsg );
}
}
}
}
void Client::Context::_auth( int lockState ){
@ -237,7 +251,7 @@ namespace mongo {
string sayClientState(){
Client* c = currentClient.get();
if ( ! c )
if ( !c )
return "no client";
return c->toString();
}
@ -259,6 +273,38 @@ namespace mongo {
}
}
CurOp::~CurOp(){
if ( _wrapped ){
scoped_lock bl(Client::clientsMutex);
_client->_curOp = _wrapped;
}
_client = 0;
}
BSONObj CurOp::query( bool threadSafe ) {
if( querySize() == 1 ) {
return _tooBig;
}
if ( ! threadSafe ){
BSONObj o(_queryBuf);
return o;
}
int size = querySize();
int before = checksum( _queryBuf , size );
BSONObj a(_queryBuf);
BSONObj b = a.copy();
int after = checksum( _queryBuf , size );
if ( before == after )
return b;
return BSON( "msg" << "query changed while capturing" );
}
BSONObj CurOp::infoNoauth( int attempt ) {
BSONObjBuilder b;
b.append("opid", _opNum);
@ -402,7 +448,7 @@ namespace mongo {
tablecell( ss , co.getOp() );
tablecell( ss , co.getNS() );
if ( co.haveQuery() )
tablecell( ss , co.query() );
tablecell( ss , co.query( true ) );
else
tablecell( ss , "" );
tablecell( ss , co.getRemoteString() );

View File

@ -29,27 +29,33 @@
#include "namespace.h"
#include "lasterror.h"
#include "stats/top.h"
//#include "repl/rs.h"
namespace mongo {
extern class ReplSet *theReplSet;
class AuthenticationInfo;
class Database;
class CurOp;
class Command;
class Client;
class MessagingPort;
extern boost::thread_specific_ptr<Client> currentClient;
class Client : boost::noncopyable {
public:
static Client *syncThread;
void iAmSyncThread() {
wassert( syncThread == 0 );
syncThread = this;
}
bool isSyncThread() const { return this == syncThread; } // true if this client is the replication secondary pull thread
static mongo::mutex clientsMutex;
static set<Client*> clients; // always be in clientsMutex when manipulating this
static int recommendedYieldMicros( int * writers = 0 , int * readers = 0 );
/* set _god=true temporarily, safely */
class GodScope {
bool _prev;
public:
@ -148,9 +154,11 @@ namespace mongo {
}
friend class CurOp;
};
}; // class Client::Context
private:
void _dropns( const string& ns );
CurOp * _curOp;
Context * _context;
bool _shutdown;
@ -162,9 +170,9 @@ namespace mongo {
BSONObj _handshake;
BSONObj _remoteId;
void _dropns( const string& ns );
public:
MessagingPort * const _mp;
string clientAddress() const;
AuthenticationInfo * getAuthenticationInfo(){ return &_ai; }
bool isAdmin() { return _ai.isAuthorized( "admin" ); }
@ -174,24 +182,19 @@ namespace mongo {
const char *ns() const { return _context->ns(); }
const char *desc() const { return _desc; }
Client(const char *desc);
Client(const char *desc, MessagingPort *p = 0);
~Client();
void addTempCollection( const string& ns );
void _invalidateDB(const string& db);
static void invalidateDB(const string& db);
static void invalidateNS( const string& ns );
void setLastOp( ReplTime op ) {
_lastOp = op;
}
ReplTime getLastOp() const {
return _lastOp;
}
void setLastOp( ReplTime op ) { _lastOp = op; }
ReplTime getLastOp() const { return _lastOp; }
/* report what the last operation was. used by getlasterror */
void appendLastOp( BSONObjBuilder& b ) {
if( theReplSet ) {
b.append("lastOp" , (long long) _lastOp);
@ -206,14 +209,13 @@ namespace mongo {
/* each thread which does db operations has a Client object in TLS.
call this when your thread starts.
*/
static void initThread(const char *desc);
static Client& initThread(const char *desc, MessagingPort *mp = 0);
/*
this has to be called as the client goes away, but before thread termination
@return true if anything was done
*/
bool shutdown();
/* this is for map/reduce writes */
bool isGod() const { return _god; }
@ -221,13 +223,12 @@ namespace mongo {
friend class CurOp;
string toString() const;
void gotHandshake( const BSONObj& o );
BSONObj getRemoteID() const { return _remoteId; }
BSONObj getHandshake() const { return _handshake; }
};
/** get the Client object for this thread. */
inline Client& cc() {
Client * c = currentClient.get();
assert( c );
@ -237,11 +238,13 @@ namespace mongo {
/* each thread which does db operations has a Client object in TLS.
call this when your thread starts.
*/
inline void Client::initThread(const char *desc) {
inline Client& Client::initThread(const char *desc, MessagingPort *mp) {
setThreadName(desc);
assert( currentClient.get() == 0 );
currentClient.reset( new Client(desc) );
Client *c = new Client(desc, mp);
currentClient.reset(c);
mongo::lastError.initThread();
return *c;
}
inline Client::GodScope::GodScope(){
@ -276,8 +279,5 @@ namespace mongo {
string sayClientState();
inline bool haveClient(){
return currentClient.get() > 0;
}
inline bool haveClient() { return currentClient.get() > 0; }
};

View File

@ -32,27 +32,37 @@
namespace mongo {
CCById ClientCursor::clientCursorsById;
CCByLoc ClientCursor::byLoc;
boost::recursive_mutex ClientCursor::ccmutex;
typedef multimap<DiskLoc, ClientCursor*> CCByLoc;
unsigned ClientCursor::byLocSize() {
CCById ClientCursor::clientCursorsById;
boost::recursive_mutex ClientCursor::ccmutex;
long long ClientCursor::numberTimedOut = 0;
/*static*/ void ClientCursor::assertNoCursors() {
recursive_scoped_lock lock(ccmutex);
return byLoc.size();
if( clientCursorsById.size() ) {
log() << "ERROR clientcursors exist but should not at this point" << endl;
ClientCursor *cc = clientCursorsById.begin()->second;
log() << "first one: " << cc->cursorid << ' ' << cc->ns << endl;
clientCursorsById.clear();
assert(false);
}
}
void ClientCursor::setLastLoc_inlock(DiskLoc L) {
if ( L == _lastLoc )
return;
CCByLoc& bl = byLoc();
if ( !_lastLoc.isNull() ) {
CCByLoc::iterator i = kv_find(byLoc, _lastLoc, this);
if ( i != byLoc.end() )
byLoc.erase(i);
CCByLoc::iterator i = kv_find(bl, _lastLoc, this);
if ( i != bl.end() )
bl.erase(i);
}
if ( !L.isNull() )
byLoc.insert( make_pair(L, this) );
bl.insert( make_pair(L, this) );
_lastLoc = L;
}
@ -76,24 +86,52 @@ namespace mongo {
{
recursive_scoped_lock lock(ccmutex);
for ( CCByLoc::iterator i = byLoc.begin(); i != byLoc.end(); ++i ) {
Database *db = cc().database();
assert(db);
assert( str::startsWith(nsPrefix, db->name) );
for( CCById::iterator i = clientCursorsById.begin(); i != clientCursorsById.end(); ++i ) {
ClientCursor *cc = i->second;
if ( strncmp(nsPrefix, cc->ns.c_str(), len) == 0 )
if( cc->_db != db )
continue;
if ( strncmp(nsPrefix, cc->ns.c_str(), len) == 0 ) {
toDelete.push_back(i->second);
}
}
/*
note : we can't iterate byloc because clientcursors may exist with a loc of null in which case
they are not in the map. perhaps they should not exist though in the future? something to
change???
CCByLoc& bl = db->ccByLoc;
for ( CCByLoc::iterator i = bl.begin(); i != bl.end(); ++i ) {
ClientCursor *cc = i->second;
if ( strncmp(nsPrefix, cc->ns.c_str(), len) == 0 ) {
assert( cc->_db == db );
toDelete.push_back(i->second);
}
}*/
for ( vector<ClientCursor*>::iterator i = toDelete.begin(); i != toDelete.end(); ++i )
delete (*i);
}
}
bool ClientCursor::shouldTimeout( unsigned millis ){
_idleAgeMillis += millis;
return _idleAgeMillis > 600000 && _pinValue == 0;
}
/* called every 4 seconds. millis is amount of idle time passed since the last call -- could be zero */
void ClientCursor::idleTimeReport(unsigned millis) {
readlock lk("");
recursive_scoped_lock lock(ccmutex);
for ( CCByLoc::iterator i = byLoc.begin(); i != byLoc.end(); ) {
CCByLoc::iterator j = i;
for ( CCById::iterator i = clientCursorsById.begin(); i != clientCursorsById.end(); ) {
CCById::iterator j = i;
i++;
if( j->second->shouldTimeout( millis ) ){
numberTimedOut++;
log(1) << "killing old cursor " << j->second->cursorid << ' ' << j->second->ns
<< " idle:" << j->second->idleTime() << "ms\n";
delete j->second;
@ -106,10 +144,12 @@ namespace mongo {
*/
void ClientCursor::informAboutToDeleteBucket(const DiskLoc& b) {
recursive_scoped_lock lock(ccmutex);
RARELY if ( byLoc.size() > 70 ) {
log() << "perf warning: byLoc.size=" << byLoc.size() << " in aboutToDeleteBucket\n";
Database *db = cc().database();
CCByLoc& bl = db->ccByLoc;
RARELY if ( bl.size() > 70 ) {
log() << "perf warning: byLoc.size=" << bl.size() << " in aboutToDeleteBucket\n";
}
for ( CCByLoc::iterator i = byLoc.begin(); i != byLoc.end(); i++ )
for ( CCByLoc::iterator i = bl.begin(); i != bl.end(); i++ )
i->second->c->aboutToDeleteBucket(b);
}
void aboutToDeleteBucket(const DiskLoc& b) {
@ -120,8 +160,11 @@ namespace mongo {
void ClientCursor::aboutToDelete(const DiskLoc& dl) {
recursive_scoped_lock lock(ccmutex);
CCByLoc::iterator j = byLoc.lower_bound(dl);
CCByLoc::iterator stop = byLoc.upper_bound(dl);
Database *db = cc().database();
assert(db);
CCByLoc& bl = db->ccByLoc;
CCByLoc::iterator j = bl.lower_bound(dl);
CCByLoc::iterator stop = bl.upper_bound(dl);
if ( j == stop )
return;
@ -139,6 +182,7 @@ namespace mongo {
for ( vector<ClientCursor*>::iterator i = toAdvance.begin(); i != toAdvance.end(); ++i ){
ClientCursor* cc = *i;
wassert(cc->_db == db);
if ( cc->_doingDeletes ) continue;
@ -157,7 +201,9 @@ namespace mongo {
c->advance();
if ( c->eof() ) {
// advanced to end
// leave ClieneCursor in place so next getMore doesn't fail
// leave ClientCursor in place so next getMore doesn't fail
// still need to mark new location though
cc->updateLocation();
}
else {
wassert( c->refLoc() != dl );
@ -296,6 +342,13 @@ namespace mongo {
int ctmLast = 0; // so we don't have to do find() which is a little slow very often.
long long ClientCursor::allocCursorId_inlock() {
if( 0 ) {
static long long z;
++z;
cout << "TEMP alloccursorid " << z << endl;
return z;
}
long long x;
int ctm = (int) curTimeMillis();
while ( 1 ) {
@ -328,7 +381,13 @@ namespace mongo {
}
void ClientCursor::appendStats( BSONObjBuilder& result ){
recursive_scoped_lock lock(ccmutex);
result.appendNumber("totalOpen", (int)clientCursorsById.size() );
result.appendNumber("clientCursors_size", (int) numCursors());
result.appendNumber("timedOut" , (int)numberTimedOut);
}
// QUESTION: Restrict to the namespace from which this command was issued?
// Alternatively, make this command admin-only?
class CmdCursorInfo : public Command {
@ -339,11 +398,8 @@ namespace mongo {
help << " example: { cursorInfo : 1 }";
}
virtual LockType locktype() const { return NONE; }
bool run(const string&, BSONObj& jsobj, string& errmsg, BSONObjBuilder& result, bool fromRepl ){
recursive_scoped_lock lock(ClientCursor::ccmutex);
result.append("totalOpen", unsigned( ClientCursor::clientCursorsById.size() ) );
result.append("byLocation_size", unsigned( ClientCursor::byLoc.size() ) );
result.append("clientCursors_size", unsigned( ClientCursor::clientCursorsById.size() ) );
bool run(const string& dbname, BSONObj& jsobj, string& errmsg, BSONObjBuilder& result, bool fromRepl ){
ClientCursor::appendStats( result );
return true;
}
} cmdCursorInfo;

View File

@ -45,8 +45,6 @@ namespace mongo {
*/
typedef map<CursorId, ClientCursor*> CCById;
typedef multimap<DiskLoc, ClientCursor*> CCByLoc;
extern BSONObj id_obj;
class ClientCursor {
@ -64,14 +62,13 @@ namespace mongo {
ElapsedTracker _yieldSometimesTracker;
static CCById clientCursorsById;
static CCByLoc byLoc;
static boost::recursive_mutex ccmutex; // must use this for all statics above!
static CursorId allocCursorId_inlock();
static long long numberTimedOut;
static boost::recursive_mutex ccmutex; // must use this for all statics above!
static CursorId allocCursorId_inlock();
public:
static void assertNoCursors();
/* use this to assure we don't in the background time out cursor while it is under use.
if you are using noTimeout() already, there is no risk anyway.
Further, this mechanism guards against two getMore requests on the same cursor executing
@ -139,19 +136,24 @@ namespace mongo {
};
/*const*/ CursorId cursorid;
string ns;
shared_ptr<Cursor> c;
int pos; // # objects into the cursor so far
BSONObj query;
int _queryOptions; // see enum QueryOptions dbclient.h
const string ns;
const shared_ptr<Cursor> c;
int pos; // # objects into the cursor so far
const BSONObj query; // used for logging diags only; optional in constructor
const int _queryOptions; // see enum QueryOptions dbclient.h
OpTime _slaveReadTill;
Database * const _db;
ClientCursor(int queryOptions, shared_ptr<Cursor>& _c, const string& _ns) :
ClientCursor(int queryOptions, shared_ptr<Cursor>& _c, const string& _ns, BSONObj _query = BSONObj()) :
_idleAgeMillis(0), _pinValue(0),
_doingDeletes(false), _yieldSometimesTracker(128,10),
ns(_ns), c(_c),
pos(0), _queryOptions(queryOptions)
pos(0), query(_query),
_queryOptions(queryOptions),
_db( cc().database() )
{
assert( _db );
assert( str::startsWith(_ns, _db->name) );
if( queryOptions & QueryOption_NoCursorTimeout )
noTimeout();
recursive_scoped_lock lock(ccmutex);
@ -308,10 +310,7 @@ namespace mongo {
/**
* @param millis amount of idle passed time since last call
*/
bool shouldTimeout( unsigned millis ){
_idleAgeMillis += millis;
return _idleAgeMillis > 600000 && _pinValue == 0;
}
bool shouldTimeout( unsigned millis );
void storeOpForSlave( DiskLoc last );
void updateSlaveLocation( CurOp& curop );
@ -327,12 +326,18 @@ private:
void noTimeout() {
_pinValue++;
}
multimap<DiskLoc, ClientCursor*>& byLoc() {
return _db->ccByLoc;
}
public:
void setDoingDeletes( bool doingDeletes ){
_doingDeletes = doingDeletes;
}
static void appendStats( BSONObjBuilder& result );
static unsigned byLocSize(); // just for diagnostics
static unsigned numCursors() { return clientCursorsById.size(); }
static void informAboutToDeleteBucket(const DiskLoc& b);
static void aboutToDelete(const DiskLoc& dl);

View File

@ -49,7 +49,7 @@ namespace mongo {
void setConnection( DBClientWithCommands *c ) { conn.reset( c ); }
bool go(const char *masterHost, string& errmsg, const string& fromdb, bool logForRepl, bool slaveOk, bool useReplAuth, bool snapshot);
bool copyCollection( const string& from , const string& ns , const BSONObj& query , string& errmsg , bool copyIndexes = true );
bool copyCollection( const string& from , const string& ns , const BSONObj& query , string& errmsg , bool copyIndexes = true, bool logForRepl = true );
};
/* for index info object:
@ -198,12 +198,12 @@ namespace mongo {
}
}
bool copyCollectionFromRemote(const string& host, const string& ns, const BSONObj& query, string errmsg) {
bool copyCollectionFromRemote(const string& host, const string& ns, const BSONObj& query, string& errmsg, bool logForRepl) {
Cloner c;
return c.copyCollection(host, ns, query, errmsg , /*copyIndexes*/ true);
return c.copyCollection(host, ns, query, errmsg , /*copyIndexes*/ true, logForRepl);
}
bool Cloner::copyCollection( const string& from , const string& ns , const BSONObj& query , string& errmsg , bool copyIndexes ){
bool Cloner::copyCollection( const string& from , const string& ns , const BSONObj& query , string& errmsg , bool copyIndexes, bool logForRepl ) {
auto_ptr<DBClientConnection> myconn;
myconn.reset( new DBClientConnection() );
if ( ! myconn->connect( from , errmsg ) )
@ -223,12 +223,17 @@ namespace mongo {
}
{ // main data
copy( ns.c_str() , ns.c_str() , false , true , false , true , Query(query).snapshot() );
copy( ns.c_str() , ns.c_str() , /*isindex*/false , logForRepl , false , true , Query(query).snapshot() );
}
/* TODO : copyIndexes bool does not seem to be implemented! */
if( !copyIndexes ) {
log() << "ERROR copy collection copyIndexes not implemented? " << ns << endl;
}
{ // indexes
string temp = ctx.db()->name + ".system.indexes";
copy( temp.c_str() , temp.c_str() , true , true , false , true , BSON( "ns" << ns ) );
copy( temp.c_str() , temp.c_str() , /*isindex*/true , logForRepl , false , true , BSON( "ns" << ns ) );
}
return true;
}

View File

@ -45,7 +45,7 @@ namespace mongo {
("bind_ip", po::value<string>(&cmdLine.bind_ip), "comma separated list of ip addresses to listen on - all local ips by default")
("logpath", po::value<string>() , "file to send all output to instead of stdout" )
("logappend" , "append to logpath instead of over-writing" )
("pidfilepath", po::value<string>(), "directory for pidfile (if not set, no pidfile is created)")
("pidfilepath", po::value<string>(), "full path to pidfile (if not set, no pidfile is created)")
#ifndef _WIN32
("fork" , "fork server process" )
#endif

View File

@ -85,9 +85,7 @@ namespace mongo {
Note if run() returns false, we do NOT log.
*/
virtual bool logTheOp() {
return false;
}
virtual bool logTheOp() { return false; }
virtual void help( stringstream& help ) const;

View File

@ -85,13 +85,7 @@ namespace mongo {
int querySize() const { return *((int *) _queryBuf); }
bool haveQuery() const { return querySize() != 0; }
BSONObj query() {
if( querySize() == 1 ) {
return _tooBig;
}
BSONObj o(_queryBuf);
return o;
}
BSONObj query( bool threadSafe = false);
void ensureStarted(){
if ( _start == 0 )
@ -228,10 +222,7 @@ namespace mongo {
memset(_queryBuf, 0, sizeof(_queryBuf));
}
~CurOp(){
if ( _wrapped )
_client->_curOp = _wrapped;
}
~CurOp();
BSONObj info() {
if( ! cc().getAuthenticationInfo()->isAuthorized("admin") ) {

View File

@ -22,6 +22,8 @@
namespace mongo {
class ClientCursor;
/**
* Database represents a database database
* Each database database has its own set of files -- dbname.ns, dbname.0, dbname.1, ...
@ -196,6 +198,9 @@ namespace mongo {
NamespaceIndex namespaceIndex;
int profile; // 0=off.
string profileName; // "alleyinsider.system.profile"
multimap<DiskLoc, ClientCursor*> ccByLoc;
int magic; // used for making sure the object is still loaded in memory
};

View File

@ -67,7 +67,6 @@ namespace mongo {
#endif
void setupSignals();
void closeAllSockets();
void startReplSets(ReplSetCmdline*);
void startReplication();
void pairWith(const char *remoteEnd, const char *arb);
@ -104,7 +103,7 @@ namespace mongo {
virtual void accepted(MessagingPort *mp) {
if ( ! connTicketHolder.tryAcquire() ){
log() << "connection refused because too many open connections: " << connTicketHolder.used() << endl;
log() << "connection refused because too many open connections: " << connTicketHolder.used() << " of " << connTicketHolder.outof() << endl;
// TODO: would be nice if we notified them...
mp->shutdown();
delete mp;
@ -207,16 +206,14 @@ namespace mongo {
void connThread( MessagingPort * inPort )
{
TicketHolderReleaser connTicketReleaser( &connTicketHolder );
Client::initThread("conn");
/* todo: move to Client object */
LastError *le = new LastError();
lastError.reset(le);
inPort->_logLevel = 1;
auto_ptr<MessagingPort> dbMsgPort( inPort );
dbMsgPort->_logLevel = 1;
Client& c = cc();
Client& c = Client::initThread("conn", inPort);
try {
@ -522,7 +519,7 @@ sendmore:
l << ( is32bit ? " 32" : " 64" ) << "-bit " << endl;
}
DEV log() << "_DEBUG build (which is slower)" << endl;
show_32_warning();
show_warnings();
log() << mongodVersion() << endl;
printGitVersion();
printSysInfo();
@ -629,7 +626,7 @@ using namespace mongo;
namespace po = boost::program_options;
void show_help_text(po::options_description options) {
show_32_warning();
show_warnings();
cout << options << endl;
};
@ -1111,9 +1108,6 @@ int main(int argc, char* argv[], char *envp[] )
namespace mongo {
/* we do not use log() below as it uses a mutex and that could cause deadlocks.
*/
string getDbContext();
#undef out

View File

@ -574,14 +574,26 @@
<ClCompile Include="repl\rs_config.cpp" />
</ItemGroup>
<ItemGroup>
<None Include="..\jstests\rs\rs_basic.js" />
<None Include="..\jstests\rs\test_framework.js" />
<None Include="..\jstests\replsets\replset1.js" />
<None Include="..\jstests\replsets\replset2.js" />
<None Include="..\jstests\replsets\replset3.js" />
<None Include="..\jstests\replsets\replset4.js" />
<None Include="..\jstests\replsets\replset5.js" />
<None Include="..\jstests\replsets\replsetadd.js" />
<None Include="..\jstests\replsets\replsetarb1.js" />
<None Include="..\jstests\replsets\replsetarb2.js" />
<None Include="..\jstests\replsets\replsetprio1.js" />
<None Include="..\jstests\replsets\replsetrestart1.js" />
<None Include="..\jstests\replsets\replsetrestart2.js" />
<None Include="..\jstests\replsets\replset_remove_node.js" />
<None Include="..\jstests\replsets\rollback.js" />
<None Include="..\jstests\replsets\rollback2.js" />
<None Include="..\jstests\replsets\sync1.js" />
<None Include="..\jstests\replsets\twosets.js" />
<None Include="..\SConstruct" />
<None Include="..\util\mongoutils\README" />
<None Include="mongo.ico" />
<None Include="repl\notes.txt" />
<None Include="repl\test.html" />
<None Include="repl\testing.js" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\client\dbclientcursor.h" />

View File

@ -840,7 +840,7 @@
<Filter Include="replSets">
<UniqueIdentifier>{3b73f786-d352-446f-a5f5-df49384baf7a}</UniqueIdentifier>
</Filter>
<Filter Include="replSets\test stuff">
<Filter Include="replSets\testing">
<UniqueIdentifier>{4a1ea357-1077-4ad1-85b4-db48a6e1eb46}</UniqueIdentifier>
</Filter>
</ItemGroup>
@ -851,24 +851,60 @@
<None Include="..\util\mongoutils\README">
<Filter>util\mongoutils</Filter>
</None>
<None Include="repl\testing.js">
<Filter>replSets\test stuff</Filter>
</None>
<None Include="repl\test.html">
<Filter>replSets\test stuff</Filter>
</None>
<None Include="..\SConstruct">
<Filter>db</Filter>
</None>
<None Include="..\jstests\rs\rs_basic.js">
<Filter>replSets\test stuff</Filter>
</None>
<None Include="..\jstests\rs\test_framework.js">
<Filter>replSets\test stuff</Filter>
</None>
<None Include="mongo.ico">
<Filter>Resource Files</Filter>
</None>
<None Include="..\jstests\replsets\replset_remove_node.js">
<Filter>replSets\testing</Filter>
</None>
<None Include="..\jstests\replsets\replset1.js">
<Filter>replSets\testing</Filter>
</None>
<None Include="..\jstests\replsets\replset2.js">
<Filter>replSets\testing</Filter>
</None>
<None Include="..\jstests\replsets\replset3.js">
<Filter>replSets\testing</Filter>
</None>
<None Include="..\jstests\replsets\replset4.js">
<Filter>replSets\testing</Filter>
</None>
<None Include="..\jstests\replsets\replset5.js">
<Filter>replSets\testing</Filter>
</None>
<None Include="..\jstests\replsets\replsetadd.js">
<Filter>replSets\testing</Filter>
</None>
<None Include="..\jstests\replsets\replsetarb1.js">
<Filter>replSets\testing</Filter>
</None>
<None Include="..\jstests\replsets\replsetarb2.js">
<Filter>replSets\testing</Filter>
</None>
<None Include="..\jstests\replsets\replsetprio1.js">
<Filter>replSets\testing</Filter>
</None>
<None Include="..\jstests\replsets\replsetrestart1.js">
<Filter>replSets\testing</Filter>
</None>
<None Include="..\jstests\replsets\replsetrestart2.js">
<Filter>replSets\testing</Filter>
</None>
<None Include="..\jstests\replsets\rollback.js">
<Filter>replSets\testing</Filter>
</None>
<None Include="..\jstests\replsets\rollback2.js">
<Filter>replSets\testing</Filter>
</None>
<None Include="..\jstests\replsets\sync1.js">
<Filter>replSets\testing</Filter>
</None>
<None Include="..\jstests\replsets\twosets.js">
<Filter>replSets\testing</Filter>
</None>
</ItemGroup>
<ItemGroup>
<Library Include="..\..\js\js64r.lib">

View File

@ -12,7 +12,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tools", "tools", "{2B262D59
..\tools\bsondump.cpp = ..\tools\bsondump.cpp
..\tools\dump.cpp = ..\tools\dump.cpp
..\tools\export.cpp = ..\tools\export.cpp
..\tools\files.cpp = ..\tools\files.cpp
..\tools\import.cpp = ..\tools\import.cpp
..\tools\restore.cpp = ..\tools\restore.cpp
..\tools\sniffer.cpp = ..\tools\sniffer.cpp
@ -29,9 +28,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "unix files", "unix files",
EndProjectSection
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "shell", "shell", "{407B4B88-3451-433C-B74F-31B31FEB5791}"
ProjectSection(SolutionItems) = preProject
..\shell\utils.h = ..\shell\utils.h
EndProjectSection
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "other", "other", "{12B11474-2D74-48C3-BB3D-F03249BEA88F}"
EndProject

View File

@ -74,6 +74,14 @@ namespace mongo {
}
} cmdResetError;
/* set by replica sets if specified in the configuration.
a pointer is used to avoid any possible locking issues with lockless reading (see below locktype() is NONE
and would like to keep that)
(for now, it simply orphans any old copy as config changes should be extremely rare).
note: once non-null, never goes to null again.
*/
BSONObj *getLastErrorDefault = 0;
class CmdGetLastError : public Command {
public:
virtual LockType locktype() const { return NONE; }
@ -88,7 +96,7 @@ namespace mongo {
help << "return error status of the last operation on this connection";
}
CmdGetLastError() : Command("getLastError", false, "getlasterror") {}
bool run(const string& dbnamne, BSONObj& cmdObj, string& errmsg, BSONObjBuilder& result, bool fromRepl) {
bool run(const string& dbnamne, BSONObj& _cmdObj, string& errmsg, BSONObjBuilder& result, bool fromRepl) {
LastError *le = lastError.disableForCommand();
if ( le->nPrev != 1 )
LastError::noError.appendSelf( result );
@ -98,6 +106,18 @@ namespace mongo {
Client& c = cc();
c.appendLastOp( result );
BSONObj cmdObj = _cmdObj;
{
BSONObj::iterator i(_cmdObj);
i.next();
if( !i.more() ) {
/* empty, use default */
BSONObj *def = getLastErrorDefault;
if( def )
cmdObj = *def;
}
}
if ( cmdObj["fsync"].trueValue() ){
log() << "fsync from getlasterror" << endl;
result.append( "fsyncFiles" , MemoryMappedFile::flushAll( true ) );
@ -126,6 +146,7 @@ namespace mongo {
assert( sprintf( buf , "w block pass: %lld" , ++passes ) < 30 );
c.curop()->setMessage( buf );
sleepmillis(1);
killCurrentOp.checkForInterrupt();
}
result.appendNumber( "wtime" , t.millis() );
}
@ -159,32 +180,6 @@ namespace mongo {
}
} cmdGetPrevError;
class CmdSwitchToClientErrors : public Command {
public:
virtual bool requiresAuth() { return false; }
virtual bool logTheOp() {
return false;
}
virtual void help( stringstream& help ) const {
help << "convert to id based errors rather than connection based";
}
virtual bool slaveOk() const {
return true;
}
virtual LockType locktype() const { return NONE; }
CmdSwitchToClientErrors() : Command("switchToClientErrors", false, "switchtoclienterrors") {}
bool run(const string& dbnamne , BSONObj& cmdObj, string& errmsg, BSONObjBuilder& result, bool fromRepl) {
if ( lastError.getID() ){
errmsg = "already in client id mode";
return false;
}
LastError *le = lastError.disableForCommand();
le->overridenById = true;
result << "ok" << 1;
return true;
}
} cmdSwitchToClientErrors;
class CmdDropDatabase : public Command {
public:
virtual bool logTheOp() {
@ -292,7 +287,6 @@ namespace mongo {
}
bool run(const string& dbname, BSONObj& cmdObj, string& errmsg, BSONObjBuilder& result, bool fromRepl) {
long long start = Listener::getElapsedTimeMillis();
BSONObjBuilder timeBuilder(128);
@ -345,6 +339,8 @@ namespace mongo {
t.appendBool( "supported" , false );
}
timeBuilder.appendNumber( "middle of mem" , Listener::getElapsedTimeMillis() - start );
t.appendNumber( "mapped" , MemoryMappedFile::totalMappedLength() / ( 1024 * 1024 ) );
t.done();
@ -381,7 +377,13 @@ namespace mongo {
globalFlushCounters.append( bb );
bb.done();
}
{
BSONObjBuilder bb( result.subobjStart( "cursors" ) );
ClientCursor::appendStats( bb );
bb.done();
}
timeBuilder.appendNumber( "after counters" , Listener::getElapsedTimeMillis() - start );
if ( anyReplEnabled() ){
@ -409,8 +411,11 @@ namespace mongo {
if ( ! authed )
result.append( "note" , "run against admin for more info" );
if ( Listener::getElapsedTimeMillis() - start > 1000 )
result.append( "timing" , timeBuilder.obj() );
if ( Listener::getElapsedTimeMillis() - start > 1000 ){
BSONObj t = timeBuilder.obj();
log() << "serverStatus was very slow: " << t << endl;
result.append( "timing" , t );
}
return true;
}
@ -648,10 +653,10 @@ namespace mongo {
virtual void help( stringstream& help ) const {
help << "create a collection";
}
virtual bool run(const string& dbname , BSONObj& cmdObj, string& errmsg, BSONObjBuilder& result, bool) {
virtual bool run(const string& dbname , BSONObj& cmdObj, string& errmsg, BSONObjBuilder& result, bool fromRepl ) {
string ns = dbname + '.' + cmdObj.firstElement().valuestr();
string err;
bool ok = userCreateNS(ns.c_str(), cmdObj, err, true);
bool ok = userCreateNS(ns.c_str(), cmdObj, err, ! fromRepl );
if ( !ok && !err.empty() )
errmsg = err;
return ok;
@ -710,12 +715,8 @@ namespace mongo {
class CmdReIndex : public Command {
public:
virtual bool logTheOp() {
return true;
}
virtual bool slaveOk() const {
return false;
}
virtual bool logTheOp() { return false; } // only reindexes on the one node
virtual bool slaveOk() const { return true; } // can reindex on a secondary
virtual LockType locktype() const { return WRITE; }
virtual void help( stringstream& help ) const {
help << "re-index a collection";
@ -765,9 +766,6 @@ namespace mongo {
class CmdListDatabases : public Command {
public:
virtual bool logTheOp() {
return false;
}
virtual bool slaveOk() const {
return true;
}
@ -945,15 +943,34 @@ namespace mongo {
"\nnote: This command may take a while to run";
}
bool run(const string& dbname, BSONObj& jsobj, string& errmsg, BSONObjBuilder& result, bool fromRepl ){
Timer timer;
string ns = jsobj.firstElement().String();
BSONObj min = jsobj.getObjectField( "min" );
BSONObj max = jsobj.getObjectField( "max" );
BSONObj keyPattern = jsobj.getObjectField( "keyPattern" );
bool estimate = jsobj["estimate"].trueValue();
Client::Context ctx( ns );
NamespaceDetails *d = nsdetails(ns.c_str());
if ( ! d || d->nrecords == 0 ){
result.appendNumber( "size" , 0 );
result.appendNumber( "numObjects" , 0 );
result.append( "millis" , timer.millis() );
return true;
}
result.appendBool( "estimate" , estimate );
shared_ptr<Cursor> c;
if ( min.isEmpty() && max.isEmpty() ) {
if ( estimate ){
result.appendNumber( "size" , d->datasize );
result.appendNumber( "numObjects" , d->nrecords );
result.append( "millis" , timer.millis() );
return 1;
}
c = theDataFileMgr.findAll( ns.c_str() );
}
else if ( min.isEmpty() || max.isEmpty() ) {
@ -964,18 +981,24 @@ namespace mongo {
IndexDetails *idx = cmdIndexDetailsForRange( ns.c_str(), errmsg, min, max, keyPattern );
if ( idx == 0 )
return false;
NamespaceDetails *d = nsdetails(ns.c_str());
c.reset( new BtreeCursor( d, d->idxNo(*idx), *idx, min, max, false, 1 ) );
}
long long avgObjSize = d->datasize / d->nrecords;
long long maxSize = jsobj["maxSize"].numberLong();
long long maxObjects = jsobj["maxObjects"].numberLong();
Timer timer;
long long size = 0;
long long numObjects = 0;
while( c->ok() ) {
size += c->currLoc().rec()->netLength();
if ( estimate )
size += avgObjSize;
else
size += c->currLoc().rec()->netLength();
numObjects++;
if ( ( maxSize && size > maxSize ) ||
@ -994,8 +1017,8 @@ namespace mongo {
}
logIfSlow( timer , os.str() );
result.append( "size", (double)size );
result.append( "numObjects" , (double)numObjects );
result.appendNumber( "size", size );
result.appendNumber( "numObjects" , numObjects );
result.append( "millis" , timer.millis() );
return true;
}
@ -1450,17 +1473,18 @@ namespace mongo {
BSONElementSet values;
shared_ptr<Cursor> cursor = bestGuessCursor(ns.c_str() , query , BSONObj() );
scoped_ptr<ClientCursor> cc (new ClientCursor(QueryOption_NoCursorTimeout, cursor, ns));
while ( cursor->ok() ){
if ( cursor->matcher() && ! cursor->matcher()->matchesCurrent( cursor.get() ) ){
cursor->advance();
continue;
if ( !cursor->matcher() || cursor->matcher()->matchesCurrent( cursor.get() ) ){
BSONObj o = cursor->current();
o.getFieldsDotted( key, values );
}
BSONObj o = cursor->current();
cursor->advance();
o.getFieldsDotted( key.c_str(), values );
if (!cc->yieldSometimes())
break;
}
BSONArrayBuilder b( result.subarrayStart( "values" ) );
@ -1574,9 +1598,6 @@ namespace mongo {
class CmdWhatsMyUri : public Command {
public:
CmdWhatsMyUri() : Command("whatsmyuri") { }
virtual bool logTheOp() {
return false; // the modification will be logged directly
}
virtual bool slaveOk() const {
return true;
}
@ -1712,12 +1733,8 @@ namespace mongo {
public:
virtual LockType locktype() const { return NONE; }
virtual bool adminOnly() const { return true; }
virtual bool logTheOp() {
return false;
}
virtual bool slaveOk() const {
return true;
}
virtual bool logTheOp() { return false; }
virtual bool slaveOk() const { return true; }
virtual void help( stringstream& help ) const {
help << "internal testing command. Makes db block (in a read lock) for 100 seconds\n";
help << "w:true write lock";
@ -1817,7 +1834,7 @@ namespace mongo {
if ( c->adminOnly() && ! fromRepl && dbname != "admin" ) {
result.append( "errmsg" , "access denied- use admin db" );
result.append( "errmsg" , "access denied; use admin db" );
log() << "command denied: " << cmdObj.toString() << endl;
return false;
}

View File

@ -60,6 +60,13 @@ namespace mongo {
bool run(const string& dbname, BSONObj& jsobj, string& errmsg, BSONObjBuilder& result, bool fromRepl ){
result << "version" << versionString << "gitVersion" << gitVersion() << "sysInfo" << sysInfo();
result << "bits" << ( sizeof( int* ) == 4 ? 32 : 64 );
result.appendBool( "debug" ,
#ifdef _DEBUG
true
#else
false
#endif
);
return true;
}
} cmdBuildInfo;
@ -189,8 +196,9 @@ namespace mongo {
CmdShutdown() : Command("shutdown") {}
bool run(const string& dbname, BSONObj& cmdObj, string& errmsg, BSONObjBuilder& result, bool fromRepl) {
Client * c = currentClient.get();
if ( c )
if ( c ) {
c->shutdown();
}
log() << "terminating, shutdown command received" << endl;
dbexit( EXIT_CLEAN ); // this never returns
return true;

View File

@ -301,6 +301,11 @@ namespace mongo {
c->checkLocation();
if ( yield && ! cc->yieldSometimes() ){
// cursor got finished by someone else, so we're done
cc.release(); // if the collection/db is dropped, cc may be deleted
break;
}
}
return num;

View File

@ -432,7 +432,7 @@ namespace mongo {
ss << p( a("/", "back", "Home") );
ss << p( "<b>MongoDB List of <a href=\"http://www.mongodb.org/display/DOCS/Commands\">Commands</a></b>\n" );
const map<string, Command*> *m = Command::commandsByBestName();
ss << "S:slave-only N:no-lock R:read-lock W:write-lock A:admin-only<br>\n";
ss << "S:slave-ok R:read-lock W:write-lock A:admin-only<br>\n";
ss << table();
ss << "<tr><th>Command</th><th>Attributes</th><th>Help</th></tr>\n";
for( map<string, Command*>::const_iterator i = m->begin(); i != m->end(); i++ )

View File

@ -1257,7 +1257,7 @@ namespace mongo {
_want._min = Point( _g , _bl );
_want._max = Point( _g , _tr );
uassert( 13064 , "need an area > 0 " , _want.area() > 0 );
_state = START;
@ -1268,12 +1268,14 @@ namespace mongo {
GEODEBUG( "center : " << center.toString() << "\t" << _prefix );
{
GeoHash a(0LL,32);
GeoHash b(0LL,32);
b.move(1,1);
_fudge = _g->distance(a,b);
}
{
GeoHash a(0LL,32);
GeoHash b(0LL,32);
b.move(1,1);
_fudge = _g->distance(a,b);
}
_wantLen = _fudge + std::max((_want._max._x - _want._min._x), (_want._max._y - _want._min._y));
ok();
}
@ -1308,32 +1310,47 @@ namespace mongo {
_state = DONE;
return;
}
Box cur( _g , _prefix );
if ( cur._min._x + _fudge < _want._min._x &&
cur._min._y + _fudge < _want._min._y &&
cur._max._x - _fudge > _want._max._x &&
cur._max._y - _fudge > _want._max._y ){
_state = DONE;
GeoHash temp = _prefix.commonPrefix( cur._max.hash( _g ) );
GEODEBUG( "box done : " << cur.toString() << " prefix:" << _prefix << " common:" << temp );
if ( temp == _prefix )
return;
_prefix = temp;
GEODEBUG( "\t one more loop" );
continue;
}
else {
if (_g->sizeEdge(_prefix) < _wantLen){
_prefix = _prefix.up();
} else {
for (int i=-1; i<=1; i++){
for (int j=-1; j<=1; j++){
if (i == 0 && j == 0)
continue; // main box
GeoHash newBox = _prefix;
newBox.move(i, j);
PREFIXDEBUG(newBox, _g);
Box cur( _g , newBox );
if (_want.intersects(cur)){
// TODO consider splitting into quadrants
getPointsForPrefix(newBox);
} else {
GEODEBUG("skipping box");
}
}
}
_state = DONE;
}
}
return;
}
}
void getPointsForPrefix(const GeoHash& prefix){
if ( ! BtreeLocation::initial( *_id , _spec , _min , _max , prefix , _found , this ) ){
return;
}
while ( _min.hasPrefix( prefix ) && _min.advance( -1 , _found , this ) );
while ( _max.hasPrefix( prefix ) && _max.advance( 1 , _found , this ) );
}
virtual bool checkDistance( const GeoHash& h , double& d ){
bool res = _want.inside( Point( _g , h ) , _fudge );
@ -1346,6 +1363,7 @@ namespace mongo {
GeoHash _bl;
GeoHash _tr;
Box _want;
double _wantLen;
int _found;

View File

@ -62,7 +62,6 @@ namespace mongo {
bool useCursors = true;
bool useHints = true;
void closeAllSockets();
void flushOpLog( stringstream &ss ) {
if( _diaglog.f && _diaglog.f->is_open() ) {
ss << "flushing op log and files\n";
@ -332,9 +331,10 @@ namespace mongo {
}
}
catch ( AssertionException& e ) {
tlog() << " Caught Assertion in " << opToString(op) << " , continuing" << endl;
static int n;
tlog(3) << " Caught Assertion in " << opToString(op) << ", continuing" << endl;
ss << " exception " + e.toString();
log = true;
log = ++n < 10;
}
}
}
@ -446,6 +446,7 @@ namespace mongo {
mongolock lk(1);
// if this ever moves to outside of lock, need to adjust check Client::Context::_finishInit
if ( ! broadcast && handlePossibleShardedMessage( m , 0 ) )
return;
@ -472,8 +473,10 @@ namespace mongo {
}
writelock lk(ns);
// if this ever moves to outside of lock, need to adjust check Client::Context::_finishInit
if ( ! broadcast & handlePossibleShardedMessage( m , 0 ) )
return;
Client::Context ctx(ns);
long long n = deleteObjects(ns, pattern, justOne, true);
@ -496,6 +499,7 @@ namespace mongo {
if( ntoreturn )
ss << " ntoreturn:" << ntoreturn;
time_t start = 0;
int pass = 0;
bool exhaust = false;
QueryResult* msgdata;
@ -508,6 +512,17 @@ namespace mongo {
catch ( GetMoreWaitException& ) {
exhaust = false;
massert(13073, "shutting down", !inShutdown() );
if( pass == 0 ) {
start = time(0);
}
else {
if( time(0) - start >= 4 ) {
// after about 4 seconds, return. this is a sanity check. pass stops at 1000 normally
// for DEV this helps and also if sleep is highly inaccurate on a platform. we want to
// return occasionally so slave can checkpoint.
pass = 10000;
}
}
pass++;
DEV
sleepmillis(20);
@ -709,32 +724,32 @@ namespace mongo {
}
catch (...) { }
tryToOutputFatal( "dbexit: really exiting now\n" );
tryToOutputFatal( "dbexit: really exiting now" );
if ( c ) c->shutdown();
::exit(rc);
}
void shutdown() {
log() << "\t shutdown: going to close listening sockets..." << endl;
log() << "shutdown: going to close listening sockets..." << endl;
ListeningSockets::get()->closeAll();
log() << "\t shutdown: going to flush oplog..." << endl;
log() << "shutdown: going to flush oplog..." << endl;
stringstream ss2;
flushOpLog( ss2 );
rawOut( ss2.str() );
/* must do this before unmapping mem or you may get a seg fault */
log() << "\t shutdown: going to close sockets..." << endl;
boost::thread close_socket_thread(closeAllSockets);
log() << "shutdown: going to close sockets..." << endl;
boost::thread close_socket_thread( boost::bind(MessagingPort::closeAllSockets, 0) );
// wait until file preallocation finishes
// we would only hang here if the file_allocator code generates a
// synchronous signal, which we don't expect
log() << "\t shutdown: waiting for fs preallocator..." << endl;
log() << "shutdown: waiting for fs preallocator..." << endl;
theFileAllocator().waitUntilFinished();
log() << "\t shutdown: closing all files..." << endl;
log() << "shutdown: closing all files..." << endl;
stringstream ss3;
MemoryMappedFile::closeAllFiles( ss3 );
rawOut( ss3.str() );
@ -744,9 +759,9 @@ namespace mongo {
#if !defined(_WIN32) && !defined(__sunos__)
if ( lockFile ){
log() << "\t shutdown: removing fs lock..." << endl;
log() << "shutdown: removing fs lock..." << endl;
if( ftruncate( lockFile , 0 ) )
log() << "\t couldn't remove fs lock " << errnoWithDescription() << endl;
log() << "couldn't remove fs lock " << errnoWithDescription() << endl;
flock( lockFile, LOCK_UN );
}
#endif
@ -766,12 +781,14 @@ namespace mongo {
bool oldFile = false;
if ( boost::filesystem::exists( name ) && boost::filesystem::file_size( name ) > 0 ){
if ( boost::filesystem::exists( name ) && boost::filesystem::file_size( name ) > 0 ) {
oldFile = true;
}
lockFile = open( name.c_str(), O_RDWR | O_CREAT , S_IRWXU | S_IRWXG | S_IRWXO );
uassert( 10309 , "Unable to create / open lock file for lockfilepath: " + name, lockFile > 0 );
if( lockFile <= 0 ) {
uasserted( 10309 , str::stream() << "Unable to create / open lock file for lockfilepath: " << name << ' ' << errnoWithDescription());
}
if (flock( lockFile, LOCK_EX | LOCK_NB ) != 0) {
close ( lockFile );
lockFile = 0;

View File

@ -143,6 +143,7 @@ namespace mongo {
}
virtual ConnectionString::ConnectionType type() const { return ConnectionString::MASTER; }
virtual bool isMember( const DBConnector * conn ) const { return this == conn; };
};
extern int lockFile;

View File

@ -34,8 +34,11 @@ namespace mongo {
void raiseError(int code , const char *msg) {
LastError *le = lastError.get();
if ( le == 0 ) {
/* might be intentional (non-user thread) */
OCCASIONALLY DEV if( !isShell ) log() << "warning dev: lastError==0 won't report:" << msg << endl;
/* might be intentional (non-user thread) */
DEV {
static unsigned n;
if( ++n < 4 && !isShell ) log() << "dev: lastError==0 won't report:" << msg << endl;
}
} else if ( le->disabled ) {
log() << "lastError disabled, can't report: " << code << ":" << msg << endl;
} else {
@ -168,9 +171,7 @@ namespace mongo {
}
LastError * LastErrorHolder::startRequest( Message& m , int clientId ) {
if ( clientId == 0 )
clientId = m.header()->id & 0xFFFF0000;
assert( clientId );
setID( clientId );
LastError * le = _get( true );
@ -179,11 +180,7 @@ namespace mongo {
}
void LastErrorHolder::startRequest( Message& m , LastError * connectionOwned ) {
if ( !connectionOwned->overridenById ) {
prepareErrForNewRequest( m, connectionOwned );
return;
}
startRequest(m);
prepareErrForNewRequest( m, connectionOwned );
}
void LastErrorHolder::disconnect( int clientId ){

View File

@ -32,7 +32,6 @@ namespace mongo {
long long nObjects;
int nPrev;
bool valid;
bool overridenById;
bool disabled;
void writeback( OID& oid ){
reset( true );
@ -56,7 +55,6 @@ namespace mongo {
nObjects = nDeleted;
}
LastError() {
overridenById = false;
reset();
}
void reset( bool _valid = false ) {
@ -127,7 +125,7 @@ namespace mongo {
/** when db receives a message/request, call this */
void startRequest( Message& m , LastError * connectionOwned );
LastError * startRequest( Message& m , int clientId = 0 );
LastError * startRequest( Message& m , int clientId );
void disconnect( int clientId );

View File

@ -259,7 +259,7 @@ namespace mongo {
}
void Matcher::parseOr( const BSONElement &e, bool subMatcher, list< shared_ptr< Matcher > > &matchers ) {
uassert( 13090, "recursive $or/$nor not allowed", !subMatcher );
uassert( 13090, "nested $or/$nor not allowed", !subMatcher );
uassert( 13086, "$or/$nor must be a nonempty array", e.type() == Array && e.embeddedObject().nFields() > 0 );
BSONObjIterator j( e.embeddedObject() );
while( j.more() ) {

View File

@ -176,11 +176,11 @@ namespace mongo {
{ // query options
if ( cmdObj["query"].type() == Object ){
filter = cmdObj["query"].embeddedObjectUserCheck();
q = filter;
}
if ( cmdObj["sort"].type() == Object )
q.sort( cmdObj["sort"].embeddedObjectUserCheck() );
if ( cmdObj["sort"].type() == Object ){
sort = cmdObj["sort"].embeddedObjectUserCheck();
}
if ( cmdObj["limit"].isNumber() )
limit = cmdObj["limit"].numberLong();
@ -203,10 +203,8 @@ namespace mongo {
long long renameIfNeeded( DBDirectClient& db ){
if ( finalLong != tempLong ){
db.dropCollection( finalLong );
if ( db.count( tempLong ) ){
BSONObj info;
uassert( 10076 , "rename failed" , db.runCommand( "admin" , BSON( "renameCollection" << tempLong << "to" << finalLong ) , info ) );
}
BSONObj info;
uassert( 10076 , "rename failed" , db.runCommand( "admin" , BSON( "renameCollection" << tempLong << "to" << finalLong ) , info ) );
}
return db.count( finalLong );
}
@ -222,7 +220,7 @@ namespace mongo {
// query options
BSONObj filter;
Query q;
BSONObj sort;
long long limit;
// functions
@ -444,7 +442,7 @@ namespace mongo {
readlock lock( mr.ns );
Client::Context ctx( mr.ns );
shared_ptr<Cursor> temp = bestGuessCursor( mr.ns.c_str(), mr.filter, BSONObj() );
shared_ptr<Cursor> temp = bestGuessCursor( mr.ns.c_str(), mr.filter, mr.sort );
auto_ptr<ClientCursor> cursor( new ClientCursor( QueryOption_NoCursorTimeout , temp , mr.ns.c_str() ) );
Timer mt;

View File

@ -564,8 +564,10 @@ namespace mongo {
}
void renameNamespace( const char *from, const char *to ) {
NamespaceIndex *ni = nsindex( from );
assert( ni && ni->details( from ) && !ni->details( to ) );
NamespaceIndex *ni = nsindex( from );
assert( ni );
assert( ni->details( from ) );
assert( ! ni->details( to ) );
// Our namespace and index details will move to a different
// memory location. The only references to namespace and
@ -637,6 +639,8 @@ namespace mongo {
}
bool legalClientSystemNS( const string& ns , bool write ){
if( ns == "local.system.replset" ) return true;
if ( ns.find( ".system.users" ) != string::npos )
return true;

View File

@ -142,8 +142,10 @@ namespace mongo {
this code (or code in now() maybe) should be improved.
*/
if( theReplSet ) {
if( !(theReplSet->lastOpTimeWritten<ts) )
log() << "replSet ERROR possible failover clock skew issue? " << theReplSet->lastOpTimeWritten << ' ' << ts << endl;
if( !(theReplSet->lastOpTimeWritten<ts) ) {
log() << "replSet ERROR possible failover clock skew issue? " << theReplSet->lastOpTimeWritten << ' ' << ts << rsLog;
log() << "replSet " << theReplSet->isPrimary() << rsLog;
}
theReplSet->lastOpTimeWritten = ts;
theReplSet->lastH = hNew;
ctx.getClient()->setLastOp( ts.asDate() );

View File

@ -195,7 +195,7 @@ namespace mongo {
// Use a ClientCursor here so we can release db mutex while scanning
// oplog (can take quite a while with large oplogs).
shared_ptr<Cursor> c = _qp.newReverseCursor();
_findingStartCursor = new ClientCursor(QueryOption_NoCursorTimeout, c, _qp.ns());
_findingStartCursor = new ClientCursor(QueryOption_NoCursorTimeout, c, _qp.ns(), BSONObj());
_findingStartTimer.reset();
_findingStartMode = Initial;
BSONElement tsElt = _qp.originalQuery()[ "ts" ];

View File

@ -56,8 +56,6 @@ namespace mongo {
}
};
const int MaxExtentSize = 0x7ff00000;
map<string, unsigned> BackgroundOperation::dbsInProg;
set<string> BackgroundOperation::nsInProg;
@ -157,7 +155,7 @@ namespace mongo {
sz = 1000000000;
int z = ((int)sz) & 0xffffff00;
assert( z > len );
DEV tlog() << "initialExtentSize(" << len << ") returns " << z << endl;
//DEV tlog() << "initialExtentSize(" << len << ") returns " << z << endl;
return z;
}
@ -272,10 +270,19 @@ namespace mongo {
/*---------------------------------------------------------------------*/
int MongoDataFile::maxSize() {
if ( sizeof( int* ) == 4 )
if ( sizeof( int* ) == 4 ) {
return 512 * 1024 * 1024;
else
} else if ( cmdLine.smallfiles ) {
return 0x7ff00000 >> 2;
} else {
return 0x7ff00000;
}
}
void MongoDataFile::badOfs(int ofs) const {
stringstream ss;
ss << "bad offset:" << ofs << " accessing file: " << mmf.filename() << " - consider repairing database";
uasserted(13440, ss.str());
}
int MongoDataFile::defaultSize( const char *filename ) const {
@ -380,7 +387,7 @@ namespace mongo {
Extent* MongoDataFile::createExtent(const char *ns, int approxSize, bool newCapped, int loops) {
massert( 10357 , "shutdown in progress", !goingAway );
massert( 10358 , "bad new extent size", approxSize >= 0 && approxSize <= MaxExtentSize );
massert( 10358 , "bad new extent size", approxSize >= 0 && approxSize <= Extent::maxSize() );
massert( 10359 , "header==0 on new extent: 32 bit mmap space exceeded?", header ); // null if file open failed
int ExtentSize = approxSize <= header->unusedLength ? approxSize : header->unusedLength;
DiskLoc loc;
@ -403,8 +410,8 @@ namespace mongo {
addNewExtentToNamespace(ns, e, loc, emptyLoc, newCapped);
DEV tlog() << "new extent " << ns << " size: 0x" << hex << ExtentSize << " loc: 0x" << hex << offset
<< " emptyLoc:" << hex << emptyLoc.getOfs() << dec << endl;
DEV tlog(1) << "new extent " << ns << " size: 0x" << hex << ExtentSize << " loc: 0x" << hex << offset
<< " emptyLoc:" << hex << emptyLoc.getOfs() << dec << endl;
return e;
}
@ -568,6 +575,14 @@ namespace mongo {
}
*/
int Extent::maxSize() {
int maxExtentSize = 0x7ff00000;
if ( cmdLine.smallfiles ) {
maxExtentSize >>= 2;
}
return maxExtentSize;
}
/*---------------------------------------------------------------------*/
shared_ptr<Cursor> DataFileMgr::findAll(const char *ns, const DiskLoc &startLoc) {
@ -728,8 +743,11 @@ namespace mongo {
try {
assert( dropIndexes(d, name.c_str(), "*", errmsg, result, true) );
}
catch( DBException& ) {
uasserted(12503,"drop: dropIndexes for collection failed - consider trying repair");
catch( DBException& e ) {
stringstream ss;
ss << "drop: dropIndexes for collection failed - consider trying repair ";
ss << " cause: " << e.what();
uasserted(12503,ss.str());
}
assert( d->nIndexes == 0 );
}
@ -894,7 +912,7 @@ namespace mongo {
if ( toupdate->netLength() < objNew.objsize() ) {
// doesn't fit. reallocate -----------------------------------------------------
uassert( 10003 , "E10003 failing update: objects in a capped ns cannot grow", !(d && d->capped));
uassert( 10003 , "failing update: objects in a capped ns cannot grow", !(d && d->capped));
d->paddingTooSmall();
if ( cc().database()->profile )
ss << " moved ";
@ -947,15 +965,19 @@ namespace mongo {
}
int followupExtentSize(int len, int lastExtentLen) {
assert( len < MaxExtentSize );
assert( len < Extent::maxSize() );
int x = initialExtentSize(len);
int y = (int) (lastExtentLen < 4000000 ? lastExtentLen * 4.0 : lastExtentLen * 1.2);
int sz = y > x ? y : x;
if ( sz < lastExtentLen )
sz = lastExtentLen;
else if ( sz > MaxExtentSize )
sz = MaxExtentSize;
if ( sz < lastExtentLen ){
// this means there was an int overflow
// so we should turn it into maxSize
sz = Extent::maxSize();
}
else if ( sz > Extent::maxSize() ){
sz = Extent::maxSize();
}
sz = ((int)sz) & 0xffffff00;
assert( sz > len );
@ -1026,7 +1048,7 @@ namespace mongo {
Timer t;
tlog() << "Buildindex " << ns << " idxNo:" << idxNo << ' ' << idx.info.obj().toString() << endl;
tlog(1) << "fastBuildIndex " << ns << " idxNo:" << idxNo << ' ' << idx.info.obj().toString() << endl;
bool dupsAllowed = !idx.unique();
bool dropDups = idx.dropDups() || inDBRepair;
@ -1511,6 +1533,13 @@ namespace mongo {
BSONObj info = loc.obj();
bool background = info["background"].trueValue();
if( background && cc().isSyncThread() ) {
/* don't do background indexing on slaves. there are nuances. this could be added later
but requires more code.
*/
log() << "info: indexing in foreground on this replica; was a background index build on the primary" << endl;
background = false;
}
int idxNo = tableToIndex->nIndexes;
IndexDetails& idx = tableToIndex->addIndex(tabletoidxns.c_str(), !background); // clear transient info caches so they refresh; increments nIndexes
@ -1892,7 +1921,10 @@ namespace mongo {
bb.done();
if( nNotClosed )
result.append("nNotClosed", nNotClosed);
else {
ClientCursor::assertNoCursors();
}
return true;
}

View File

@ -79,6 +79,8 @@ namespace mongo {
void flush( bool sync );
private:
void badOfs(int) const;
int defaultSize( const char *filename ) const;
Extent* getExtent(DiskLoc loc);
@ -255,6 +257,8 @@ namespace mongo {
Extent* getPrevExtent() {
return xprev.isNull() ? 0 : DataFileMgr::getExtent(xprev);
}
static int maxSize();
};
/*
@ -339,7 +343,7 @@ namespace mongo {
inline Record* MongoDataFile::recordAt(DiskLoc dl) {
int ofs = dl.getOfs();
assert( ofs >= DataFileHeader::HeaderSize );
if( ofs < DataFileHeader::HeaderSize ) badOfs(ofs); // will uassert - external call to keep out of the normal code path
return (Record*) _p.at(ofs, -1);
}

View File

@ -320,7 +320,6 @@ namespace mongo {
while ( 1 ) {
if ( !c->ok() ) {
// log() << "TEMP Tailable : " << c->tailable() << ' ' << (queryOptions & QueryOption_AwaitData) << endl;
if ( c->tailable() ) {
/* when a tailable cursor hits "EOF", ok() goes false, and current() is null. however
advance() can still be retries as a reactivation attempt. when there is new data, it will
@ -654,11 +653,12 @@ namespace mongo {
if ( !ClientCursor::recoverFromYield( _yieldData ) ) {
_c.reset();
_cc.reset();
_so.reset();
massert( 13338, "cursor dropped during query", false );
// TODO maybe we want to prevent recording the winning plan as well?
}
}
}
}
virtual void next() {
if ( _findingStartCursor.get() ) {
@ -772,7 +772,8 @@ namespace mongo {
_n = _inMemSort ? _so->size() : _n;
}
else if ( _inMemSort ) {
_so->fill( _buf, _pq.getFields() , _n );
if( _so.get() )
_so->fill( _buf, _pq.getFields() , _n );
}
if ( _pq.hasOption( QueryOption_CursorTailable ) && _pq.getNumToReturn() != 1 )
@ -785,8 +786,10 @@ namespace mongo {
if ( _pq.isExplain()) {
_eb.noteScan( _c.get(), _nscanned, _nscannedObjects, _n, scanAndOrderRequired(), _curop.elapsedMillis(), useHints && !_pq.getHint().eoo() );
} else {
_response.appendData( _buf.buf(), _buf.len() );
_buf.decouple();
if (_buf.len()) {
_response.appendData( _buf.buf(), _buf.len() );
_buf.decouple();
}
}
if ( stop ) {
setStop();
@ -1042,14 +1045,13 @@ namespace mongo {
if ( moreClauses ) {
// this MultiCursor will use a dumb NoOp to advance(), so no need to specify mayYield
shared_ptr< Cursor > multi( new MultiCursor( mps, cursor, dqo.matcher(), dqo ) );
cc = new ClientCursor(queryOptions, multi, ns);
cc = new ClientCursor(queryOptions, multi, ns, jsobj.getOwned());
} else {
cursor->setMatcher( dqo.matcher() );
cc = new ClientCursor( queryOptions, cursor, ns );
cc = new ClientCursor( queryOptions, cursor, ns, jsobj.getOwned() );
}
cursorid = cc->cursorid;
cc->query = jsobj.getOwned();
DEV tlog() << "query has more, cursorid: " << cursorid << endl;
DEV tlog(2) << "query has more, cursorid: " << cursorid << endl;
cc->pos = n;
cc->pq = pq_shared;
cc->fields = pq.getFieldPtr();

View File

@ -361,7 +361,7 @@ namespace mongo {
const IndexSpec& spec = ii.getSpec();
if ( spec.getTypeName() == _special && spec.suitability( _originalQuery , order_ ) ){
usingPrerecordedPlan_ = true;
mayRecordPlan_ = true;
mayRecordPlan_ = false;
plans_.push_back( PlanPtr( new QueryPlan( d , j , *fbs_ , _originalQuery, order_ ,
BSONObj() , BSONObj() , _special ) ) );
return;

View File

@ -944,6 +944,8 @@ namespace mongo {
return ( l % 2 == 0 ); // if we're inside an interval
}
// binary search for interval containing the specified element
// an even return value indicates that the element is contained within a valid interval
int FieldRangeVector::matchingLowElement( const BSONElement &e, int i, bool forward ) const {
int l = -1;
int h = _ranges[ i ].intervals().size() * 2;
@ -980,23 +982,16 @@ namespace mongo {
BSONElement kk = k.next();
int number = (int) kk.number();
bool forward = ( number >= 0 ? 1 : -1 ) * ( _direction >= 0 ? 1 : -1 ) > 0;
BSONElement e = obj.getField( kk.fieldName() );
if ( e.eoo() ) {
e = staticNull.firstElement();
BSONElementSet keys;
obj.getFieldsDotted( kk.fieldName(), keys );
bool match = false;
for( BSONElementSet::const_iterator j = keys.begin(); j != keys.end(); ++j ) {
if ( matchesElement( *j, i, forward ) ) {
match = true;
break;
}
}
if ( e.type() == Array ) {
BSONObjIterator j( e.embeddedObject() );
bool match = false;
while( j.more() ) {
if ( matchesElement( j.next(), i, forward ) ) {
match = true;
break;
}
}
if ( !match ) {
return false;
}
} else if ( !matchesElement( e, i, forward ) ) {
if ( !match ) {
return false;
}
}
@ -1007,9 +1002,13 @@ namespace mongo {
int FieldRangeVector::Iterator::advance( const BSONObj &curr ) {
BSONObjIterator j( curr );
BSONObjIterator o( _v._keyPattern );
// track first field for which we are not at the end of the valid values,
// since we may need to advance from the key prefix ending with this field
int latestNonEndpoint = -1;
// iterate over fields to determine appropriate advance method
for( int i = 0; i < (int)_i.size(); ++i ) {
if ( i > 0 && !_v._ranges[ i - 1 ].intervals()[ _i[ i - 1 ] ].equality() ) {
// if last bound was inequality, we don't know anything about where we are for this field
// TODO if possible avoid this certain cases when field in prev key is the same
setMinus( i );
}
@ -1017,9 +1016,9 @@ namespace mongo {
BSONElement oo = o.next();
bool reverse = ( ( oo.number() < 0 ) ^ ( _v._direction < 0 ) );
BSONElement jj = j.next();
if ( _i[ i ] == -1 ) {
if ( _i[ i ] == -1 ) { // unknown position for this field, do binary search
int l = _v.matchingLowElement( jj, i, !reverse );
if ( l % 2 == 0 ) {
if ( l % 2 == 0 ) { // we are in a valid range for this field
_i[ i ] = l / 2;
int diff = (int)_v._ranges[ i ].intervals().size() - _i[ i ];
if ( diff > 1 ) {
@ -1031,7 +1030,8 @@ namespace mongo {
}
}
continue;
} else {
} else { // not in a valid range for this field - determine if and how to advance
// check if we're after the last interval for this field
if ( l == (int)_v._ranges[ i ].intervals().size() * 2 - 1 ) {
if ( latestNonEndpoint == -1 ) {
return -2;
@ -1053,7 +1053,11 @@ namespace mongo {
}
}
bool first = true;
// _i[ i ] != -1, so we have a starting interval for this field
// which serves as a lower/equal bound on the first iteration -
// we advance from this interval to find a matching interval
while( _i[ i ] < (int)_v._ranges[ i ].intervals().size() ) {
// compare to current interval's upper bound
int x = _v._ranges[ i ].intervals()[ _i[ i ] ]._upper._bound.woCompare( jj, false );
if ( reverse ) {
x = -x;
@ -1062,16 +1066,22 @@ namespace mongo {
eq = true;
break;
}
// see if we're less than the upper bound
if ( x > 0 ) {
if ( i == 0 && first ) {
break; // the value of 1st field won't go backward
// the value of 1st field won't go backward, so don't check lower bound
// TODO maybe we can check first only?
break;
}
// if it's an equality interval, don't need to compare separately to lower bound
if ( !_v._ranges[ i ].intervals()[ _i[ i ] ].equality() ) {
// compare to current interval's lower bound
x = _v._ranges[ i ].intervals()[ _i[ i ] ]._lower._bound.woCompare( jj, false );
if ( reverse ) {
x = -x;
}
}
// if we're less than the lower bound, advance
if ( x > 0 ) {
setZero( i + 1 );
// skip to curr / i / nextbounds
@ -1084,17 +1094,20 @@ namespace mongo {
break;
}
}
// we're above the upper bound, so try next interval and reset remaining fields
++_i[ i ];
setZero( i + 1 );
first = false;
}
int diff = (int)_v._ranges[ i ].intervals().size() - _i[ i ];
if ( diff > 1 || ( !eq && diff == 1 ) ) {
// check if we're not at the end of valid values for this field
latestNonEndpoint = i;
} else if ( diff == 0 ) {
} else if ( diff == 0 ) { // check if we're past the last interval for this field
if ( latestNonEndpoint == -1 ) {
return -2;
}
// more values possible, skip...
setZero( latestNonEndpoint + 1 );
// skip to curr / latestNonEndpoint + 1 / superlative
for( int j = latestNonEndpoint + 1; j < (int)_i.size(); ++j ) {

View File

@ -137,9 +137,6 @@ namespace mongo {
virtual bool adminOnly() const {
return true;
}
virtual bool logTheOp() {
return false;
}
virtual LockType locktype() const { return WRITE; }
void help(stringstream&h) const { h << "replace a node in a replica pair"; }
CmdReplacePeer() : Command("replacePeer", false, "replacepeer") { }
@ -199,9 +196,6 @@ namespace mongo {
virtual bool adminOnly() const {
return true;
}
virtual bool logTheOp() {
return false;
}
virtual void help(stringstream& h) const { h << "internal"; }
virtual LockType locktype() const { return WRITE; }
CmdForceDead() : Command("forcedead") { }
@ -222,9 +216,7 @@ namespace mongo {
virtual bool adminOnly() const {
return true;
}
virtual bool logTheOp() {
return false;
}
virtual bool logTheOp() { return false; }
virtual LockType locktype() const { return WRITE; }
void help(stringstream&h) const { h << "resync (from scratch) an out of date replica slave.\nhttp://www.mongodb.org/display/DOCS/Master+Slave"; }
CmdResync() : Command("resync") { }
@ -290,11 +282,13 @@ namespace mongo {
}
}
else {
result.append("ismaster", replSettings.master || replSettings.slave == 0 ? 1 : 0);
//result.append("msg", "not paired");
result.appendBool("ismaster", _isMaster() );
}
if ( level ){
if ( level && replSet ){
result.append( "info" , "is replica set" );
}
else if ( level ){
BSONObjBuilder sources( result.subarrayStart( "sources" ) );
readlock lk( "local.sources" );
@ -664,6 +658,8 @@ namespace mongo {
ReplSource tmp(c->current());
if ( tmp.hostName != cmdLine.source ) {
log() << "repl: --source " << cmdLine.source << " != " << tmp.hostName << " from local.sources collection" << endl;
log() << "repl: for instructions on changing this slave's source, see:" << endl;
log() << "http://dochub.mongodb.org/core/masterslave" << endl;
log() << "repl: terminating mongod after 30 seconds" << endl;
sleepsecs(30);
dbexit( EXIT_REPLICATION_ERROR );
@ -856,11 +852,12 @@ namespace mongo {
see logOp() comments.
*/
void ReplSource::sync_pullOpLog_applyOperation(BSONObj& op, OpTime *localLogTail) {
log( 6 ) << "processing op: " << op << endl;
// skip no-op
if ( op.getStringField( "op" )[ 0 ] == 'n' )
if( logLevel >= 6 ) // op.tostring is expensive so doing this check explicitly
log(6) << "processing op: " << op << endl;
if( op.getStringField("op")[0] == 'n' )
return;
char clientName[MaxDatabaseLen];
const char *ns = op.getStringField("ns");
nsToDatabase(ns, clientName);
@ -1256,8 +1253,14 @@ namespace mongo {
if ( tailing || initial ) {
if ( initial )
log(1) << "repl: initial run\n";
else
assert( syncedTo < nextOpTime );
else {
if( !( syncedTo <= nextOpTime ) ) {
log() << "repl ASSERTION failed : syncedTo <= nextOpTime" << endl;
log() << "repl syncTo: " << syncedTo.toStringLong() << endl;
log() << "repl nextOpTime: " << nextOpTime.toStringLong() << endl;
assert(false);
}
}
oplogReader.putBack( op ); // op will be processed in the loop below
nextOpTime = OpTime(); // will reread the op below
}
@ -1301,12 +1304,15 @@ namespace mongo {
1) find most recent op in local log
2) more()?
*/
if ( !oplogReader.more() ) {
bool moreInitialSyncsPending = !addDbNextPass.empty() && n; // we need "&& n" to assure we actually process at least one op to get a sync point recorded in the first place.
if ( moreInitialSyncsPending || !oplogReader.more() ) {
dblock lk;
OpTime nextLastSaved = nextLastSavedLocalTs();
{
dbtemprelease t;
if ( oplogReader.more() ) {
if ( !moreInitialSyncsPending && oplogReader.more() ) {
if ( getInitialSyncCompleted() ) { // if initial sync hasn't completed, break out of loop so we can set to completed or clone more dbs
continue;
}
@ -1323,6 +1329,8 @@ namespace mongo {
log() << "repl: end sync_pullOpLog syncedTo: " << syncedTo.toStringLong() << endl;
break;
}
else {
}
OCCASIONALLY if( n > 0 && ( n > 100000 || time(0) - saveLast > 60 ) ) {
// periodically note our progress, in case we are doing a lot of work and crash
@ -1681,6 +1689,7 @@ namespace mongo {
void replSlaveThread() {
sleepsecs(1);
Client::initThread("replslave");
cc().iAmSyncThread();
{
dblock lk;

View File

@ -44,19 +44,36 @@ namespace mongo {
/** throws assertions if connect failure etc. */
ScopedConn(string hostport);
~ScopedConn();
DBClientConnection* operator->();
/* If we were to run a query and not exhaust the cursor, future use of the connection would be problematic.
So here what we do is wrapper known safe methods and not allow cursor-style queries at all. This makes
ScopedConn limited in functionality but very safe. More non-cursor wrappers can be added here if needed.
*/
bool runCommand(const string &dbname, const BSONObj& cmd, BSONObj &info, int options=0) {
return conn()->runCommand(dbname, cmd, info, options);
}
unsigned long long count(const string &ns) {
return conn()->count(ns);
}
BSONObj findOne(const string &ns, const Query& q, const BSONObj *fieldsToReturn = 0, int queryOptions = 0) {
return conn()->findOne(ns, q, fieldsToReturn, queryOptions);
}
private:
auto_ptr<scoped_lock> connLock;
static mutex mapMutex;
struct X {
mutex z;
DBClientConnection cc;
X() : z("X"), cc(/*reconnect*/true, 0, /*timeout*/10) {
X() : z("X"), cc(/*reconnect*/ true, 0,
/*timeout*/ theReplSet ? theReplSet->config().ho.heartbeatTimeoutMillis/1000.0 : 10.0) {
cc._logLevel = 2;
}
} *x;
typedef map<string,ScopedConn::X*> M;
static M& _map;
DBClientConnection* conn() { return &x->cc; }
};
inline ScopedConn::ScopedConn(string hostport) {
@ -84,8 +101,8 @@ namespace mongo {
// conLock releases...
}
inline DBClientConnection* ScopedConn::operator->() {
/*inline DBClientConnection* ScopedConn::operator->() {
return &x->cc;
}
}*/
}

View File

@ -83,6 +83,17 @@ namespace mongo {
return vUp * 2 > totalVotes();
}
bool Consensus::shouldRelinquish() const {
int vUp = rs._self->config().votes;
const long long T = rs.config().ho.heartbeatTimeoutMillis * rs.config().ho.heartbeatConnRetries;
for( Member *m = rs.head(); m; m=m->next() ) {
long long dt = m->hbinfo().timeDown();
if( dt < T )
vUp += m->config().votes;
}
return !( vUp * 2 > totalVotes() );
}
static const int VETO = -10000;
const time_t LeaseTime = 30;
@ -123,6 +134,9 @@ namespace mongo {
OID round = cmd["round"].OID();
int myver = rs.config().version;
const Member* primary = rs.box.getPrimary();
const Member* hopeful = rs.findById(whoid);
int vote = 0;
if( set != rs.name() ) {
log() << "replSet error received an elect request for '" << set << "' but our set name is '" << rs.name() << "'" << rsLog;
@ -136,6 +150,16 @@ namespace mongo {
log() << "replSet info got stale version # during election" << rsLog;
vote = -10000;
}
else if( !hopeful ) {
log() << "couldn't find member with id " << whoid << rsLog;
vote = -10000;
}
else if( primary && primary->hbinfo().opTime > hopeful->hbinfo().opTime ) {
// other members might be aware of more up-to-date nodes
log() << hopeful->fullName() << " is trying to elect itself but " <<
primary->fullName() << " is already primary and more up-to-date" << rsLog;
vote = -10000;
}
else {
try {
vote = yea(whoid);
@ -154,7 +178,7 @@ namespace mongo {
void ReplSetImpl::_getTargets(list<Target>& L, int& configVersion) {
configVersion = config().version;
for( Member *m = head(); m; m=m->next() )
if( m->hbinfo().up() )
if( m->hbinfo().maybeUp() )
L.push_back( Target(m->fullName()) );
}
@ -322,6 +346,7 @@ namespace mongo {
void Consensus::electSelf() {
assert( !rs.lockedByMe() );
assert( !rs.myConfig().arbiterOnly );
assert( rs.myConfig().slaveDelay == 0 );
try {
_electSelf();
}

View File

@ -19,6 +19,7 @@
#include "health.h"
#include "../../util/background.h"
#include "../../client/dbclient.h"
#include "../../client/connpool.h"
#include "../commands.h"
#include "../../util/concurrency/value.h"
#include "../../util/concurrency/task.h"
@ -89,11 +90,13 @@ namespace mongo {
}
s << td(config().votes);
{
string stateText = ReplSet::stateAsStr(state());
string stateText = state().toString();
if( _config.hidden )
stateText += " (hidden)";
if( ok || stateText.empty() )
s << td(stateText); // text blank if we've never connected
else
s << td( grey(str::stream() << "(was " << ReplSet::stateAsStr(state()) << ')', true) );
s << td( grey(str::stream() << "(was " << state().toString() << ')', true) );
}
s << td( grey(hbinfo().lastHeartbeatMsg,!ok) );
stringstream q;
@ -105,28 +108,30 @@ namespace mongo {
s << td("");
s << _tr();
}
string ReplSetImpl::stateAsHtml(MemberState s) {
if( s.s == MemberState::RS_STARTUP ) return a("", "serving still starting up, or still trying to initiate the set", "STARTUP");
if( s.s == MemberState::RS_PRIMARY ) return a("", "this server thinks it is primary", "PRIMARY");
if( s.s == MemberState::RS_SECONDARY ) return a("", "this server thinks it is a secondary (slave mode)", "SECONDARY");
if( s.s == MemberState::RS_RECOVERING ) return a("", "recovering/resyncing; after recovery usually auto-transitions to secondary", "RECOVERING");
if( s.s == MemberState::RS_FATAL ) return a("", "something bad has occurred and server is not completely offline with regard to the replica set. fatal error.", "RS_FATAL");
if( s.s == MemberState::RS_STARTUP2 ) return a("", "loaded config, still determining who is primary", "RS_STARTUP2");
if( s.s == MemberState::RS_FATAL ) return a("", "something bad has occurred and server is not completely offline with regard to the replica set. fatal error.", "FATAL");
if( s.s == MemberState::RS_STARTUP2 ) return a("", "loaded config, still determining who is primary", "STARTUP2");
if( s.s == MemberState::RS_ARBITER ) return a("", "this server is an arbiter only", "ARBITER");
if( s.s == MemberState::RS_DOWN ) return a("", "member is down, slow, or unreachable", "DOWN");
if( s.s == MemberState::RS_ROLLBACK ) return a("", "rolling back operations to get in sync", "ROLLBACK");
return "";
}
string ReplSetImpl::stateAsStr(MemberState s) {
if( s.s == MemberState::RS_STARTUP ) return "STARTUP";
if( s.s == MemberState::RS_PRIMARY ) return "PRIMARY";
if( s.s == MemberState::RS_SECONDARY ) return "SECONDARY";
if( s.s == MemberState::RS_RECOVERING ) return "RECOVERING";
if( s.s == MemberState::RS_FATAL ) return "FATAL";
if( s.s == MemberState::RS_STARTUP2 ) return "STARTUP2";
if( s.s == MemberState::RS_ARBITER ) return "ARBITER";
if( s.s == MemberState::RS_DOWN ) return "DOWN";
string MemberState::toString() const {
if( s == MemberState::RS_STARTUP ) return "STARTUP";
if( s == MemberState::RS_PRIMARY ) return "PRIMARY";
if( s == MemberState::RS_SECONDARY ) return "SECONDARY";
if( s == MemberState::RS_RECOVERING ) return "RECOVERING";
if( s == MemberState::RS_FATAL ) return "FATAL";
if( s == MemberState::RS_STARTUP2 ) return "STARTUP2";
if( s == MemberState::RS_ARBITER ) return "ARBITER";
if( s == MemberState::RS_DOWN ) return "DOWN";
if( s == MemberState::RS_ROLLBACK ) return "ROLLBACK";
return "";
}
@ -171,7 +176,7 @@ namespace mongo {
}
void ReplSetImpl::_getOplogDiagsAsHtml(unsigned server_id, stringstream& ss) const {
Member *m = findById(server_id);
const Member *m = findById(server_id);
if( m == 0 ) {
ss << "Error : can't find a member with id: " << server_id << '\n';
return;
@ -182,7 +187,7 @@ namespace mongo {
//const bo fields = BSON( "o" << false << "o2" << false );
const bo fields;
ScopedConn conn(m->fullName());
ScopedDbConnection conn(m->fullName());
auto_ptr<DBClientCursor> c = conn->query(rsoplog, Query().sort("$natural",1), 20, 0, &fields);
if( c.get() == 0 ) {
@ -241,8 +246,6 @@ namespace mongo {
ss << _table();
ss << p(time_t_to_String_short(time(0)) + " current time");
//ss << "</pre>\n";
if( !otEnd.isNull() ) {
ss << "<p>Log length in time: ";
unsigned d = otEnd.getSecs() - otFirst.getSecs();
@ -255,6 +258,7 @@ namespace mongo {
ss << "</p>\n";
}
conn.done();
}
void ReplSetImpl::_summarizeAsHtml(stringstream& s) const {
@ -302,7 +306,7 @@ namespace mongo {
td(ago(started)) <<
td("") << // last heartbeat
td(ToString(_self->config().votes)) <<
td(stateAsHtml(box.getState()));
td( stateAsHtml(box.getState()) + (_self->config().hidden?" (hidden)":"") );
s << td( _hbmsg );
stringstream q;
q << "/_replSetOplog?" << _self->id();
@ -329,7 +333,7 @@ namespace mongo {
_rsLog.toHTML( s );
}
Member* ReplSetImpl::findById(unsigned id) const {
const Member* ReplSetImpl::findById(unsigned id) const {
if( id == _self->id() ) return _self;
for( Member *m = head(); m; m = m->next() )
if( m->id() == id )
@ -371,6 +375,7 @@ namespace mongo {
v.push_back(bb.obj());
m = m->next();
}
sort(v.begin(), v.end());
b.append("set", name());
b.appendTimeT("date", time(0));
b.append("myState", box.getState().s);

View File

@ -27,7 +27,7 @@ namespace mongo {
HealthOptions() {
heartbeatSleepMillis = 2000;
heartbeatTimeoutMillis = 10000;
heartbeatConnRetries = 3;
heartbeatConnRetries = 2;
}
bool isDefault() const { return *this == HealthOptions(); }

View File

@ -40,6 +40,13 @@ namespace mongo {
// hacky
string *discoveredSeed = 0;
long long HeartbeatInfo::timeDown() const {
if( up() ) return 0;
if( downSince == 0 )
return 0; // still waiting on first heartbeat
return jsTime() - downSince;
}
/* { replSetHeartbeat : <setname> } */
class CmdReplSetHeartbeat : public ReplSetCommand {
public:
@ -55,6 +62,14 @@ namespace mongo {
errmsg = "not running with --replSet";
return false;
}
/* we want to keep heartbeat connections open when relinquishing primary. tag them here. */
{
MessagingPort *mp = cc()._mp;
if( mp )
mp->tag |= 1;
}
if( cmdObj["pv"].Int() != 1 ) {
errmsg = "incompatible replset protocol version";
return false;
@ -91,7 +106,7 @@ namespace mongo {
result.append("set", theReplSet->name());
result.append("state", theReplSet->state().s);
result.append("hbmsg", theReplSet->hbmsg());
result.append("time", (int) time(0));
result.append("time", (long long) time(0));
result.appendDate("opTime", theReplSet->lastOpTimeWritten.asDate());
int v = theReplSet->config().version;
result.append("v", v);
@ -119,7 +134,7 @@ namespace mongo {
assert( theReplSet == 0 || !theReplSet->lockedByMe() );
ScopedConn conn(memberFullName);
return conn->runCommand("admin", cmd, result);
return conn.runCommand("admin", cmd, result, 0);
}
/* poll every other set member to check its status */
@ -196,7 +211,12 @@ namespace mongo {
static time_t last = 0;
time_t now = time(0);
if( mem.changed(old) || now-last>4 ) {
bool changed = mem.changed(old);
if( changed ) {
if( old.hbstate != mem.hbstate )
log() << "replSet " << h.toString() << ' ' << mem.hbstate.toString() << rsLog;
}
if( changed || now-last>4 ) {
last = now;
theReplSet->mgr->send( boost::bind(&Manager::msgCheckNewState, theReplSet->mgr) );
}
@ -205,8 +225,9 @@ namespace mongo {
private:
void down(HeartbeatInfo& mem, string msg) {
mem.health = 0.0;
if( mem.upSince ) {
if( mem.upSince || mem.downSince == 0 ) {
mem.upSince = 0;
mem.downSince = jsTime();
log() << "replSet info " << h.toString() << " is now down (or slow to respond)" << rsLog;
}
mem.lastHeartbeatMsg = msg;

View File

@ -29,12 +29,17 @@ namespace mongo {
};
/* check members OTHER THAN US to see if they think they are primary */
const Member * Manager::findOtherPrimary() {
const Member * Manager::findOtherPrimary(bool& two) {
two = false;
Member *m = rs->head();
Member *p = 0;
while( m ) {
DEV assert( m != rs->_self );
if( m->state().primary() && m->hbinfo().up() ) {
if( p ) throw "twomasters"; // our polling is asynchronous, so this is often ok.
if( p ) {
two = true;
return 0;
}
p = m;
}
m = m->next();
@ -63,7 +68,11 @@ namespace mongo {
if( rs->box.getPrimary() == m )
return;
rs->_self->lhb() = "";
rs->box.set(rs->iAmArbiterOnly() ? MemberState::RS_ARBITER : MemberState::RS_RECOVERING, m);
if( rs->iAmArbiterOnly() ) {
rs->box.set(MemberState::RS_ARBITER, m);
} else {
rs->box.noteRemoteIsPrimary(m);
}
}
/** called as the health threads get new results */
@ -87,11 +96,14 @@ namespace mongo {
}
const Member *p2;
try { p2 = findOtherPrimary(); }
catch(string s) {
/* two other nodes think they are primary (asynchronously polled) -- wait for things to settle down. */
log() << "replSet warning DIAG 2 primary" << s << rsLog;
return;
{
bool two;
p2 = findOtherPrimary(two);
if( two ) {
/* two other nodes think they are primary (asynchronously polled) -- wait for things to settle down. */
log() << "replSet warning DIAG two primaries (transiently)" << rsLog;
return;
}
}
if( p2 ) {
@ -136,7 +148,7 @@ namespace mongo {
return;
}
if( !rs->elect.aMajoritySeemsToBeUp() ) {
if( rs->elect.shouldRelinquish() ) {
log() << "replSet can't see a majority of the set, relinquishing primary" << rsLog;
rs->relinquish();
}

View File

@ -43,7 +43,7 @@ namespace mongo {
void run() {
try {
ScopedConn c(d.toHost);
d.ok = c->runCommand("admin", cmd, d.result);
d.ok = c.runCommand("admin", cmd, d.result);
}
catch(DBException&) {
DEV log() << "dev caught dbexception on multiCommand " << d.toHost << rsLog;

View File

@ -26,7 +26,7 @@
namespace mongo {
void checkAllMembersUpForConfigChange(const ReplSetConfig& cfg, bool initial);
void checkMembersUpForConfigChange(const ReplSetConfig& cfg, bool initial);
/* commands in other files:
replSetHeartbeat - health.cpp
@ -34,19 +34,27 @@ namespace mongo {
*/
bool replSetBlind = false;
unsigned replSetForceInitialSyncFailure = 0;
class CmdReplSetTest : public ReplSetCommand {
public:
virtual void help( stringstream &help ) const {
help << "Just for testing : do not use.\n";
help << "Just for regression tests.\n";
}
CmdReplSetTest() : ReplSetCommand("replSetTest") { }
virtual bool run(const string& , BSONObj& cmdObj, string& errmsg, BSONObjBuilder& result, bool fromRepl) {
log() << "replSet replSetTest command received: " << cmdObj.toString() << rsLog;
if( cmdObj.hasElement("forceInitialSyncFailure") ) {
replSetForceInitialSyncFailure = (unsigned) cmdObj["forceInitialSyncFailure"].Number();
return true;
}
// may not need this, but if removed check all tests still work:
if( !check(errmsg, result) )
return false;
if( cmdObj.hasElement("blind") ) {
replSetBlind = cmdObj.getBoolField("blind");
log() << "replSet info replSetTest command received, replSetBlind=" << replSetBlind << rsLog;
return true;
}
return false;
@ -55,6 +63,7 @@ namespace mongo {
class CmdReplSetGetRBID : public ReplSetCommand {
public:
/* todo: ideally this should only change on rollbacks NOT on mongod restarts also. fix... */
int rbid;
virtual void help( stringstream &help ) const {
help << "internal";
@ -65,12 +74,15 @@ namespace mongo {
virtual bool run(const string& , BSONObj& cmdObj, string& errmsg, BSONObjBuilder& result, bool fromRepl) {
if( !check(errmsg, result) )
return false;
result.append("rbid",rbid);
result.append("rbid",rbid);
return true;
}
} cmdReplSetRBID;
using namespace bson;
void incRBID() {
cmdReplSetRBID.rbid++;
}
int getRBID(DBClientConnection *c) {
bo info;
c->simpleCommand("admin", &info, "replSetGetRBID");
@ -151,9 +163,9 @@ namespace mongo {
return false;
}
checkAllMembersUpForConfigChange(newConfig,false);
checkMembersUpForConfigChange(newConfig,false);
log() << "replSet replSetReconfig all members seem up" << rsLog;
log() << "replSet replSetReconfig [2]" << rsLog;
theReplSet->haveNewConfig(newConfig, true);
ReplSet::startupStatusMsg = "replSetReconfig'd";

View File

@ -31,39 +31,48 @@ namespace mongo {
extern string *discoveredSeed;
void ReplSetImpl::sethbmsg(string s, int logLevel) {
static time_t lastLogged;
if( s == _hbmsg ) {
// unchanged
if( time(0)-lastLogged < 60 )
return;
}
static time_t lastLogged;
_hbmsgTime = time(0);
unsigned sz = s.size();
if( sz >= 256 )
memcpy(_hbmsg, s.c_str(), 255);
else {
_hbmsg[sz] = 0;
memcpy(_hbmsg, s.c_str(), sz);
}
if( !s.empty() ) {
lastLogged = time(0);
log(logLevel) << "replSet " << s << rsLog;
}
if( s == _hbmsg ) {
// unchanged
if( _hbmsgTime - lastLogged < 60 )
return;
}
unsigned sz = s.size();
if( sz >= 256 )
memcpy(_hbmsg, s.c_str(), 255);
else {
_hbmsg[sz] = 0;
memcpy(_hbmsg, s.c_str(), sz);
}
if( !s.empty() ) {
lastLogged = _hbmsgTime;
log(logLevel) << "replSet " << s << rsLog;
}
}
void ReplSetImpl::assumePrimary() {
assert( iAmPotentiallyHot() );
writelock lk("admin."); // so we are synchronized with _logOp()
box.setSelfPrimary(_self);
log() << "replSet PRIMARY" << rsLog; // self (" << _self->id() << ") is now primary" << rsLog;
//log() << "replSet PRIMARY" << rsLog; // self (" << _self->id() << ") is now primary" << rsLog;
}
void ReplSetImpl::changeState(MemberState s) { box.change(s, _self); }
void ReplSetImpl::relinquish() {
if( box.getState().primary() ) {
log() << "replSet relinquishing primary state" << rsLog;
changeState(MemberState::RS_RECOVERING);
log() << "replSet info relinquished primary state" << rsLog;
/* close sockets that were talking to us */
/*log() << "replSet closing sockets after reqlinquishing primary" << rsLog;
MessagingPort::closeAllSockets(1);*/
// todo: >
//changeState(MemberState::RS_SECONDARY);
}
else if( box.getState().startup2() ) {
// ? add comment
@ -109,11 +118,18 @@ namespace mongo {
}
void ReplSetImpl::_fillIsMasterHost(const Member *m, vector<string>& hosts, vector<string>& passives, vector<string>& arbiters) {
if( m->config().hidden )
return;
if( m->potentiallyHot() ) {
hosts.push_back(m->h().toString());
}
else if( !m->config().arbiterOnly ) {
passives.push_back(m->h().toString());
if( m->config().slaveDelay ) {
/* hmmm - we don't list these as they are stale. */
} else {
passives.push_back(m->h().toString());
}
}
else {
arbiters.push_back(m->h().toString());
@ -123,6 +139,7 @@ namespace mongo {
void ReplSetImpl::_fillIsMaster(BSONObjBuilder& b) {
const StateBox::SP sp = box.get();
bool isp = sp.state.primary();
b.append("setName", name());
b.append("ismaster", isp);
b.append("secondary", sp.state.secondary());
{
@ -151,6 +168,10 @@ namespace mongo {
}
if( myConfig().arbiterOnly )
b.append("arbiterOnly", true);
if( myConfig().slaveDelay )
b.append("slaveDelay", myConfig().slaveDelay);
if( myConfig().hidden )
b.append("hidden", true);
}
/** @param cfgString <setname>/<seedhost1>,<seedhost2> */
@ -199,6 +220,7 @@ namespace mongo {
_self(0),
mgr( new Manager(this) )
{
_cfg = 0;
memset(_hbmsg, 0, sizeof(_hbmsg));
*_hbmsg = '.'; // temp...just to see
lastH = 0;
@ -244,7 +266,7 @@ namespace mongo {
loadLastOpTimeWritten();
}
catch(std::exception& e) {
log() << "replSet ERROR FATAL couldn't query the local " << rsoplog << " collection. Terminating mongod after 30 seconds." << rsLog;
log() << "replSet error fatal couldn't query the local " << rsoplog << " collection. Terminating mongod after 30 seconds." << rsLog;
log() << e.what() << rsLog;
sleepsecs(30);
dbexit( EXIT_REPLICATION_ERROR );
@ -259,25 +281,64 @@ namespace mongo {
ReplSetImpl::StartupStatus ReplSetImpl::startupStatus = PRESTART;
string ReplSetImpl::startupStatusMsg;
// true if ok; throws if config really bad; false if config doesn't include self
bool ReplSetImpl::initFromConfig(ReplSetConfig& c) {
extern BSONObj *getLastErrorDefault;
/** @param reconf true if this is a reconfiguration and not an initial load of the configuration.
@return true if ok; throws if config really bad; false if config doesn't include self
*/
bool ReplSetImpl::initFromConfig(ReplSetConfig& c, bool reconf) {
/* NOTE: haveNewConfig() writes the new config to disk before we get here. So
we cannot error out at this point, except fatally. Check errors earlier.
*/
lock lk(this);
if( getLastErrorDefault || !c.getLastErrorDefaults.isEmpty() ) {
// see comment in dbcommands.cpp for getlasterrordefault
getLastErrorDefault = new BSONObj( c.getLastErrorDefaults );
}
list<const ReplSetConfig::MemberCfg*> newOnes;
bool additive = reconf;
{
unsigned nfound = 0;
int me = 0;
for( vector<ReplSetConfig::MemberCfg>::iterator i = c.members.begin(); i != c.members.end(); i++ ) {
const ReplSetConfig::MemberCfg& m = *i;
if( m.h.isSelf() ) {
nfound++;
me++;
if( !reconf || (_self && _self->id() == (unsigned) m._id) )
;
else {
log() << "replSet " << _self->id() << ' ' << m._id << rsLog;
assert(false);
}
}
else if( reconf ) {
const Member *old = findById(m._id);
if( old ) {
nfound++;
assert( (int) old->id() == m._id );
if( old->config() == m ) {
additive = false;
}
}
else {
newOnes.push_back(&m);
}
}
}
if( me == 0 ) {
// log() << "replSet config : " << _cfg->toString() << rsLog;
log() << "replSet warning can't find self in the repl set configuration:" << rsLog;
log() << "replSet error can't find self in the repl set configuration:" << rsLog;
log() << c.toString() << rsLog;
return false;
assert(false);
}
uassert( 13302, "replSet error self appears twice in the repl set configuration", me<=1 );
if( reconf && config().members.size() != nfound )
additive = false;
}
_cfg = new ReplSetConfig(c);
@ -286,6 +347,24 @@ namespace mongo {
_name = _cfg->_id;
assert( !_name.empty() );
if( additive ) {
log() << "replSet info : additive change to configuration" << rsLog;
for( list<const ReplSetConfig::MemberCfg*>::const_iterator i = newOnes.begin(); i != newOnes.end(); i++ ) {
const ReplSetConfig::MemberCfg* m = *i;
Member *mi = new Member(m->h, m->_id, m, false);
/** we will indicate that new members are up() initially so that we don't relinquish our
primary state because we can't (transiently) see a majority. they should be up as we
check that new members are up before getting here on reconfig anyway.
*/
mi->get_hbinfo().health = 0.1;
_members.push(mi);
startHealthTaskFor(mi);
}
return true;
}
// start with no members. if this is a reconfig, drop the old ones.
_members.orphanAll();
@ -390,9 +469,9 @@ namespace mongo {
startupStatus = EMPTYCONFIG;
startupStatusMsg = "can't get " + rsConfigNs + " config from self or any seed (EMPTYCONFIG)";
log() << "replSet can't get " << rsConfigNs << " config from self or any seed (EMPTYCONFIG)" << rsLog;
log() << "replSet have you ran replSetInitiate yet?" << rsLog;
log(1) << "replSet have you ran replSetInitiate yet?" << rsLog;
if( _seeds->size() == 0 )
log() << "replSet no seed hosts were specified on the --replSet command line - that might be the issue" << rsLog;
log(1) << "replSet info no seed hosts were specified on the --replSet command line" << rsLog;
}
else {
startupStatus = EMPTYUNREACHABLE;
@ -415,6 +494,7 @@ namespace mongo {
startupStatusMsg = "replSet error loading set config (BADCONFIG)";
log() << "replSet error loading configurations " << e.toString() << rsLog;
log() << "replSet error replication will not start" << rsLog;
sethbmsg("error loading set config");
_fatal();
throw;
}
@ -428,11 +508,10 @@ namespace mongo {
{
//lock l(this);
box.set(MemberState::RS_FATAL, 0);
sethbmsg("fatal error");
log() << "replSet error fatal error, stopping replication" << rsLog;
//sethbmsg("fatal error");
log() << "replSet error fatal, stopping replication" << rsLog;
}
void ReplSet::haveNewConfig(ReplSetConfig& newConfig, bool addComment) {
lock l(this); // convention is to lock replset before taking the db rwlock
writelock lk("");
@ -441,7 +520,7 @@ namespace mongo {
comment = BSON( "msg" << "Reconfig set" << "version" << newConfig.version );
newConfig.saveConfigLocally(comment);
try {
initFromConfig(newConfig);
initFromConfig(newConfig, true);
log() << "replSet replSetReconfig new config saved locally" << rsLog;
}
catch(DBException& e) {

View File

@ -44,19 +44,19 @@ namespace mongo {
public:
Member(HostAndPort h, unsigned ord, const ReplSetConfig::MemberCfg *c, bool self);
string fullName() const { return h().toString(); }
const ReplSetConfig::MemberCfg& config() const { return *_config; }
const ReplSetConfig::MemberCfg& config() const { return _config; }
const HeartbeatInfo& hbinfo() const { return _hbinfo; }
string lhb() { return _hbinfo.lastHeartbeatMsg; }
HeartbeatInfo& get_hbinfo() { return _hbinfo; }
string lhb() const { return _hbinfo.lastHeartbeatMsg; }
MemberState state() const { return _hbinfo.hbstate; }
const HostAndPort& h() const { return _h; }
unsigned id() const { return _hbinfo.id(); }
bool potentiallyHot() const { return _config->potentiallyHot(); } // not arbiter, not priority 0
bool potentiallyHot() const { return _config.potentiallyHot(); } // not arbiter, not priority 0
void summarizeMember(stringstream& s) const;
friend class ReplSetImpl;
private:
const ReplSetConfig::MemberCfg *_config; /* todo: when this changes??? */
HostAndPort _h;
const ReplSetConfig::MemberCfg _config;
const HostAndPort _h;
HeartbeatInfo _hbinfo;
};
@ -64,7 +64,13 @@ namespace mongo {
ReplSetImpl *rs;
bool busyWithElectSelf;
int _primary;
const Member* findOtherPrimary();
/** @param two - if true two primaries were seen. this can happen transiently, in addition to our
polling being only occasional. in this case null is returned, but the caller should
not assume primary itself in that situation.
*/
const Member* findOtherPrimary(bool& two);
void noteARemoteIsPrimary(const Member *);
virtual void starting();
public:
@ -102,6 +108,7 @@ namespace mongo {
int totalVotes() const;
bool aMajoritySeemsToBeUp() const;
bool shouldRelinquish() const;
void electSelf();
void electCmdReceived(BSONObj, BSONObjBuilder*);
void multiCommand(BSONObj cmd, list<Target>& L);
@ -119,8 +126,8 @@ namespace mongo {
protected:
RSBase() : magic(0x12345677), m("RSBase"), _locked(0) { }
~RSBase() {
log() << "~RSBase should never be called?" << rsLog;
assert(false);
/* this can happen if we throw in the constructor; otherwise never happens. thus we log it as it is quite unusual. */
log() << "replSet ~RSBase called" << rsLog;
}
class lock {
@ -175,6 +182,9 @@ namespace mongo {
const Member* getPrimary() const { return sp.primary; }
void change(MemberState s, const Member *self) {
scoped_lock lk(m);
if( sp.state != s ) {
log() << "replSet " << s.toString() << rsLog;
}
sp.state = s;
if( s.primary() ) {
sp.primary = self;
@ -194,6 +204,12 @@ namespace mongo {
assert( !sp.state.primary() );
sp.primary = mem;
}
void noteRemoteIsPrimary(const Member *remote) {
scoped_lock lk(m);
if( !sp.state.secondary() && !sp.state.fatal() )
sp.state = MemberState::RS_RECOVERING;
sp.primary = remote;
}
StateBox() : m("StateBox") { }
private:
mutex m;
@ -226,7 +242,6 @@ namespace mongo {
};
static StartupStatus startupStatus;
static string startupStatusMsg;
static string stateAsStr(MemberState state);
static string stateAsHtml(MemberState state);
/* todo thread */
@ -241,28 +256,24 @@ namespace mongo {
void endOldHealthTasks();
void startHealthTaskFor(Member *m);
private:
Consensus elect;
bool ok() const { return !box.getState().fatal(); }
void relinquish();
void forgetPrimary();
protected:
bool _stepDown();
private:
void assumePrimary();
void loadLastOpTimeWritten();
void changeState(MemberState s);
protected:
// "heartbeat message"
// sent in requestHeartbeat respond in field "hbm"
char _hbmsg[256]; // we change this unlocked, thus not an stl::string
time_t _hbmsgTime; // when it was logged
public:
void sethbmsg(string s, int logLevel = 0);
protected:
bool initFromConfig(ReplSetConfig& c); // true if ok; throws if config really bad; false if config doesn't include self
bool initFromConfig(ReplSetConfig& c, bool reconf=false); // true if ok; throws if config really bad; false if config doesn't include self
void _fillIsMaster(BSONObjBuilder&);
void _fillIsMasterHost(const Member*, vector<string>&, vector<string>&, vector<string>&);
const ReplSetConfig& config() { return *_cfg; }
@ -305,7 +316,9 @@ namespace mongo {
private:
Member* head() const { return _members.head(); }
Member* findById(unsigned id) const;
public:
const Member* findById(unsigned id) const;
private:
void _getTargets(list<Target>&, int &configVersion);
void getTargets(list<Target>&, int &configVersion);
void startThreads();
@ -321,8 +334,10 @@ namespace mongo {
void _syncDoInitialSync();
void syncDoInitialSync();
void _syncThread();
bool tryToGoLiveAsASecondary(OpTime&); // readlocks
void syncTail();
void syncApply(const BSONObj &o);
unsigned _syncRollback(OplogReader& r);
void syncRollback(OplogReader& r);
void syncFixUp(HowToFixUp& h, OplogReader& r);
public:
@ -342,9 +357,10 @@ namespace mongo {
/* call after constructing to start - returns fairly quickly after la[unching its threads */
void go() { _go(); }
void fatal() { _fatal(); }
bool isPrimary();
bool isSecondary();
bool isPrimary() { return box.getState().primary(); }
bool isSecondary() { return box.getState().secondary(); }
MemberState state() const { return ReplSetImpl::state(); }
string name() const { return ReplSetImpl::name(); }
const ReplSetConfig& config() { return ReplSetImpl::config(); }
@ -364,7 +380,10 @@ namespace mongo {
bool lockedByMe() { return RSBase::lockedByMe(); }
// heartbeat msg to send to others; descriptive diagnostic info
string hbmsg() const { return _hbmsg; }
string hbmsg() const {
if( time(0)-_hbmsgTime > 120 ) return "";
return _hbmsg;
}
};
/** base class for repl set commands. checks basic things such as in rs mode before the command
@ -386,6 +405,8 @@ namespace mongo {
if( theReplSet == 0 ) {
result.append("startupStatus", ReplSet::startupStatus);
errmsg = ReplSet::startupStatusMsg.empty() ? "replset unknown error 2" : ReplSet::startupStatusMsg;
if( ReplSet::startupStatus == 3 )
result.append("info", "run rs.initiate(...) if not yet done for the set");
return false;
}
return true;
@ -395,19 +416,10 @@ namespace mongo {
/** inlines ----------------- */
inline Member::Member(HostAndPort h, unsigned ord, const ReplSetConfig::MemberCfg *c, bool self) :
_config(c), _h(h), _hbinfo(ord) {
if( self ) {
_hbinfo.health = 1.0;
}
}
inline bool ReplSet::isPrimary() {
/* todo replset */
return box.getState().primary();
}
inline bool ReplSet::isSecondary() {
return box.getState().secondary();
_config(*c), _h(h), _hbinfo(ord)
{
if( self )
_hbinfo.health = 1.0;
}
}

View File

@ -31,6 +31,16 @@ namespace mongo {
void logOpInitiate(const bo&);
void assertOnlyHas(BSONObj o, const set<string>& fields) {
BSONObj::iterator i(o);
while( i.more() ) {
BSONElement e = i.next();
if( !fields.count( e.fieldName() ) ) {
uasserted(13434, str::stream() << "unexpected field '" << e.fieldName() << "'in object");
}
}
}
list<HostAndPort> ReplSetConfig::otherMemberHostnames() const {
list<HostAndPort> L;
for( vector<MemberCfg>::const_iterator i = members.begin(); i != members.end(); i++ ) {
@ -42,7 +52,7 @@ namespace mongo {
/* comment MUST only be set when initiating the set by the initiator */
void ReplSetConfig::saveConfigLocally(bo comment) {
check();
checkRsConfig();
log() << "replSet info saving a newer config version to local.system.replset" << rsLog;
{
writelock lk("");
@ -81,6 +91,8 @@ namespace mongo {
if( votes != 1 ) b << "votes" << votes;
if( priority != 1.0 ) b << "priority" << priority;
if( arbiterOnly ) b << "arbiterOnly" << true;
if( slaveDelay ) b << "slaveDelay" << slaveDelay;
if( hidden ) b << "hidden" << hidden;
return b.obj();
}
@ -114,10 +126,18 @@ namespace mongo {
mchk(_id >= 0 && _id <= 255);
mchk(priority >= 0 && priority <= 1000);
mchk(votes >= 0 && votes <= 100);
uassert(13419, "replica set config : this version of mongo only supports priorities 0 and 1", priority == 0 || priority == 1);
uassert(13419, "this version of mongod only supports priorities 0 and 1", priority == 0 || priority == 1);
uassert(13437, "slaveDelay requires priority be zero", slaveDelay == 0 || priority == 0);
uassert(13438, "bad slaveDelay value", slaveDelay >= 0 && slaveDelay <= 3600 * 24 * 366);
uassert(13439, "priority must be 0 when hidden=true", priority == 0 || !hidden);
}
/** @param o old config
@param n new config
*/
/*static*/ bool ReplSetConfig::legalChange(const ReplSetConfig& o, const ReplSetConfig& n, string& errmsg) {
assert( theReplSet );
if( o._id != n._id ) {
errmsg = "set name may not change";
return false;
@ -131,9 +151,28 @@ namespace mongo {
return false;
}
map<HostAndPort,const ReplSetConfig::MemberCfg*> old;
for( vector<ReplSetConfig::MemberCfg>::const_iterator i = o.members.begin(); i != o.members.end(); i++ ) {
old[i->h] = &(*i);
}
int me = 0;
for( vector<ReplSetConfig::MemberCfg>::const_iterator i = n.members.begin(); i != n.members.end(); i++ ) {
const ReplSetConfig::MemberCfg& m = *i;
if( old.count(m.h) ) {
if( old[m.h]->_id != m._id ) {
log() << "replSet reconfig error with member: " << m.h.toString() << rsLog;
uasserted(13432, "_id may not change for members");
}
}
if( m.h.isSelf() )
me++;
}
uassert(13433, "can't find self in new replset config", me == 1);
/* TODO : MORE CHECKS HERE */
cout << "TODO : don't allow removal of a node until we handle it at the removed node end." << endl;
log() << "replSet TODO : don't allow removal of a node until we handle it at the removed node end?" << endl;
// we could change its votes to zero perhaps instead as a short term...
return true;
@ -144,7 +183,7 @@ namespace mongo {
_ok = false;
}
void ReplSetConfig::check() const {
void ReplSetConfig::checkRsConfig() const {
uassert(13132,
"nonmatching repl set name in _id field; check --replSet command line",
_id == cmdLine.ourSetName());
@ -154,6 +193,10 @@ namespace mongo {
}
void ReplSetConfig::from(BSONObj o) {
static const string legal[] = {"_id","version", "members","settings"};
static const set<string> legals(legal, legal + 4);
assertOnlyHas(o, legals);
md5 = o.md5();
_id = o["_id"].String();
if( o["version"].ok() ) {
@ -170,7 +213,7 @@ namespace mongo {
if( settings["heartbeatTimeout"].ok() )
ho.heartbeatTimeoutMillis = (unsigned) (settings["heartbeatTimeout"].Number() * 1000);
ho.check();
try { getLastErrorDefaults = settings["getLastErrorDefaults"].Obj(); } catch(...) { }
try { getLastErrorDefaults = settings["getLastErrorDefaults"].Obj().copy(); } catch(...) { }
}
set<string> hosts;
@ -188,6 +231,10 @@ namespace mongo {
BSONObj mobj = members[i].Obj();
MemberCfg m;
try {
static const string legal[] = {"_id","votes","priority","host","hidden","slaveDelay","arbiterOnly"};
static const set<string> legals(legal, legal + 7);
assertOnlyHas(mobj, legals);
try {
m._id = (int) mobj["_id"].Number();
} catch(...) {
@ -205,6 +252,9 @@ namespace mongo {
if( m.h.isLocalHost() )
localhosts++;
m.arbiterOnly = mobj.getBoolField("arbiterOnly");
m.slaveDelay = mobj["slaveDelay"].numberInt();
if( mobj.hasElement("hidden") )
m.hidden = mobj.getBoolField("hidden");
if( mobj.hasElement("priority") )
m.priority = mobj["priority"].Number();
if( mobj.hasElement("votes") )
@ -220,7 +270,7 @@ namespace mongo {
catch(DBException& e) {
log() << "replSet cfg parsing exception for members[" << i << "] " << e.what() << rsLog;
stringstream ss;
ss << "replSet members[" << i << "] bad config object";
ss << "bad config for member[" << i << "] " << e.what();
uassert(13135, ss.str(), false);
}
if( !(ords.count(m._id) == 0 && hosts.count(m.h.toString()) == 0) ) {
@ -252,9 +302,8 @@ namespace mongo {
clear();
int level = 2;
DEV level = 0;
//log(0) << "replSet load config from: " << h.toString() << rsLog;
auto_ptr<DBClientCursor> c;
BSONObj cfg;
int v = -5;
try {
if( h.isSelf() ) {
@ -287,13 +336,28 @@ namespace mongo {
}
v = -4;
ScopedConn conn(h.toString());
v = -3;
c = conn->query(rsConfigNs);
if( c.get() == 0 ) {
version = v; return;
unsigned long long count = 0;
try {
ScopedConn conn(h.toString());
v = -3;
cfg = conn.findOne(rsConfigNs, Query()).getOwned();
count = conn.count(rsConfigNs);
}
if( !c->more() ) {
catch ( DBException& e) {
if ( !h.isSelf() ) {
throw;
}
// on startup, socket is not listening yet
DBDirectClient cli;
cfg = cli.findOne( rsConfigNs, Query() ).getOwned();
count = cli.count(rsConfigNs);
}
if( count > 1 )
uasserted(13109, str::stream() << "multiple rows in " << rsConfigNs << " not supported host: " << h.toString());
if( cfg.isEmpty() ) {
version = EMPTYCONFIG;
return;
}
@ -305,9 +369,8 @@ namespace mongo {
return;
}
BSONObj o = c->nextSafe();
uassert(13109, "multiple rows in " + rsConfigNs + " not supported", !c->more());
from(o);
from(cfg);
checkRsConfig();
_ok = true;
log(level) << "replSet load config ok from " << (h.isSelf() ? "self" : h.toString()) << rsLog;
}

View File

@ -41,18 +41,27 @@ namespace mongo {
bool ok() const { return _ok; }
struct MemberCfg {
MemberCfg() : _id(-1), votes(1), priority(1.0), arbiterOnly(false) { }
MemberCfg() : _id(-1), votes(1), priority(1.0), arbiterOnly(false), slaveDelay(0), hidden(false) { }
int _id; /* ordinal */
unsigned votes; /* how many votes this node gets. default 1. */
HostAndPort h;
double priority; /* 0 means can never be primary */
bool arbiterOnly;
int slaveDelay; /* seconds. int rather than unsigned for convenient to/front bson conversion. */
bool hidden; /* if set, don't advertise to drives in isMaster. for non-primaries (priority 0) */
void check() const; /* check validity, assert if not. */
BSONObj asBson() const;
bool potentiallyHot() const {
return !arbiterOnly && priority > 0;
}
bool operator==(const MemberCfg& r) const {
return _id==r._id && votes == r.votes && h == r.h && priority == r.priority &&
arbiterOnly == r.arbiterOnly && slaveDelay == r.slaveDelay && hidden == r.hidden;
}
bool operator!=(const MemberCfg& r) const { return !(*this == r); }
};
vector<MemberCfg> members;
string _id;
int version;
@ -68,7 +77,7 @@ namespace mongo {
string toString() const { return asBson().toString(); }
/** validate the settings. does not call check() on each member, you have to do that separately. */
void check() const;
void checkRsConfig() const;
/** check if modification makes sense */
static bool legalChange(const ReplSetConfig& old, const ReplSetConfig& n, string& errmsg);

View File

@ -66,7 +66,7 @@ namespace mongo {
void _logOpObjRS(const BSONObj& op);
bool copyCollectionFromRemote(const string& host, const string& ns, const BSONObj& query, string errmsg);
bool copyCollectionFromRemote(const string& host, const string& ns, const BSONObj& query, string &errmsg, bool logforrepl);
static void emptyOplog() {
writelock lk(rsoplog);

View File

@ -32,10 +32,12 @@ using namespace mongoutils;
namespace mongo {
/* throws
@param initial -
/* called on a reconfig AND on initiate
throws
@param initial true when initiating
*/
void checkAllMembersUpForConfigChange(const ReplSetConfig& cfg, bool initial) {
void checkMembersUpForConfigChange(const ReplSetConfig& cfg, bool initial) {
int failures = 0;
int me = 0;
for( vector<ReplSetConfig::MemberCfg>::const_iterator i = cfg.members.begin(); i != cfg.members.end(); i++ ) {
if( i->h.isSelf() ) {
@ -45,7 +47,7 @@ namespace mongo {
}
}
}
uassert(13278, "bad config?", me <= 1);
uassert(13278, "bad config - dups?", me <= 1); // dups?
uassert(13279, "can't find self in the replset config", me == 1);
for( vector<ReplSetConfig::MemberCfg>::const_iterator i = cfg.members.begin(); i != cfg.members.end(); i++ ) {
@ -62,12 +64,11 @@ namespace mongo {
}
}
catch(DBException& e) {
log() << "replSet requestHeartbeat " << i->h.toString() << " : " << e.toString() << rsLog;
log() << "replSet cmufcc requestHeartbeat " << i->h.toString() << " : " << e.toString() << rsLog;
}
catch(...) {
log() << "replSet error exception in requestHeartbeat?" << rsLog;
log() << "replSet cmufcc error exception in requestHeartbeat?" << rsLog;
}
cout << "TEMP hb res cfg change:" << res.toString() << endl;
if( res.getBoolField("mismatch") )
uasserted(13145, "set name does not match the set name host " + i->h.toString() + " expects");
if( *res.getStringField("set") ) {
@ -83,9 +84,31 @@ namespace mongo {
}
}
if( !ok && !res["rs"].trueValue() ) {
if( !res.isEmpty() )
if( !res.isEmpty() ) {
/* strange. got a response, but not "ok". log it. */
log() << "replSet warning " << i->h.toString() << " replied: " << res.toString() << rsLog;
uasserted(13144, "need members up to initiate/reconfig, not ok: " + i->h.toString());
}
bool allowFailure = false;
failures++;
if( res.isEmpty() && !initial && failures == 1 ) {
/* for now we are only allowing 1 node to be down on a reconfig. this can be made to be a minority
trying to keep change small as release is near.
*/
const Member* m = theReplSet->findById( i->_id );
if( m ) {
// ok, so this was an existing member (wouldn't make sense to add to config a new member that is down)
assert( m->h().toString() == i->h.toString() );
allowFailure = true;
}
}
if( !allowFailure ) {
string msg = string("need members up to initiate, not ok : ") + i->h.toString();
if( !initial )
msg = string("need most members up to reconfigure, not ok : ") + i->h.toString();
uasserted(13144, msg);
}
}
}
if( initial ) {
@ -175,8 +198,10 @@ namespace mongo {
configObj = cmdObj["replSetInitiate"].Obj();
}
bool parsed = false;
try {
ReplSetConfig newConfig(configObj);
parsed = true;
if( newConfig.version > 1 ) {
errmsg = "can't initiate with a version number greater than 1";
@ -185,7 +210,7 @@ namespace mongo {
log() << "replSet replSetInitiate config object parses ok, " << newConfig.members.size() << " members specified" << rsLog;
checkAllMembersUpForConfigChange(newConfig, true);
checkMembersUpForConfigChange(newConfig, true);
log() << "replSet replSetInitiate all members seem up" << rsLog;
@ -199,7 +224,11 @@ namespace mongo {
}
catch( DBException& e ) {
log() << "replSet replSetInitiate exception: " << e.what() << rsLog;
throw;
if( !parsed )
errmsg = string("couldn't parse cfg object ") + e.what();
else
errmsg = string("couldn't initiate : ") + e.what();
return false;
}
return true;

View File

@ -40,7 +40,8 @@ namespace mongo {
RS_STARTUP2,
RS_UNKNOWN, /* remote node not yet reached */
RS_ARBITER,
RS_DOWN /* node not reachable for a report */
RS_DOWN, /* node not reachable for a report */
RS_ROLLBACK
} s;
MemberState(MS ms = RS_UNKNOWN) : s(ms) { }
@ -51,6 +52,9 @@ namespace mongo {
bool recovering() const { return s == RS_RECOVERING; }
bool startup2() const { return s == RS_STARTUP2; }
bool fatal() const { return s == RS_FATAL; }
bool rollback() const { return s == RS_ROLLBACK; }
string toString() const;
bool operator==(const MemberState& r) const { return s == r.s; }
bool operator!=(const MemberState& r) const { return s != r.s; }
@ -61,26 +65,35 @@ namespace mongo {
class HeartbeatInfo {
unsigned _id;
public:
HeartbeatInfo() : _id(0xffffffff),skew(INT_MIN) { }
HeartbeatInfo() : _id(0xffffffff),hbstate(MemberState::RS_UNKNOWN),health(-1.0),downSince(0),skew(INT_MIN) { }
HeartbeatInfo(unsigned id);
bool up() const { return health > 0; }
unsigned id() const { return _id; }
MemberState hbstate;
double health;
time_t upSince;
long long downSince;
time_t lastHeartbeat;
string lastHeartbeatMsg;
OpTime opTime;
int skew;
bool up() const { return health > 0; }
/** health is set to -1 on startup. that means we haven't even checked yet. 0 means we checked and it failed. */
bool maybeUp() const { return health != 0; }
long long timeDown() const; // ms
/* true if changed in a way of interest to the repl set manager. */
bool changed(const HeartbeatInfo& old) const;
};
inline HeartbeatInfo::HeartbeatInfo(unsigned id) : _id(id) {
health = -1.0;
lastHeartbeat = upSince = 0;
skew = INT_MIN;
hbstate = MemberState::RS_UNKNOWN;
health = -1.0;
downSince = 0;
lastHeartbeat = upSince = 0;
skew = INT_MIN;
}
inline bool HeartbeatInfo::changed(const HeartbeatInfo& old) const {

View File

@ -62,6 +62,14 @@ namespace mongo {
using namespace bson;
bool copyCollectionFromRemote(const string& host, const string& ns, const BSONObj& query, string& errmsg, bool logforrepl);
void incRBID();
class rsfatal : public std::exception {
public:
virtual const char* what() const throw(){ return "replica set fatal exception"; }
};
struct DocID {
const char *ns;
be _id;
@ -81,6 +89,8 @@ namespace mongo {
/* collections to drop */
set<string> toDrop;
set<string> collectionsToResync;
OpTime commonPoint;
DiskLoc commonPointOurDiskloc;
@ -113,17 +123,59 @@ namespace mongo {
if( *op == 'c' ) {
be first = o.firstElement();
NamespaceString s(d.ns); // foo.$cmd
if( string("create") == first.fieldName() ) {
/* Create collection operation
{ ts: ..., h: ..., op: "c", ns: "foo.$cmd", o: { create: "abc", ... } }
*/
string ns = s.db + '.' + o["create"].String(); // -> foo.abc
h.toDrop.insert(ns);
string cmdname = first.fieldName();
Command *cmd = Command::findCommand(cmdname.c_str());
if( cmd == 0 ) {
log() << "replSet warning rollback no suchcommand " << first.fieldName() << " - different mongod versions perhaps?" << rsLog;
return;
}
else {
log() << "replSet WARNING can't roll back this command yet: " << o.toString() << rsLog;
else {
/* findandmodify - tranlated?
godinsert?,
renamecollection a->b. just resync a & b
*/
if( cmdname == "create" ) {
/* Create collection operation
{ ts: ..., h: ..., op: "c", ns: "foo.$cmd", o: { create: "abc", ... } }
*/
string ns = s.db + '.' + o["create"].String(); // -> foo.abc
h.toDrop.insert(ns);
return;
}
else if( cmdname == "drop" ) {
string ns = s.db + '.' + first.valuestr();
h.collectionsToResync.insert(ns);
return;
}
else if( cmdname == "dropIndexes" || cmdname == "deleteIndexes" ) {
/* TODO: this is bad. we simply full resync the collection here, which could be very slow. */
log() << "replSet info rollback of dropIndexes is slow in this version of mongod" << rsLog;
string ns = s.db + '.' + first.valuestr();
h.collectionsToResync.insert(ns);
return;
}
else if( cmdname == "renameCollection" ) {
/* TODO: slow. */
log() << "replSet info rollback of renameCollection is slow in this version of mongod" << rsLog;
string from = first.valuestr();
string to = o["to"].String();
h.collectionsToResync.insert(from);
h.collectionsToResync.insert(to);
return;
}
else if( cmdname == "reIndex" ) {
return;
}
else if( cmdname == "dropDatabase" ) {
log() << "replSet error rollback : can't rollback drop database full resync will be required" << rsLog;
log() << "replSet " << o.toString() << rsLog;
throw rsfatal();
}
else {
log() << "replSet error can't rollback this command yet: " << o.toString() << rsLog;
log() << "replSet cmdname=" << cmdname << rsLog;
throw rsfatal();
}
}
}
@ -141,8 +193,6 @@ namespace mongo {
static void syncRollbackFindCommonPoint(DBClientConnection *them, HowToFixUp& h) {
static time_t last;
if( time(0)-last < 60 ) {
// this could put a lot of load on someone else, don't repeat too often
sleepsecs(10);
throw "findcommonpoint waiting a while before trying again";
}
last = time(0);
@ -170,12 +220,14 @@ namespace mongo {
BSONObj theirObj = t->nextSafe();
OpTime theirTime = theirObj["ts"]._opTime();
if( 1 ) {
{
long long diff = (long long) ourTime.getSecs() - ((long long) theirTime.getSecs());
/* diff could be positive, negative, or zero */
log() << "replSet info syncRollback diff in end of log times : " << diff << " seconds" << rsLog;
log() << "replSet info rollback our last optime: " << ourTime.toStringPretty() << rsLog;
log() << "replSet info rollback their last optime: " << theirTime.toStringPretty() << rsLog;
log() << "replSet info rollback diff in end of log times: " << diff << " seconds" << rsLog;
if( diff > 3600 ) {
log() << "replSet syncRollback too long a time period for a rollback." << rsLog;
log() << "replSet rollback too long a time period for a rollback." << rsLog;
throw "error not willing to roll back more than one hour of data";
}
}
@ -197,16 +249,35 @@ namespace mongo {
refetch(h, ourObj);
if( !t->more() ) {
log() << "replSet rollback error RS100 reached beginning of remote oplog" << rsLog;
log() << "replSet them: " << them->toString() << " scanned: " << scanned << rsLog;
log() << "replSet theirTime: " << theirTime.toStringLong() << rsLog;
log() << "replSet ourTime: " << ourTime.toStringLong() << rsLog;
throw "RS100 reached beginning of remote oplog [2]";
}
theirObj = t->nextSafe();
theirTime = theirObj["ts"]._opTime();
u.advance();
if( !u.ok() ) throw "reached beginning of local oplog";
if( !u.ok() ) {
log() << "replSet rollback error RS101 reached beginning of local oplog" << rsLog;
log() << "replSet them: " << them->toString() << " scanned: " << scanned << rsLog;
log() << "replSet theirTime: " << theirTime.toStringLong() << rsLog;
log() << "replSet ourTime: " << ourTime.toStringLong() << rsLog;
throw "RS101 reached beginning of local oplog [1]";
}
ourObj = u.current();
ourTime = ourObj["ts"]._opTime();
}
else if( theirTime > ourTime ) {
/* todo: we could hit beginning of log here. exception thrown is ok but not descriptive, so fix up */
if( !t->more() ) {
log() << "replSet rollback error RS100 reached beginning of remote oplog" << rsLog;
log() << "replSet them: " << them->toString() << " scanned: " << scanned << rsLog;
log() << "replSet theirTime: " << theirTime.toStringLong() << rsLog;
log() << "replSet ourTime: " << ourTime.toStringLong() << rsLog;
throw "RS100 reached beginning of remote oplog [1]";
}
theirObj = t->nextSafe();
theirTime = theirObj["ts"]._opTime();
}
@ -214,7 +285,13 @@ namespace mongo {
// theirTime < ourTime
refetch(h, ourObj);
u.advance();
if( !u.ok() ) throw "reached beginning of local oplog";
if( !u.ok() ) {
log() << "replSet rollback error RS101 reached beginning of local oplog" << rsLog;
log() << "replSet them: " << them->toString() << " scanned: " << scanned << rsLog;
log() << "replSet theirTime: " << theirTime.toStringLong() << rsLog;
log() << "replSet ourTime: " << ourTime.toStringLong() << rsLog;
throw "RS101 reached beginning of local oplog [2]";
}
ourObj = u.current();
ourTime = ourObj["ts"]._opTime();
}
@ -226,7 +303,19 @@ namespace mongo {
bson::bo goodVersionOfObject;
};
void ReplSetImpl::syncFixUp(HowToFixUp& h, OplogReader& r) {
static void setMinValid(bo newMinValid) {
try {
log() << "replSet minvalid=" << newMinValid["ts"]._opTime().toStringLong() << rsLog;
}
catch(...) { }
{
Helpers::putSingleton("local.replset.minvalid", newMinValid);
Client::Context cx( "local." );
cx.db()->flushFiles(true);
}
}
void ReplSetImpl::syncFixUp(HowToFixUp& h, OplogReader& r) {
DBClientConnection *them = r.conn();
// fetch all first so we needn't handle interruption in a fancy way
@ -237,6 +326,7 @@ namespace mongo {
bo newMinValid;
/* fetch all the goodVersions of each document from current primary */
DocID d;
unsigned long long n = 0;
try {
@ -258,43 +348,98 @@ namespace mongo {
}
newMinValid = r.getLastOp(rsoplog);
if( newMinValid.isEmpty() ) {
sethbmsg("syncRollback error newMinValid empty?");
sethbmsg("rollback error newMinValid empty?");
return;
}
}
catch(DBException& e) {
sethbmsg(str::stream() << "syncRollback re-get objects: " << e.toString(),0);
log() << "syncRollback couldn't re-get ns:" << d.ns << " _id:" << d._id << ' ' << n << '/' << h.toRefetch.size() << rsLog;
sethbmsg(str::stream() << "rollback re-get objects: " << e.toString(),0);
log() << "rollback couldn't re-get ns:" << d.ns << " _id:" << d._id << ' ' << n << '/' << h.toRefetch.size() << rsLog;
throw e;
}
sethbmsg("syncRollback 3.5");
MemoryMappedFile::flushAll(true);
sethbmsg("rollback 3.5");
if( h.rbid != getRBID(r.conn()) ) {
// our source rolled back itself. so the data we received isn't necessarily consistent.
sethbmsg("syncRollback rbid on source changed during rollback, cancelling this attempt");
sethbmsg("rollback rbid on source changed during rollback, cancelling this attempt");
return;
}
// update them
sethbmsg(str::stream() << "syncRollback 4 n:" << goodVersions.size());
sethbmsg(str::stream() << "rollback 4 n:" << goodVersions.size());
bool warn = false;
assert( !h.commonPointOurDiskloc.isNull() );
MemoryMappedFile::flushAll(true);
dbMutex.assertWriteLocked();
/* we have items we are writing that aren't from a point-in-time. thus best not to come online
until we get to that point in freshness. */
try {
log() << "replSet set minvalid=" << newMinValid["ts"]._opTime().toString() << rsLog;
}
catch(...){}
Helpers::putSingleton("local.replset.minvalid", newMinValid);
setMinValid(newMinValid);
/** any full collection resyncs required? */
if( !h.collectionsToResync.empty() ) {
for( set<string>::iterator i = h.collectionsToResync.begin(); i != h.collectionsToResync.end(); i++ ) {
string ns = *i;
sethbmsg(str::stream() << "rollback 4.1 coll resync " << ns);
Client::Context c(*i, dbpath, 0, /*doauth*/false);
try {
bob res;
string errmsg;
dropCollection(ns, errmsg, res);
{
dbtemprelease r;
bool ok = copyCollectionFromRemote(them->getServerAddress(), ns, bo(), errmsg, false);
if( !ok ) {
log() << "replSet rollback error resyncing collection " << ns << ' ' << errmsg << rsLog;
throw "rollback error resyncing rollection [1]";
}
}
}
catch(...) {
log() << "replset rollback error resyncing collection " << ns << rsLog;
throw "rollback error resyncing rollection [2]";
}
}
/** first drop collections to drop - that might make things faster below actually if there were subsequent inserts */
/* we did more reading from primary, so check it again for a rollback (which would mess us up), and
make minValid newer.
*/
sethbmsg("rollback 4.2");
{
string err;
try {
newMinValid = r.getLastOp(rsoplog);
if( newMinValid.isEmpty() ) {
err = "can't get minvalid from primary";
} else {
setMinValid(newMinValid);
}
}
catch(...) {
err = "can't get/set minvalid";
}
if( h.rbid != getRBID(r.conn()) ) {
// our source rolled back itself. so the data we received isn't necessarily consistent.
// however, we've now done writes. thus we have a problem.
err += "rbid at primary changed during resync/rollback";
}
if( !err.empty() ) {
log() << "replSet error rolling back : " << err << ". A full resync will be necessary." << rsLog;
/* todo: reset minvalid so that we are permanently in fatal state */
/* todo: don't be fatal, but rather, get all the data first. */
sethbmsg("rollback error");
throw rsfatal();
}
}
sethbmsg("rollback 4.3");
}
sethbmsg("rollback 4.6");
/** drop collections to drop before doing individual fixups - that might make things faster below actually if there were subsequent inserts to rollback */
for( set<string>::iterator i = h.toDrop.begin(); i != h.toDrop.end(); i++ ) {
Client::Context c(*i, dbpath, 0, /*doauth*/false);
try {
@ -308,6 +453,7 @@ namespace mongo {
}
}
sethbmsg("rollback 4.7");
Client::Context c(rsoplog, dbpath, 0, /*doauth*/false);
NamespaceDetails *oplogDetails = nsdetails(rsoplog);
uassert(13423, str::stream() << "replSet error in rollback can't find " << rsoplog, oplogDetails);
@ -320,7 +466,12 @@ namespace mongo {
bo pattern = d._id.wrap(); // { _id : ... }
try {
assert( d.ns && *d.ns );
if( h.collectionsToResync.count(d.ns) ) {
/* we just synced this entire collection */
continue;
}
/* keep an archive of items rolled back */
shared_ptr<RemoveSaver>& rs = removeSavers[d.ns];
if ( ! rs )
rs.reset( new RemoveSaver( "rollback" , "" , d.ns ) );
@ -343,7 +494,7 @@ namespace mongo {
long long start = Listener::getElapsedTimeMillis();
DiskLoc loc = Helpers::findOne(d.ns, pattern, false);
if( Listener::getElapsedTimeMillis() - start > 200 )
log() << "replSet warning roll back slow no _id index for " << d.ns << rsLog;
log() << "replSet warning roll back slow no _id index for " << d.ns << " perhaps?" << rsLog;
//would be faster but requires index: DiskLoc loc = Helpers::findById(nsd, pattern);
if( !loc.isNull() ) {
try {
@ -411,9 +562,9 @@ namespace mongo {
removeSavers.clear(); // this effectively closes all of them
sethbmsg(str::stream() << "syncRollback 5 d:" << deletes << " u:" << updates);
sethbmsg(str::stream() << "rollback 5 d:" << deletes << " u:" << updates);
MemoryMappedFile::flushAll(true);
sethbmsg("syncRollback 6");
sethbmsg("rollback 6");
// clean up oplog
log(2) << "replSet rollback truncate oplog after " << h.commonPoint.toStringPretty() << rsLog;
@ -423,59 +574,99 @@ namespace mongo {
/* reset cached lastoptimewritten and h value */
loadLastOpTimeWritten();
sethbmsg("syncRollback 7");
sethbmsg("rollback 7");
MemoryMappedFile::flushAll(true);
// done
if( warn )
sethbmsg("issues during syncRollback, see log");
else
sethbmsg("syncRollback done");
sethbmsg("rollback done");
}
void ReplSetImpl::syncRollback(OplogReader&r) {
unsigned s = _syncRollback(r);
if( s )
sleepsecs(s);
}
unsigned ReplSetImpl::_syncRollback(OplogReader&r) {
assert( !lockedByMe() );
assert( !dbMutex.atLeastReadLocked() );
sethbmsg("syncRollback 0");
sethbmsg("rollback 0");
writelocktry lk(rsoplog, 20000);
if( !lk.got() ) {
sethbmsg("syncRollback couldn't get write lock in a reasonable time");
sleepsecs(2);
return;
sethbmsg("rollback couldn't get write lock in a reasonable time");
return 2;
}
if( box.getState().secondary() ) {
/* by doing this, we will not service reads (return an error as we aren't in secondary staate.
that perhaps is moot becasue of the write lock above, but that write lock probably gets deferred
or removed or yielded later anyway.
also, this is better for status reporting - we know what is happening.
*/
box.change(MemberState::RS_ROLLBACK, _self);
}
HowToFixUp how;
sethbmsg("syncRollback 1");
sethbmsg("rollback 1");
{
r.resetCursor();
/*DBClientConnection us(false, 0, 0);
string errmsg;
if( !us.connect(HostAndPort::me().toString(),errmsg) ) {
sethbmsg("syncRollback connect to self failure" + errmsg);
sethbmsg("rollback connect to self failure" + errmsg);
return;
}*/
sethbmsg("syncRollback 2 FindCommonPoint");
sethbmsg("rollback 2 FindCommonPoint");
try {
syncRollbackFindCommonPoint(r.conn(), how);
}
catch( const char *p ) {
sethbmsg(string("syncRollback 2 error ") + p);
sleepsecs(10);
return;
sethbmsg(string("rollback 2 error ") + p);
return 10;
}
catch( rsfatal& ) {
_fatal();
return 2;
}
catch( DBException& e ) {
sethbmsg(string("syncRollback 2 exception ") + e.toString() + "; sleeping 1 min");
sethbmsg(string("rollback 2 exception ") + e.toString() + "; sleeping 1 min");
dbtemprelease r;
sleepsecs(60);
throw;
}
}
sethbmsg("replSet syncRollback 3 fixup");
sethbmsg("replSet rollback 3 fixup");
syncFixUp(how, r);
{
incRBID();
try {
syncFixUp(how, r);
}
catch( rsfatal& ) {
sethbmsg("rollback fixup error");
_fatal();
return 2;
}
catch(...) {
incRBID(); throw;
}
incRBID();
/* success - leave "ROLLBACK" state
can go to SECONDARY once minvalid is achieved
*/
box.change(MemberState::RS_RECOVERING, _self);
}
return 0;
}
}

View File

@ -24,8 +24,11 @@ namespace mongo {
using namespace bson;
extern unsigned replSetForceInitialSyncFailure;
void startSyncThread() {
Client::initThread("rs_sync");
cc().iAmSyncThread();
theReplSet->syncThread();
cc().shutdown();
}
@ -67,7 +70,14 @@ namespace mongo {
return false;
}
r.query(rsoplog, bo());
{
BSONObjBuilder q;
q.appendDate("$gte", applyGTE.asDate());
BSONObjBuilder query;
query.append("ts", q.done());
BSONObj queryObj = query.done();
r.query(rsoplog, queryObj);
}
assert( r.haveCursor() );
/* we lock outside the loop to avoid the overhead of locking on every operation. server isn't usable yet anyway! */
@ -91,6 +101,7 @@ namespace mongo {
// todo : use exhaust
unsigned long long n = 0;
while( 1 ) {
if( !r.more() )
break;
BSONObj o = r.nextSafe(); /* note we might get "not master" at some point */
@ -103,9 +114,14 @@ namespace mongo {
anymore. assumePrimary is in the db lock so we are safe as long as
we check after we locked above. */
const Member *p1 = box.getPrimary();
if( p1 != primary ) {
log() << "replSet primary was:" << primary->fullName() << " now:" <<
(p1 != 0 ? p1->fullName() : "none") << rsLog;
if( p1 != primary || replSetForceInitialSyncFailure ) {
int f = replSetForceInitialSyncFailure;
if( f > 0 ) {
replSetForceInitialSyncFailure = f-1;
log() << "replSet test code invoked, replSetForceInitialSyncFailure" << rsLog;
}
log() << "replSet primary was:" << primary->fullName() << " now:" <<
(p1 != 0 ? p1->fullName() : "none") << rsLog;
throw DBException("primary changed",0);
}
@ -131,6 +147,32 @@ namespace mongo {
return true;
}
/* should be in RECOVERING state on arrival here.
readlocks
@return true if transitioned to SECONDARY
*/
bool ReplSetImpl::tryToGoLiveAsASecondary(OpTime& /*out*/ minvalid) {
bool golive = false;
{
readlock lk("local.replset.minvalid");
BSONObj mv;
if( Helpers::getSingleton("local.replset.minvalid", mv) ) {
minvalid = mv["ts"]._opTime();
if( minvalid <= lastOpTimeWritten ) {
golive=true;
}
}
else
golive = true; /* must have been the original member */
}
if( golive ) {
sethbmsg("");
changeState(MemberState::RS_SECONDARY);
}
return golive;
}
/* tail the primary's oplog. ok to return, will be re-called. */
void ReplSetImpl::syncTail() {
// todo : locking vis a vis the mgr...
@ -147,14 +189,19 @@ namespace mongo {
{
BSONObj remoteOldestOp = r.findOne(rsoplog, Query());
OpTime ts = remoteOldestOp["ts"]._opTime();
DEV log() << "remoteOldestOp: " << ts.toStringPretty() << endl;
else log(3) << "remoteOldestOp: " << ts.toStringPretty() << endl;
DEV log() << "replSet remoteOldestOp: " << ts.toStringLong() << rsLog;
else log(3) << "replSet remoteOldestOp: " << ts.toStringLong() << rsLog;
DEV {
// debugging sync1.js...
log() << "replSet lastOpTimeWritten: " << lastOpTimeWritten.toStringLong() << rsLog;
log() << "replSet our state: " << state().toString() << rsLog;
}
if( lastOpTimeWritten < ts ) {
log() << "replSet error too stale to catch up, at least from primary " << hn << rsLog;
log() << "replSet our last optime : " << lastOpTimeWritten.toStringPretty() << rsLog;
log() << "replSet oldest at " << hn << " : " << ts.toStringPretty() << rsLog;
log() << "replSet error RS102 too stale to catch up, at least from primary: " << hn << rsLog;
log() << "replSet our last optime : " << lastOpTimeWritten.toStringLong() << rsLog;
log() << "replSet oldest at " << hn << " : " << ts.toStringLong() << rsLog;
log() << "replSet See http://www.mongodb.org/display/DOCS/Resyncing+a+Very+Stale+Replica+Set+Member" << rsLog;
sethbmsg("error too stale to catch up");
sethbmsg("error RS102 too stale to catch up");
sleepsecs(120);
return;
}
@ -203,8 +250,8 @@ namespace mongo {
OpTime ts = o["ts"]._opTime();
long long h = o["h"].numberLong();
if( ts != lastOpTimeWritten || h != lastH ) {
log() << "TEMP our last op time written: " << lastOpTimeWritten.toStringPretty() << endl;
log() << "TEMP primary's GTE: " << ts.toStringPretty() << endl;
log(1) << "TEMP our last op time written: " << lastOpTimeWritten.toStringPretty() << endl;
log(1) << "TEMP primary's GTE: " << ts.toStringPretty() << endl;
/*
}*/
@ -213,7 +260,13 @@ namespace mongo {
}
}
while( 1 ) {
/* we have now checked if we need to rollback and we either don't have to or did it. */
{
OpTime minvalid;
tryToGoLiveAsASecondary(minvalid);
}
while( 1 ) {
while( 1 ) {
if( !r.moreInCurrentBatch() ) {
/* we need to occasionally check some things. between
@ -222,28 +275,13 @@ namespace mongo {
/* perhaps we should check this earlier? but not before the rollback checks. */
if( state().recovering() ) {
/* can we go to RS_SECONDARY state? we can if not too old and if minvalid achieved */
bool golive = false;
OpTime minvalid;
{
readlock lk("local.replset.minvalid");
BSONObj mv;
if( Helpers::getSingleton("local.replset.minvalid", mv) ) {
minvalid = mv["ts"]._opTime();
if( minvalid <= lastOpTimeWritten ) {
golive=true;
}
}
else
golive = true; /* must have been the original member */
}
bool golive = ReplSetImpl::tryToGoLiveAsASecondary(minvalid);
if( golive ) {
sethbmsg("");
log() << "replSet SECONDARY" << rsLog;
changeState(MemberState::RS_SECONDARY);
;
}
else {
sethbmsg(str::stream() << "still syncing, not yet to minValid optime " << minvalid.toString());
//log() << "TEMP " << lastOpTimeWritten.toString() << rsLog;
sethbmsg(str::stream() << "still syncing, not yet to minValid optime" << minvalid.toString());
}
/* todo: too stale capability */
@ -271,12 +309,40 @@ namespace mongo {
syncApply(o);
_logOpObjRS(o); /* with repl sets we write the ops to our oplog too: */
}
int sd = myConfig().slaveDelay;
if( sd ) {
const OpTime ts = o["ts"]._opTime();
long long a = ts.getSecs();
long long b = time(0);
long long lag = b - a;
long long sleeptime = sd - lag;
if( sleeptime > 0 ) {
uassert(12000, "rs slaveDelay differential too big check clocks and systems", sleeptime < 0x40000000);
log() << "replSet temp slavedelay sleep:" << sleeptime << rsLog;
if( sleeptime < 60 ) {
sleepsecs((int) sleeptime);
}
else {
// sleep(hours) would prevent reconfigs from taking effect & such!
long long waitUntil = b + sleeptime;
while( 1 ) {
sleepsecs(6);
if( time(0) >= waitUntil )
break;
if( box.getPrimary() != primary )
break;
if( myConfig().slaveDelay != sd ) // reconf
break;
}
}
}
}
}
}
r.tailCheck();
if( !r.haveCursor() ) {
log() << "replSet TEMP end syncTail pass with " << hn << rsLog;
// TODO : reuse our cnonection to the primary.
log(1) << "replSet end syncTail pass with " << hn << rsLog;
// TODO : reuse our connection to the primary.
return;
}
if( box.getPrimary() != primary )
@ -291,6 +357,10 @@ namespace mongo {
sleepsecs(1);
return;
}
if( sp.state.fatal() ) {
sleepsecs(5);
return;
}
/* later, we can sync from up secondaries if we want. tbd. */
if( sp.primary == 0 )

View File

@ -164,7 +164,7 @@ namespace mongo {
if( replSet ) {
/* todo: speed up the secondary case. as written here there are 2 mutex entries, it can be 1. */
if( isMaster() ) return;
notMasterUnless( pq.hasOption(QueryOption_SlaveOk) && theReplSet->isSecondary() );
notMasterUnless( pq.hasOption(QueryOption_SlaveOk) && theReplSet && theReplSet->isSecondary() );
} else {
notMasterUnless(isMaster() || pq.hasOption(QueryOption_SlaveOk) || replSettings.slave == SimpleSlave );
}

View File

@ -266,8 +266,8 @@ namespace mongo {
ss << "# databases: " << dbHolder.size() << '\n';
if( ClientCursor::byLocSize()>500 )
ss << "Cursors byLoc.size(): " << ClientCursor::byLocSize() << '\n';
if( ClientCursor::numCursors()>500 )
ss << "# Cursors: " << ClientCursor::numCursors() << '\n';
ss << "\nreplication: ";
if( *replInfo )

View File

@ -88,16 +88,17 @@ namespace mongo {
void _add(BSONObj& k, BSONObj o, DiskLoc* loc) {
if (!loc){
best.insert(make_pair(k,o));
best.insert(make_pair(k.getOwned(),o.getOwned()));
} else {
BSONObjBuilder b;
b.appendElements(o);
b.append("$diskLoc", loc->toBSONObj());
best.insert(make_pair(k, b.obj()));
best.insert(make_pair(k.getOwned(), b.obj().getOwned()));
}
}
void _addIfBetter(BSONObj& k, BSONObj o, BestMap::iterator i, DiskLoc* loc) {
/* todo : we don't correct approxSize here. */
const BSONObj& worstBestKey = i->first;
int c = worstBestKey.woCompare(k, order.pattern);
if ( c > 0 ) {
@ -124,7 +125,11 @@ namespace mongo {
BSONObj k = order.getKeyFromObject(o);
if ( (int) best.size() < limit ) {
approxSize += k.objsize();
uassert( 10128 , "too much key data for sort() with no index. add an index or specify a smaller limit", approxSize < 1 * 1024 * 1024 );
approxSize += o.objsize();
/* note : adjust when bson return limit adjusts. note this limit should be a bit higher. */
uassert( 10128 , "too much data for sort() with no index. add an index or specify a smaller limit", approxSize < 32 * 1024 * 1024 );
_add(k, o, loc);
return;
}

View File

@ -49,9 +49,7 @@ namespace mongo {
class CmdGetNonce : public Command {
public:
virtual bool requiresAuth() { return false; }
virtual bool logTheOp() {
return false;
}
virtual bool logTheOp() { return false; }
virtual bool slaveOk() const {
return true;
}

View File

@ -163,7 +163,7 @@ namespace mongo {
ss << usage.count;
ss << "</td><td>";
double per = 100 * ((double)usage.time)/elapsed;
ss << setprecision(4) << fixed << per << "%";
ss << setprecision(1) << fixed << per << "%";
ss << "</td>";
}

View File

@ -517,17 +517,19 @@ namespace mongo {
DEBUGUPDATE( "\t\t createNewFromMods root: " << root );
BSONObjIteratorSorted es( obj );
BSONElement e = es.next();
ModStateHolder::iterator m = _mods.lower_bound( root );
ModStateHolder::iterator mend = _mods.lower_bound( root + '{' );
StringBuilder buf(root.size() + 2 );
buf << root << (char)255;
ModStateHolder::iterator mend = _mods.lower_bound( buf.str() );
set<string> onedownseen;
while ( e.type() && m != mend ){
string field = root + e.fieldName();
FieldCompareResult cmp = compareDottedFieldNames( m->second.m->fieldName , field );
DEBUGUPDATE( "\t\t\t field:" << field << "\t mod:" << m->second.m->fieldName << "\t cmp:" << cmp );
DEBUGUPDATE( "\t\t\t field:" << field << "\t mod:" << m->second.m->fieldName << "\t cmp:" << cmp << "\t short: " << e.fieldName() );
switch ( cmp ){
@ -550,6 +552,13 @@ namespace mongo {
e = es.next();
m++;
}
else {
// this is a very weird case
// have seen it in production, but can't reproduce
// this assert prevents an inf. loop
// but likely isn't the correct solution
assert(0);
}
continue;
}
case LEFT_BEFORE: // Mod on a field that doesn't exist
@ -613,6 +622,8 @@ namespace mongo {
BSONObjIteratorSorted i( query );
while ( i.more() ){
BSONElement e = i.next();
if ( e.fieldName()[0] == '$' ) // for $atomic and anything else we add
continue;
if ( e.type() == Object && e.embeddedObject().firstElement().fieldName()[0] == '$' ){
// this means this is a $gt type filter, so don't make part of the new object

View File

@ -234,7 +234,7 @@ namespace BasicTests {
if ( y < 1000 || y > 2500 ){
cout << "sleeptest y: " << y << endl;
ASSERT( y >= 1000 );
ASSERT( y <= 100000 );
/* ASSERT( y <= 100000 ); */
}
}
}
@ -319,6 +319,9 @@ namespace BasicTests {
class LexNumCmp {
public:
void run() {
ASSERT( ! isNumber( (char)255 ) );
ASSERT_EQUALS( 0, lexNumCmp( "a", "a" ) );
ASSERT_EQUALS( -1, lexNumCmp( "a", "aa" ) );
ASSERT_EQUALS( 1, lexNumCmp( "aa", "a" ) );
@ -346,7 +349,7 @@ namespace BasicTests {
ASSERT_EQUALS( -1, lexNumCmp( "f12f", "f12g" ) );
ASSERT_EQUALS( 1, lexNumCmp( "f12g", "f12f" ) );
ASSERT_EQUALS( 1, lexNumCmp( "aa{", "aab" ) );
ASSERT_EQUALS( 1, lexNumCmp( "aa{", "aa1" ) );
ASSERT_EQUALS( -1, lexNumCmp( "aa{", "aa1" ) );
ASSERT_EQUALS( -1, lexNumCmp( "a1{", "a11" ) );
ASSERT_EQUALS( 1, lexNumCmp( "a1{a", "a1{" ) );
ASSERT_EQUALS( -1, lexNumCmp( "a1{", "a1{a" ) );
@ -355,6 +358,38 @@ namespace BasicTests {
ASSERT_EQUALS( -1 , lexNumCmp( "a.0" , "a.1" ) );
ASSERT_EQUALS( -1 , lexNumCmp( "a.0.b" , "a.1" ) );
ASSERT_EQUALS( -1 , lexNumCmp( "b." , "b.|" ) );
ASSERT_EQUALS( -1 , lexNumCmp( "b.0e" , (string("b.") + (char)255).c_str() ) );
ASSERT_EQUALS( -1 , lexNumCmp( "b." , "b.0e" ) );
ASSERT_EQUALS( 0, lexNumCmp( "238947219478347782934718234", "238947219478347782934718234"));
ASSERT_EQUALS( 0, lexNumCmp( "000238947219478347782934718234", "238947219478347782934718234"));
ASSERT_EQUALS( 1, lexNumCmp( "000238947219478347782934718235", "238947219478347782934718234"));
ASSERT_EQUALS( -1, lexNumCmp( "238947219478347782934718234", "238947219478347782934718234.1"));
ASSERT_EQUALS( 0, lexNumCmp( "238", "000238"));
ASSERT_EQUALS( 0, lexNumCmp( "002384", "0002384"));
ASSERT_EQUALS( 0, lexNumCmp( "00002384", "0002384"));
ASSERT_EQUALS( 0, lexNumCmp( "0", "0"));
ASSERT_EQUALS( 0, lexNumCmp( "0000", "0"));
ASSERT_EQUALS( 0, lexNumCmp( "0", "000"));
ASSERT_EQUALS( -1, lexNumCmp( "0000", "0.0"));
ASSERT_EQUALS( 1, lexNumCmp( "2380", "238"));
ASSERT_EQUALS( 1, lexNumCmp( "2385", "2384"));
ASSERT_EQUALS( 1, lexNumCmp( "2385", "02384"));
ASSERT_EQUALS( 1, lexNumCmp( "2385", "002384"));
ASSERT_EQUALS( -1, lexNumCmp( "123.234.4567", "00238"));
ASSERT_EQUALS( 0, lexNumCmp( "123.234", "00123.234"));
ASSERT_EQUALS( 0, lexNumCmp( "a.123.b", "a.00123.b"));
ASSERT_EQUALS( 1, lexNumCmp( "a.123.b", "a.b.00123.b"));
ASSERT_EQUALS( -1, lexNumCmp( "a.00.0", "a.0.1"));
ASSERT_EQUALS( 0, lexNumCmp( "01.003.02", "1.3.2"));
ASSERT_EQUALS( -1, lexNumCmp( "1.3.2", "10.300.20"));
ASSERT_EQUALS( 0, lexNumCmp( "10.300.20", "000000000000010.0000300.000000020"));
ASSERT_EQUALS( 0, lexNumCmp( "0000a", "0a"));
ASSERT_EQUALS( -1, lexNumCmp( "a", "0a"));
ASSERT_EQUALS( -1, lexNumCmp( "000a", "001a"));
ASSERT_EQUALS( 0, lexNumCmp( "010a", "0010a"));
}
};

View File

@ -389,6 +389,35 @@ namespace JsobjTests {
}
};
class ToStringNumber {
public:
void run(){
BSONObjBuilder b;
b.append( "a" , (int)4 );
b.append( "b" , (double)5 );
b.append( "c" , (long long)6 );
b.append( "d" , 123.456789123456789123456789123456789 );
b.append( "e" , 123456789.123456789123456789123456789 );
b.append( "f" , 1234567891234567891234.56789123456789 );
b.append( "g" , -123.456 );
BSONObj x = b.obj();
ASSERT_EQUALS( "4", x["a"].toString( false , true ) );
ASSERT_EQUALS( "5.0", x["b"].toString( false , true ) );
ASSERT_EQUALS( "6", x["c"].toString( false , true ) );
ASSERT_EQUALS( "123.4567891234568" , x["d"].toString( false , true ) );
ASSERT_EQUALS( "123456789.1234568" , x["e"].toString( false , true ) );
// ASSERT_EQUALS( "1.234567891234568e+21" , x["f"].toString( false , true ) ); // windows and *nix are different - TODO, work around for test or not bother?
ASSERT_EQUALS( "-123.456" , x["g"].toString( false , true ) );
}
};
class NullString {
public:
void run() {
@ -1693,6 +1722,7 @@ namespace JsobjTests {
add< BSONObjTests::AppendIntOrLL >();
add< BSONObjTests::AppendNumber >();
add< BSONObjTests::ToStringArray >();
add< BSONObjTests::ToStringNumber >();
add< BSONObjTests::NullString >();
add< BSONObjTests::Validation::BadType >();
add< BSONObjTests::Validation::EooBeforeEnd >();

View File

@ -541,7 +541,7 @@ namespace JSTests {
ASSERT( s->exec( "c = {c:a.a.toString()}", "foo", false, true, false ) );
out = s->getObject( "c" );
stringstream ss;
ss << "NumberLong( \"" << val << "\" )";
ss << "NumberLong(\"" << val << "\")";
ASSERT_EQUALS( ss.str(), out.firstElement().valuestr() );
ASSERT( s->exec( "d = {d:a.a.toNumber()}", "foo", false, true, false ) );

View File

@ -25,6 +25,12 @@
#include "dbtests.h"
namespace mongo {
// here because we don't nesc. want to expose yet
int initialExtentSize(int len);
int followupExtentSize(int len, int lastExtentLen);
}
namespace PdfileTests {
namespace ScanCapped {
@ -301,6 +307,31 @@ namespace PdfileTests {
}
};
} // namespace Insert
class ExtentSizing {
public:
struct SmallFilesControl {
SmallFilesControl(){
old = cmdLine.smallfiles;
cmdLine.smallfiles = false;
}
~SmallFilesControl(){
cmdLine.smallfiles = old;
}
bool old;
};
void run(){
SmallFilesControl c;
// test that no matter what we start with, we always get to max extent size
for ( int obj=16; obj<(4*1024*1024); obj += 111 ){
int sz = initialExtentSize( obj );
for ( int i=0; i<100; i++ ){
sz = followupExtentSize( obj , sz );
}
ASSERT_EQUALS( Extent::maxSize() , sz );
}
}
};
class All : public Suite {
public:
@ -321,6 +352,7 @@ namespace PdfileTests {
add< ScanCapped::FirstInExtent >();
add< ScanCapped::LastInExtent >();
add< Insert::UpdateDate >();
add< ExtentSizing >();
}
} myall;

47
debian/changelog vendored
View File

@ -1,8 +1,55 @@
mongodb (1.6.5) unstable; urgency=low
* full change log http://jira.mongodb.org/browse/SERVER/fixforversion/10207
-- Richard Kreuter <richard@10gen.com> Tue, 7 Dec 2010 16:56:28 -0500
mongodb (1.6.4) unstable; urgency=low
* replica_sets shell helpers
* sharding chunk safety, yielding during migrate cleanup
* full change log http://jira.mongodb.org/browse/SERVER/fixforversion/10191
-- Richard Kreuter <richard@10gen.com> Tue, 26 Oct 2010 16:56:28 -0500
mongodb (1.6.3) unstable; urgency=low
* replica_sets slavedelay, rollback
* sharding optimization for larger than ram data sets
* full change log http://jira.mongodb.org/browse/SERVER/fixforversion/10190
-- Richard Kreuter <richard@10gen.com> Thu, 23 Sep 2010 16:56:28 -0500
mongodb (1.6.2) unstable; urgency=low
* replica_sets some fixes
* sharding some fixes with rs
* full change log http://jira.mongodb.org/browse/SERVER/fixforversion/10187
-- Richard Kreuter <richard@10gen.com> Wed, 1 Sep 2010 16:56:28 -0500
mongodb (1.6.1) unstable; urgency=low
* replica_sets some fixes
* sharding some fixes with rs
* full change log http://jira.mongodb.org/browse/SERVER/fixforversion/10183
-- Richard Kreuter <richard@10gen.com> Tue, 17 Aug 2010 16:56:28 -0500
mongodb (1.6.0) unstable; urgency=low
* sharding stable
* replica_sets stable
-- Richard Kreuter <richard@10gen.com> Thu, 05 Aug 2010 16:56:28 -0500
mongodb (1.5.8) unstable; urgency=low
* sharding lots of changes
* replica_sets lots of changes
-- Richard Kreuter <richard@10gen.com> Tue, 03 Aug 2010 16:56:28 -0500
mongodb (1.5.7) unstable; urgency=low

View File

@ -3,7 +3,7 @@
#---------------------------------------------------------------------------
DOXYFILE_ENCODING = UTF-8
PROJECT_NAME = MongoDB
PROJECT_NUMBER = 1.5.8
PROJECT_NUMBER = 1.6.6-pre-
OUTPUT_DIRECTORY = docs/doxygen
CREATE_SUBDIRS = NO
OUTPUT_LANGUAGE = English

View File

@ -1,5 +1,5 @@
t = db.getCollection( "foo" );
t = db.getCollection( "foo_basic3" );
t.find( { "a.b" : 1 } ).toArray();

View File

@ -1,5 +1,5 @@
t = db.getCollection( "foo" );
t = db.getCollection( "foo_basic9" );
t.save( { "foo$bar" : 5 } );

32
jstests/datasize3.js Normal file
View File

@ -0,0 +1,32 @@
t = db.datasize3;
t.drop()
function run( options ){
var c = { dataSize : "test.datasize3" };
if ( options )
Object.extend( c , options );
return db.runCommand( c );
}
t.insert( { x : 1 } )
a = run()
b = run( { estimate : true } )
assert.eq( a.size , b.size );
t.ensureIndex( { x : 1 } )
for ( i=2; i<100; i++ )
t.insert( { x : i } )
a = run( { min : { x : 20 } , max : { x : 50 } } )
b = run( { min : { x : 20 } , max : { x : 50 } , estimate : true } )
assert.eq( a.size , b.size );

View File

@ -21,4 +21,10 @@ assert( res.databases && res.databases.length > 0 , "listDatabases 1 " + tojson(
x = db._adminCommand( "ismaster" );
assert( x.ismaster , "ismaster failed: " + tojson( x ) )
before = db.runCommand( "serverStatus" )
sleep( 5000 )
after = db.runCommand( "serverStatus" )
assert.lt( 3 , after.uptimeEstimate , "up1" )
assert.gt( after.uptimeEstimate , before.uptimeEstimate , "up2" )
// TODO: add more tests here

View File

@ -1,6 +1,6 @@
a = db.getSisterDB( "test_dbnamea" )
b = db.getSisterDB( "test_dbnameA" )
a = db.getSisterDB( "dbcasetest_dbnamea" )
b = db.getSisterDB( "dbcasetest_dbnameA" )
a.dropDatabase();
b.dropDatabase();

31
jstests/delx.js Normal file
View File

@ -0,0 +1,31 @@
a = db.getSisterDB("delxa" )
b = db.getSisterDB("delxb" )
function setup( mydb ){
mydb.dropDatabase();
for ( i=0; i<100; i++ ){
mydb.foo.insert( { _id : i } );
}
mydb.getLastError();
}
setup( a );
setup( b );
assert.eq( 100 , a.foo.find().itcount() , "A1" )
assert.eq( 100 , b.foo.find().itcount() , "A2" )
x = a.foo.find().sort( { _id : 1 } ).batchSize( 60 )
y = b.foo.find().sort( { _id : 1 } ).batchSize( 60 )
x.next();
y.next();
a.foo.remove( { _id : { $gt : 50 } } );
assert.eq( 51 , a.foo.find().itcount() , "B1" )
assert.eq( 100 , b.foo.find().itcount() , "B2" )
assert.eq( 59 , x.itcount() , "C1" )
assert.eq( 99 , y.itcount() , "C2" ); // this was asserting because ClientCursor byLoc doesn't take db into consideration

View File

@ -14,9 +14,10 @@ if ( !doIt ) {
if ( doIt ) {
port = allocatePorts( 1 )[ 0 ];
m = startMongoProgram( "mongod", "--port", port, "--dbpath", "/data/db/diskfulltest", "--nohttpinterface", "--bind_ip", "127.0.0.1" );
m.getDB( "diskfulltest" ).getCollection( "diskfulltest" ).save( { a: 6 } );
c = m.getDB( "diskfulltest" ).getCollection( "diskfulltest" )
c.save( { a: 6 } );
assert.soon( function() { return rawMongoProgramOutput().match( /file allocation failure/ ); }, "didn't see 'file allocation failure'" );
assert.soon( function() { return rawMongoProgramOutput().match( /Caught Assertion in insert , continuing/ ); }, "didn't see 'Caught Assertion...'" );
assert.isnull( c.findOne() , "shouldn't exist" );
sleep( 3000 );
m2 = new Mongo( m.host );
printjson( m2.getDBs() );

32
jstests/evalc.js Normal file
View File

@ -0,0 +1,32 @@
t = db.jstests_evalc;
t.drop();
for( i = 0; i < 10; ++i ) {
t.save( {i:i} );
}
// SERVER-1610
function op() {
uri = db.runCommand( "whatsmyuri" ).you;
printjson( uri );
p = db.currentOp().inprog;
for ( var i in p ) {
var o = p[ i ];
if ( o.client == uri ) {
print( "found it" );
return o.opid;
}
}
return -1;
}
s = startParallelShell( "print( 'starting forked:' + Date() ); for ( i=0; i<500000; i++ ){ db.currentOp(); } print( 'ending forked:' + Date() ); " )
print( "starting eval: " + Date() )
for ( i=0; i<20000; i++ ){
db.eval( "db.jstests_evalc.count( {i:10} );" );
}
print( "end eval: " + Date() )
s();

View File

@ -36,7 +36,7 @@ for ( i=0; i<searches.length; i++ ){
//printjson( Array.sort( t.find(q).map( function(z){ return z._id; } ) ) )
assert.eq( correct[i].length , t.find( q ).itcount() , "itcount : " + tojson( searches[i] ) );
assert.eq( correct[i].length , t.find( q ).itcount() , "count : " + tojson( searches[i] ) );
assert.eq( correct[i].length , t.find( q ).count() , "count : " + tojson( searches[i] ) );
assert.gt( correct[i].length * 2 , t.find(q).explain().nscanned , "nscanned : " + tojson( searches[i] ) )
}

View File

@ -0,0 +1,27 @@
t = db.geo_qo1;
t.drop()
t.ensureIndex({loc:"2d"})
t.insert({'issue':0})
t.insert({'issue':1})
t.insert({'issue':2})
t.insert({'issue':2, 'loc':[30.12,-118]})
t.insert({'issue':1, 'loc':[30.12,-118]})
t.insert({'issue':0, 'loc':[30.12,-118]})
assert.eq( 6 , t.find().itcount() , "A1" )
assert.eq( 2 , t.find({'issue':0}).itcount() , "A2" )
assert.eq( 1 , t.find({'issue':0,'loc':{$near:[30.12,-118]}}).itcount() , "A3" )
assert.eq( 2 , t.find({'issue':0}).itcount() , "B1" )
assert.eq( 6 , t.find().itcount() , "B2" )
assert.eq( 2 , t.find({'issue':0}).itcount() , "B3" )
assert.eq( 1 , t.find({'issue':0,'loc':{$near:[30.12,-118]}}).itcount() , "B4" )

44
jstests/mr_sort.js Normal file
View File

@ -0,0 +1,44 @@
t = db.mr_sort;
t.drop()
t.ensureIndex( { x : 1 } )
t.insert( { x : 1 } )
t.insert( { x : 10 } )
t.insert( { x : 2 } )
t.insert( { x : 9 } )
t.insert( { x : 3 } )
t.insert( { x : 8 } )
t.insert( { x : 4 } )
t.insert( { x : 7 } )
t.insert( { x : 5 } )
t.insert( { x : 6 } )
m = function(){
emit( "a" , this.x )
}
r = function( k , v ){
return Array.sum( v )
}
res = t.mapReduce( m , r );
x = res.convertToSingleObject();
res.drop();
assert.eq( { "a" : 55 } , x , "A1" )
res = t.mapReduce( m , r , { query : { x : { $lt : 3 } } } )
x = res.convertToSingleObject();
res.drop();
assert.eq( { "a" : 3 } , x , "A2" )
res = t.mapReduce( m , r , { sort : { x : 1 } , limit : 2 } );
x = res.convertToSingleObject();
res.drop();
assert.eq( { "a" : 3 } , x , "A3" )

View File

@ -4,50 +4,50 @@ n = new NumberLong( 4 );
assert.eq.automsg( "4", "n" );
assert.eq.automsg( "4", "n.toNumber()" );
assert.eq.automsg( "8", "n + 4" );
assert.eq.automsg( "'NumberLong( 4 )'", "n.toString()" );
assert.eq.automsg( "'NumberLong( 4 )'", "tojson( n )" );
assert.eq.automsg( "'NumberLong(4)'", "n.toString()" );
assert.eq.automsg( "'NumberLong(4)'", "tojson( n )" );
a = {}
a.a = n;
p = tojson( a );
assert.eq.automsg( "'{ \"a\" : NumberLong( 4 ) }'", "p" );
assert.eq.automsg( "'{ \"a\" : NumberLong(4) }'", "p" );
assert.eq.automsg( "NumberLong( 4 )", "eval( tojson( NumberLong( 4 ) ) )" );
assert.eq.automsg( "NumberLong(4 )", "eval( tojson( NumberLong( 4 ) ) )" );
assert.eq.automsg( "a", "eval( tojson( a ) )" );
n = new NumberLong( -4 );
assert.eq.automsg( "-4", "n" );
assert.eq.automsg( "-4", "n.toNumber()" );
assert.eq.automsg( "0", "n + 4" );
assert.eq.automsg( "'NumberLong( -4 )'", "n.toString()" );
assert.eq.automsg( "'NumberLong( -4 )'", "tojson( n )" );
assert.eq.automsg( "'NumberLong(-4)'", "n.toString()" );
assert.eq.automsg( "'NumberLong(-4)'", "tojson( n )" );
a = {}
a.a = n;
p = tojson( a );
assert.eq.automsg( "'{ \"a\" : NumberLong( -4 ) }'", "p" );
assert.eq.automsg( "'{ \"a\" : NumberLong(-4) }'", "p" );
// too big to fit in double
n = new NumberLong( "11111111111111111" );
assert.eq.automsg( "11111111111111112", "n.toNumber()" );
assert.eq.automsg( "11111111111111116", "n + 4" );
assert.eq.automsg( "'NumberLong( \"11111111111111111\" )'", "n.toString()" );
assert.eq.automsg( "'NumberLong( \"11111111111111111\" )'", "tojson( n )" );
assert.eq.automsg( "'NumberLong(\"11111111111111111\")'", "n.toString()" );
assert.eq.automsg( "'NumberLong(\"11111111111111111\")'", "tojson( n )" );
a = {}
a.a = n;
p = tojson( a );
assert.eq.automsg( "'{ \"a\" : NumberLong( \"11111111111111111\" ) }'", "p" );
assert.eq.automsg( "'{ \"a\" : NumberLong(\"11111111111111111\") }'", "p" );
assert.eq.automsg( "NumberLong( '11111111111111111' )", "eval( tojson( NumberLong( '11111111111111111' ) ) )" );
assert.eq.automsg( "NumberLong('11111111111111111' )", "eval( tojson( NumberLong( '11111111111111111' ) ) )" );
assert.eq.automsg( "a", "eval( tojson( a ) )" );
n = new NumberLong( "-11111111111111111" );
assert.eq.automsg( "-11111111111111112", "n.toNumber()" );
assert.eq.automsg( "-11111111111111108", "n + 4" );
assert.eq.automsg( "'NumberLong( \"-11111111111111111\" )'", "n.toString()" );
assert.eq.automsg( "'NumberLong( \"-11111111111111111\" )'", "tojson( n )" );
assert.eq.automsg( "'NumberLong(\"-11111111111111111\")'", "n.toString()" );
assert.eq.automsg( "'NumberLong(\"-11111111111111111\")'", "tojson( n )" );
a = {}
a.a = n;
p = tojson( a );
assert.eq.automsg( "'{ \"a\" : NumberLong( \"-11111111111111111\" ) }'", "p" );
assert.eq.automsg( "'{ \"a\" : NumberLong(\"-11111111111111111\") }'", "p" );
// parsing
assert.throws.automsg( function() { new NumberLong( "" ); } );

View File

@ -14,3 +14,15 @@ t.find({ $or: [ { a: {$in:[]} } ] } ).toArray();
assert.eq.automsg( "2", "t.find({ $or: [ { a: {$in:[]} }, {a:1}, {a:3} ] } ).toArray().length" );
assert.eq.automsg( "2", "t.find({ $or: [ {a:1}, { a: {$in:[]} }, {a:3} ] } ).toArray().length" );
assert.eq.automsg( "2", "t.find({ $or: [ {a:1}, {a:3}, { a: {$in:[]} } ] } ).toArray().length" );
// nested negate field
t.drop();
t.save( {a:{b:1,c:1}} );
t.ensureIndex( { 'a.b':1 } );
t.ensureIndex( { 'a.c':1 } );
assert.eq( 1, t.find( {$or: [ { 'a.b':1 }, { 'a.c':1 } ] } ).itcount() );
t.remove();
t.save( {a:[{b:1,c:1},{b:2,c:1}]} );
assert.eq( 1, t.find( {$or: [ { 'a.b':2 }, { 'a.c':1 } ] } ).itcount() );

View File

@ -14,5 +14,5 @@ assert.eq( 4 , t.count() , "B" );
t.remove( { _id : 5 } );
assert.eq( 3 , t.count() , "C" );
t.remove( { _id : { $lt : 8 } } , "D" );
t.remove( { _id : { $lt : 8 } } );
assert.eq( 1 , t.count() , "D" );

16
jstests/remove_justone.js Normal file
View File

@ -0,0 +1,16 @@
t = db.remove_justone
t.drop()
t.insert( { x : 1 } )
t.insert( { x : 1 } )
t.insert( { x : 1 } )
t.insert( { x : 1 } )
assert.eq( 4 , t.count() )
t.remove( { x : 1 } , true )
assert.eq( 3 , t.count() )
t.remove( { x : 1 } )
assert.eq( 0 , t.count() )

View File

@ -141,6 +141,14 @@ assert.soon( function(){ return am.lotOfIndexes.getIndexes().length == as.lotOfI
assert.eq( am.lotOfIndexes.getIndexes().length , as.lotOfIndexes.getIndexes().length , "lots of indexes b" )
// multi-update with $inc
am.mu1.update( { _id : 1 , $atomic : 1 } , { $inc : { x : 1 } } , true , true )
x = { _id : 1 , x : 1 }
assert.eq( x , am.mu1.findOne() , "mu1" );
assert.soon( function(){ z = as.mu1.findOne(); printjson( z ); return friendlyEqual( x , z ); } , "mu2" )
rt.stop();

View File

@ -16,9 +16,13 @@ ldb = left.getDB( "test" )
rdb = right.getDB( "test" )
ldb.foo.insert( { _id : 1 , x : "eliot" } )
ldb.runCommand( { getlasterror : 1 , w : 2 } )
var result = ldb.runCommand( { getlasterror : 1 , w : 2 , wtimeout : 20000 } );
printjson(result);
rdb.foo.insert( { _id : 2 , x : "sara" } )
rdb.runCommand( { getlasterror : 1 , w : 2 } )
result = rdb.runCommand( { getlasterror : 1 , w : 2 , wtimeout : 20000 } )
printjson(result);
print( "check 3" )
assert.eq( 2 , ldb.foo.count() , "B1" )
assert.eq( 2 , rdb.foo.count() , "B2" )

View File

@ -12,32 +12,40 @@ ismaster = function( n ) {
// bring up node connections before arbiter connections so that arb can forward to node when expected
connect = function() {
if ( lp == null ) {
print("connecting lp");
lp = startMongoProgram( "mongobridge", "--port", lpPort, "--dest", "localhost:" + lPort );
}
if ( rp == null ) {
print("connecting rp");
rp = startMongoProgram( "mongobridge", "--port", rpPort, "--dest", "localhost:" + rPort );
}
if ( al == null ) {
print("connecting al");
al = startMongoProgram( "mongobridge", "--port", alPort, "--dest", "localhost:" + aPort );
}
if ( ar == null ) {
print("connecting ar");
ar = startMongoProgram( "mongobridge", "--port", arPort, "--dest", "localhost:" + aPort );
}
}
disconnectNode = function( mongo ) {
disconnectNode = function( mongo ) {
if ( lp ) {
print("disconnecting lp: "+lpPort);
stopMongoProgram( lpPort );
lp = null;
}
if ( rp ) {
print("disconnecting rp: "+rpPort);
stopMongoProgram( rpPort );
rp = null;
}
if ( mongo.host.match( new RegExp( "^127.0.0.1:" + lPort + "$" ) ) ) {
print("disconnecting al: "+alPort);
stopMongoProgram( alPort );
al = null;
} else if ( mongo.host.match( new RegExp( "^127.0.0.1:" + rPort + "$" ) ) ) {
print("disconnecting ar: "+arPort);
stopMongoProgram( arPort );
ar = null;
} else {
@ -64,47 +72,47 @@ doTest1 = function() {
pair = new ReplPair( l, r, a );
// normal startup
print("normal startup");
pair.start();
pair.waitForSteadyState();
// disconnect slave
print("disconnect slave");
disconnectNode( pair.slave() );
pair.waitForSteadyState( [ 1, -3 ], pair.master().host );
// disconnect master
print("disconnect master");
disconnectNode( pair.master() );
pair.waitForSteadyState( [ -3, -3 ] );
// reconnect
print("reconnect");
connect();
pair.waitForSteadyState();
// disconnect master
print("disconnect master");
disconnectNode( pair.master() );
pair.waitForSteadyState( [ 1, -3 ], pair.slave().host, true );
// disconnect new master
print("disconnect new master");
disconnectNode( pair.master() );
pair.waitForSteadyState( [ -3, -3 ] );
// reconnect
print("reconnect");
connect();
pair.waitForSteadyState();
// disconnect slave
print("disconnect slave");
disconnectNode( pair.slave() );
pair.waitForSteadyState( [ 1, -3 ], pair.master().host );
// reconnect slave
print("reconnect slave");
connect();
pair.waitForSteadyState( [ 1, 0 ], pair.master().host );
// disconnect master
print("disconnect master");
disconnectNode( pair.master() );
pair.waitForSteadyState( [ 1, -3 ], pair.slave().host, true );
// reconnect old master
print("reconnect old master");
connect();
pair.waitForSteadyState( [ 1, 0 ], pair.master().host );

View File

@ -26,13 +26,15 @@ doTest = function( signal ) {
am.save( {i:2} );
assert.eq( 2, am.count() );
sleep( 3000 );
rt.stop( true, signal );
sleep( 3000 );
assert.eq( 1, s.getDB( baseName ).a.count() );
soonCount( 2 );
rt.stop();
}
doTest( 15 ); // SIGTERM
doTest( 9 ); // SIGKILL
print("repl10.js dotest(15)");
doTest(15); // SIGTERM
print("repl10.js dotest(15)");
doTest(9); // SIGKILL
print("repl10.js SUCCESS");

47
jstests/repl/repl12.js Normal file
View File

@ -0,0 +1,47 @@
// SERVER-1626
// check for initial sync of multiple db's
function debug( x ) {
print( "DEBUG:" + tojson( x ) );
}
rt = new ReplTest( "repl12tests" );
m = rt.start( true );
usedDBs = []
a = "a"
for( i = 0; i < 3; ++i ) {
usedDBs.push( a )
m.getDB( a ).c.save( {} );
a += "a";
}
m.getDB(a).getLastError();
//print("\n\n\n DB NAMES MASTER:");
//printjson(m.getDBNames());
var z = 10500;
print("sleeping " + z + "ms");
sleep(z);
s = rt.start(false);
function countHave(){
var have = 0;
for ( var i=0; i<usedDBs.length; i++ ){
if ( s.getDB( usedDBs[i] ).c.findOne() )
have++;
}
return have;
}
assert.soon(
function() {
var c = countHave();
debug( "count: " + c );
return c == 3; }
);
//printjson(s.getDBNames());

View File

@ -44,15 +44,8 @@ doTest = function( signal ) {
checkWrite( rp.master(), rp.slave() );
// allow slave to finish initial sync
assert.soon(
function() {
var res = rp.slave().getDB( "admin" ).runCommand( {replacepeer:1} );
if ( res.ok == 1 )
return true;
printjson( res );
return false;
}
);
var res = rp.slave().getDB( "admin" ).runCommand( {replacepeer:1} );
assert( res.ok , "replacepeer didn't finish: " + tojson( res ) );
// Should not be saved to slave.
writeOne( rp.master() );

View File

@ -1,4 +1,6 @@
// Test SERVER-623 - starting repl peer from a new snapshot of master
// Test SERVER-623 - starting repl peer from a new snapshot of master
print("snapshot2.js 1 -----------------------------------------------------------");
ports = allocatePorts( 3 );
@ -7,21 +9,37 @@ var basePath = "/data/db/" + baseName;
a = new MongodRunner( ports[ 0 ], basePath + "-arbiter" );
l = new MongodRunner( ports[ 1 ], basePath + "-left", "127.0.0.1:" + ports[ 2 ], "127.0.0.1:" + ports[ 0 ] );
r = new MongodRunner( ports[ 2 ], basePath + "-right", "127.0.0.1:" + ports[ 1 ], "127.0.0.1:" + ports[ 0 ] );
r = new MongodRunner( ports[ 2 ], basePath + "-right", "127.0.0.1:" + ports[ 1 ], "127.0.0.1:" + ports[ 0 ] );
print("snapshot2.js 2 -----------------------------------------------------------");
rp = new ReplPair( l, r, a );
rp.start();
rp.waitForSteadyState();
rp = new ReplPair(l, r, a);
rp.start();
print("snapshot2.js 3 -----------------------------------------------------------");
rp.waitForSteadyState();
print("snapshot2.js 4 -----------------------------------------------------------");
big = new Array( 2000 ).toString(); // overflow oplog, so test can't pass supriously
rp.slave().setSlaveOk();
for( i = 0; i < 500; ++i ) {
rp.master().getDB( baseName )[ baseName ].save( { _id: new ObjectId(), i: i, b: big } );
if ( i % 250 == 249 ) {
assert.soon( function() { return i+1 == rp.slave().getDB( baseName )[ baseName ].count(); } );
rp.slave().setSlaveOk();
print("snapshot2.js 5 -----------------------------------------------------------");
for (i = 0; i < 500; ++i) {
rp.master().getDB( baseName )[ baseName ].save( { _id: new ObjectId(), i: i, b: big } );
if (i % 250 == 249) {
function p() { return i + 1 == rp.slave().getDB(baseName)[baseName].count(); }
try {
assert.soon(p);
} catch (e) {
print("\n\n\nsnapshot2.js\ni+1:" + (i + 1));
print("slave count:" + rp.slave().getDB(baseName)[baseName].count());
sleep(2000);
print(p());
throw (e);
}
sleep( 10 ); // give master a chance to grab a sync point - have such small oplogs the master log might overflow otherwise
}
}
}
print("snapshot2.js 6 -----------------------------------------------------------");
rp.master().getDB( "admin" ).runCommand( {fsync:1,lock:1} );
leftMaster = ( rp.master().host == rp.left().host );
@ -47,5 +65,8 @@ assert.eq( 500, rp.slave().getDB( baseName )[ baseName ].count() );
rp.master().getDB( baseName )[ baseName ].save( {i:500} );
assert.soon( function() { return 501 == rp.slave().getDB( baseName )[ baseName ].count(); } );
assert( !rawMongoProgramOutput().match( /resync/ ) );
assert( !rawMongoProgramOutput().match( /SyncException/ ) );
assert( !rawMongoProgramOutput().match( /resync/ ) );
assert(!rawMongoProgramOutput().match(/SyncException/));
print("snapshot2.js SUCCESS ----------------");

Some files were not shown because too many files have changed in this diff Show More