Compare commits

...

371 Commits
master ... v2.0

Author SHA1 Message Date
Greg Studer
c28079649e SERVER-10458 sanity check before critical section that all cloned docs sent 2013-08-12 10:35:02 -04:00
Greg Studer
e5a7faaecd SERVER-10478 fix batch limit check for _cloneLocs in migration 2013-08-12 10:34:56 -04:00
Ernie Hershey
ec60d7de77 post 2.0.9 2013-04-02 17:14:20 -04:00
Dan Pasette
7e34cb36a6 BUMP 2.0.9 2013-03-29 18:14:19 -04:00
Eric Milkie
cae3ea8b1d post 2.0.9-rc1 2013-03-27 11:04:52 -04:00
Eric Milkie
446b5ded23 BUMP 2.0.9-rc1 2013-03-26 22:23:19 -04:00
Ben Becker
bb999bb503 SERVER-9124: cast id to double before converting to JS 2013-03-26 18:33:20 -07:00
Dan Pasette
b7b6c38446 BUMP 2.9.0-rc0 2013-03-26 17:04:44 -04:00
Dan Pasette
3c5c12f7d5 SERVER-9124: Avoid raw pointers for SM's nativeHelper 2013-03-26 16:52:39 -04:00
Dan Pasette
bc7400d46a post 2.0.8 2012-11-16 12:01:10 -05:00
Dan Pasette
a340a57af7 BUMP 2.0.8 2012-11-15 19:55:43 -05:00
Eric Milkie
1d3d3ba938 post 2.0.8-rc0 2012-10-26 16:32:55 -04:00
Dan Pasette
744074d2cf BUMP 2.0.8-rc0 2012-10-25 18:46:58 -04:00
Eric Milkie
365e89e5ec fix for Solaris s3dist 2012-10-25 16:09:40 -04:00
Tad Marshall
6d021c86d3 Compile when SIGPIPE is not defined
Conflicts:
	s/server.cpp

Signed-off-by: Eric Milkie <milkie@10gen.com>
2012-10-16 09:37:19 -04:00
Dan Pasette
7577f95c80 SERVER-6397 fix backport by stopping balancer without helper 2012-10-16 02:08:04 -04:00
Spencer T Brody
3d8d35771f Ignore SIGPIPE on mongos. SERVER-6509 SERVER-6513
Was already ignoring on mongod, this just duplicated that behavior for mongos.

Conflicts:

	s/server.cpp
2012-10-15 17:18:41 -04:00
Dan Pasette
239d7d6a19 SERVER-6647 Potential out of bounds access in ReplicaSetMonitor
Backport of commit f86f60afe1
2012-10-15 17:17:09 -04:00
Spencer T Brody
5eaf375b0c Make C++ driver call GLE after storing gridFS chunks, before calling filemd5. SERVER-6742
This ensures that there are no pending writebacks from the chunks being inserted.
2012-10-15 17:17:09 -04:00
Dan Pasette
0786517099 SERVER-6709: Don't call ->done() on a null ptr
Backport of git commit: bf724ef210
2012-10-15 17:17:09 -04:00
Dan Crosta
01477c20c8 SERVER-4995: check for and link with librt on Solaris 2012-10-15 16:16:25 -04:00
gregs
86b6b474a8 SERVER-6397 buildbot sync2.js turn off balancer before doing manual chunk moves 2012-10-15 16:15:39 -04:00
Eliot Horowitz
4d37e1acba fix for SERVER-6463 slightly better 2012-10-13 09:08:17 -04:00
Eliot Horowitz
8ea06cd353 backport of 8e42151ecc for SERVER-6463 2012-10-12 10:22:19 -04:00
Aaron
72cc3481b9 SERVER-6878 Clean distinct3.js and make evalb.js more robust.
Conflicts:

	jstests/evalb.js
2012-09-12 15:58:51 -04:00
Dan Pasette
daf7aec921 post 2.0.7 2012-08-08 18:40:16 -04:00
Dan Pasette
875033920e BUMP 2.0.7 2012-08-07 07:31:19 -04:00
Eric Milkie
d54dc5e869 forgot the trailing hyphen; should fix buildbot. 2012-08-05 14:37:19 -04:00
Dan Pasette
24f90398dc post 2.0.7-rc1 2012-08-02 11:30:02 -04:00
Dan Pasette
9efe4cce27 BUMP 2.0.7-rc1 2012-07-29 23:13:40 -04:00
Eliot Horowitz
de0cfcd8de SERVER-6391 - don't sleep if we're a reader,
and call ElapsedTracker::resetLastTime when we're done sleeping

Conflicts:

	db/clientcursor.cpp
2012-07-27 16:31:12 -04:00
Eliot Horowitz
8e42151ecc SERVER-6391 - lower sleep times when yielding 2012-07-27 16:28:58 -04:00
Eliot Horowitz
6701b6ea85 SERVER-6391 add resetLastTime to ElapsedTracker 2012-07-27 16:28:48 -04:00
Eric Milkie
6aa80782bc SERVER-6509 ignore SIGPIPE rather than printing a message
Solaris was crashing because we were using signal() instead of sigaction()
to install the dummy signal handler for SIGPIPE.  SIGPIPE is supressed
via the socket library on other operating systems but this is not an option
on Solaris.

Conflicts:
	db/db.cpp
2012-07-27 11:33:21 -04:00
Eric Milkie
c88805a6f6 SERVER-5680 fix Windows accvios due to incorrect recursive locking of MongoFiles
Conflicts:
	db/dur.cpp
2012-07-27 10:26:05 -04:00
Eric Milkie
7542d7baa9 SERVER-6512 ReplicaSetMonitor::_checkConnection does not check upper bounds for the indexes
Make sure to invalidate the cached _master index whenever the _nodes structure is modified.
This is a short term fix - the long term is to not use indexes at all.
2012-07-27 10:13:08 -04:00
Eric Milkie
90fa91c352 forgot the trailing hyphen 2012-07-16 08:51:36 -04:00
Eric Milkie
1ba3671b1c post 2.0.7-rc0 2012-07-15 08:43:34 -04:00
Eric Milkie
a56780496b BUMP 2.0.7-rc0 2012-07-13 22:19:28 -04:00
Eliot Horowitz
accb562a78 SERVER-6414 - fixed posix_fadvise call 2012-07-12 13:38:53 -04:00
Eric Milkie
61d3a31ca4 fix test failure on Windows: open temp file in binary mode 2012-07-12 11:58:06 -04:00
Eric Milkie
75fe13d0b1 fix Windows compile and link, for real 2012-07-12 09:59:07 -04:00
Eliot Horowitz
dc6d43de35 windows include 2012-07-11 19:37:47 -04:00
Eliot Horowitz
8e584c2fe8 SERVER-6414 - windows compile part 5 2012-07-11 19:16:04 -04:00
Eliot Horowitz
e67589e105 SERVER-6414 - windows compile part 4 2012-07-11 19:09:10 -04:00
Eliot Horowitz
c6a40c4423 SERVER-6414 - windows compile part 3 2012-07-11 18:31:38 -04:00
Eliot Horowitz
ea06d5d59a SERVER-6414 - windows compile part 2 2012-07-11 18:25:12 -04:00
Eliot Horowitz
87c31eb85c SERVER-6414 - windows compile 2012-07-11 18:23:36 -04:00
Eric Milkie
a31879b251 Windows does not have ssize_t 2012-07-11 16:33:04 -04:00
Eliot Horowitz
6b24994f08 SERVER-6414 - use regular file io, not mmap for external sort
Conflicts:

	db/extsort.cpp
	db/extsort.h
2012-07-11 15:29:39 -04:00
Eric Milkie
560db9021b SERVER-6311 do not crash if FlushFileBuffers fails
Unclear what it means if it fails. It should not matter with
regard to data integrity; the critical call is FlushViewOfFile.
2012-07-11 14:01:16 -04:00
Eric Milkie
afd5eb4e2c SERVER-6372 fassert does not exist in 2.0 2012-07-10 09:38:50 -04:00
Greg Studer
b0e8e2bfa9 SERVER-5920 buildbot bad_config_load.js also check for socket exceptions in test
Signed-off-by: Eric Milkie <milkie@10gen.com>
2012-07-09 16:57:50 -04:00
Eric Milkie
7d3a8463b4 SERVER-6311 abort if FlushViewOfFile takes longer than 15 minutes
This avoids data corruption on Windows; the previous behavior gave up
after 60 seconds and then blindly continued.

Signed-off-by: Eric Milkie <milkie@10gen.com>
2012-07-09 16:31:45 -04:00
Randolph Tan
97d9c1b815 SERVER-5594 memory corruption in sharding/auth1.js V8 builder
Signed-off-by: Eric Milkie <milkie@10gen.com>
2012-07-09 15:52:32 -04:00
Josh Price
6de83ddbe9 SERVER-6359 mongoexport now outputs full strings in CSV mode
See discussion here: https://groups.google.com/forum/?fromgroups#!topic/mongodb-user/ngu9U1lKMfk

Signed-off-by: Eric Milkie <milkie@10gen.com>
2012-07-09 15:25:51 -04:00
Greg Studer
f198c21e4b SERVER-6305 command-line option to turn off auto-splitting on particular mongoses 2012-07-06 11:47:58 -04:00
Eric Milkie
2ff57e149c fix Windows compile 2012-07-05 10:08:19 -04:00
Aaron
b72aa7471c SERVER-4907 Backport query plan hinting when oplog entries are applied. 2012-07-04 16:39:39 -07:00
Siddharth Singh
e25d6a4165 SERVER-4992 Disable dropDatabase command on config
i) Diallow completely via mongos
ii) And partially if mongod started with --configsvr

Signed-off-by: Eric Milkie <milkie@10gen.com>
2012-07-03 13:56:21 -04:00
Matt Dannenberg
b39f7ff6b9 SERVER-5473 mongostat will not auth unless passed a username or password
Signed-off-by: Spencer T Brody <spencer@10gen.com>
Signed-off-by: Eric Milkie <milkie@10gen.com>
2012-07-03 13:54:33 -04:00
Eric Milkie
16fdca3498 SERVER-5872 use ScopedDBConnection when we talk to other shards during autosplit 2012-07-03 11:42:18 -04:00
Greg Studer
17c3a2c3a7 SERVER-5920 protect reload of database config, ensure we don't get partial dbconfig objs 2012-07-03 09:57:01 -04:00
Richard Kreuter
bf25d51add Don't grow a document on $pull/$pullAll. SERVER-6047 2012-07-02 16:40:10 -04:00
Greg Studer
ae56ae532c SERVER-6167 reduce logging verbosity on stale versioned writes and getting distlocks 2012-07-02 14:51:30 -04:00
Greg Studer
9dc4c3fb5b SERVER-6178 catch dbexceptions not socket exceptions during startup consistency check
Backport of commit 29253bec3b .

Signed-off-by: Tad Marshall <tad@10gen.com>
2012-06-28 18:24:43 -04:00
Tad Marshall
80f143dc95 SERVER-6006 import code and fixes from 2.1.x into test
The addition of a call to s.stopBalancer() failed because that
function didn't exist in 2.0.  Bring in all the code that is
needed to make it work in 2.0.  Also pick up assert changes from
2.1 that make the test more reliable.
2012-06-28 14:16:04 -04:00
Greg Studer
73370d7bc4 SERVER-6006 buildbot sharding_rs2.js turn off balancer in test before split/migrate
Signed-off-by: Tad Marshall <tad@10gen.com>
2012-06-27 16:39:09 -04:00
Greg Studer
12de29a401 SERVER-4800 make unsorted parallel cursors do round-robin when pulling data, minimize timeouts
Signed-off-by: Tad Marshall <tad@10gen.com>
2012-06-27 15:36:51 -04:00
Tad Marshall
dd36d37c09 SERVER-6162 adapt sharding/no_empty_reset.js for v2.0
The test jstests/sharding/no_empty_reset.js was using some
functionality that wasn't present in the 2.0 shell.  Add code
to find the shard name manually to adapt for this.
2012-06-27 13:56:28 -04:00
Tad Marshall
75fa25bc1d Visual Studio -- .gitignore, make mongo shell buildable
Add */*/ipch to .gitignore so shell/msvc/ipch (Intellisense
precompiled header) files don't show up on "git status" list.
Fix incorrect file locations and settings in Visual Studio
project files for mongo shell.
2012-06-27 09:54:12 -04:00
Tad Marshall
7012a03237 Revert "Always go through relinquish when stepping down SERVER-5258"
This reverts commit 4ecae7484e.

Caused failures in jstests/replsets/remove1.js .
2012-06-26 19:55:35 -04:00
gregs
6c19d602f1 SERVER-6162 backport of targeted shard ranges instead of broadcast on all queries
test and fix for zero-version being sent to unneeded shards during scatter/gather

Backport based on f93918db8e

Signed-off-by: Tad Marshall <tad@10gen.com>
2012-06-25 14:13:59 -04:00
Kristina
4ecae7484e Always go through relinquish when stepping down SERVER-5258
Signed-off-by: Tad Marshall <tad@10gen.com>
2012-06-25 13:14:52 -04:00
Brandon Diamond
4bb6e76b20 SERVER-4291: Return code of recv unchecked
Signed-off-by: Tad Marshall <tad@10gen.com>
2012-06-22 12:09:41 -04:00
Tad Marshall
f45435a022 SERVER-3969 handle spaces in passwords at the "Enter password:" prompt
Use "getline( cin, password );" instead of "cin >> password;" to read
passwords that may contain spaces.
2012-06-22 11:13:08 -04:00
Tad Marshall
034b064a04 SERVER-3097 -- "mongod --install" uses wrong image path depending on CWD
Use GetModuleFileName() to get path of running exe.
2012-06-22 10:35:38 -04:00
Tad Marshall
881d6229e1 SERVER-5663, SERVER-2942 MapViewOfFileEx backport
Backport the fixes for Windows memory-mapped files made in
2.1.x into the 2.0.x branch.  Stop using VirtualProtect in
remapPrivateView, use UnmapViewOfFile and MapViewOfFileEx
to refresh the private view of the memory-mapped file.
Place memory-mapped files at a high address in 64-bit to
get out of the way of allocations made by Windows.
2012-06-20 17:47:51 -04:00
Tad Marshall
4ada6dfbc2 Visual Studio -- update shell/mongo_vstudio.cpp 2012-06-20 17:33:27 -04:00
Tad Marshall
f9828af52c SERVER-6132 makeChunkWritable abort on failure (Windows) 2012-06-20 13:57:59 -04:00
Eric Milkie
e3120a3fbd fix smalloplog; cleanup extra collection 2012-06-19 10:21:14 -04:00
Tad Marshall
e1504ed07f SERVER-2833 -- shut down cleanly on OS or Service Controller shutdown event
Added code to log shutdown events from the Windows Service Controller
and to respond correctly to those events.  Shutdown from the console
on logoff or shutdown callbacks (stop ignoring them).
2012-06-10 16:12:08 -04:00
Tad Marshall
ef11f578a4 Visual Studio -- .gitignore ipch, make mongos buildable
Add ipch directory to .gitignore list, add db/security_commands.cpp
to dbgrid.vcxproj for mongos, remove dead files, cleanup filters slightly.
2012-06-10 07:24:45 -04:00
Eric Milkie
9ffb237472 post 2.0.6 2012-06-04 23:31:19 -04:00
Eric Milkie
e1c0cbc258 BUMP 2.0.6 2012-06-04 09:42:54 -04:00
Andy Schwerin
eba41d3136 post 2.0.6-rc0 2012-05-23 09:49:47 -04:00
Eric Milkie
ec370983a5 BUMP 2.0.6-rc0 2012-05-22 13:09:43 -04:00
Eric Milkie
095dc59270 fassert not available in 2.0 yet 2012-05-18 22:12:08 -04:00
Eric Milkie
6b08691668 SERVER-5040 retry initial sync if errors occur when creating indexes
If you clone a database and a document, due to an update, moves forward in memory, cloner might clone both the old and new document.
When this happens, creating a unique index might fail. This change restarts the clone when this happens, and will abort after 3 failed cloning attempts.
2012-05-18 16:48:34 -04:00
Eric Milkie
c3d0639c9a SERVER-4609 ensure correct buffer sizes for string representations of numbers 2012-05-17 20:30:52 -04:00
Eric Milkie
1d84085365 fix js-1.7 for freebsd
fixes this compilation problem:
src/third_party/js-1.7/jsprf.c: In function 'BuildArgArray':
src/third_party/js-1.7/jsprf.c:644: error: incompatible types in assignment
2012-05-16 09:15:26 -04:00
Eric Milkie
dfbf91e16a backport - fix handling of socket timeouts on Windows SERVER-4758 2012-05-16 08:54:32 -04:00
Eric Milkie
dbd87d09fd SERVER-4758 raising timeout to 10 minutes for safety 2012-05-15 13:32:46 -04:00
Eric Milkie
ee64e77c32 SERVER-5581 (backport only)
Only attempt to clear a query's pattern if the query is satisfiable for the specified index type.
2012-05-15 13:29:10 -04:00
Eric Milkie
03c34bd5fa SERVER-5353 Backport print capped collection scan on _id query warning message in appropriate cases. 2012-05-13 16:48:04 -04:00
Randolph Tan
db9d17af5c SERVER-5746 Wrong initialization for ReplicaSetMonitor Nodes
Modified the initialization of the ok member variable of ReplicaSetMonitor::Node to true if conn smart pointer is not null.

Conflicts:

	jstests/sharding/slaveok_routing.js
2012-05-10 14:49:37 -04:00
Greg Studer
0397af7906 SERVER-5405 make sure we recycle authenticated conn when done
Conflicts:

	client/dbclient_rs.cpp
2012-05-10 14:49:37 -04:00
Randolph Tan
2cf91c83a1 SERVER-5405 mongos does not send reads to secondaries
Authenticate connection to replica members with keyFile credentials when calling
replSetGetStatus internally.

Conflicts:

	client/dbclient_rs.cpp
2012-05-10 14:49:37 -04:00
Eric Milkie
1aaac5eb0d SERVER-5706 if only slaveDelay'd nodes are available, use them
SERVER-4750 prevent syncing to secondaries with a slavedelay greater than yourself

Conflicts:

	db/repl/rs_initialsync.cpp
	jstests/replsets/slavedelay3.js
2012-05-10 11:56:44 -04:00
Greg Studer
dd21525b02 SERVER-4603 handle last shard migration more correctly
Signed-off-by: Eric Milkie <milkie@10gen.com>
2012-05-09 16:53:00 -04:00
Tony Hannan
77db8a50cf SERVER-2917: REST interface now authenticate user to db when user successfully authenticates to web server
Signed-off-by: Eric Milkie <milkie@10gen.com>
2012-05-09 16:50:41 -04:00
Eric Milkie
c94a29477a SERVER-3791 compact now restarts the extent sizing algorithm
The 'compact' operation sequentially copies all the records in the namespace into a new extent. Since this operation creates no new data,
the standard extent logarithmic sizing should not apply; the algorithm is only to accomodate data growth.
Instead, we will start back at the beginning with the smallest extent size.  This will allow for freed-extent reuse over multiple compacts.
Note that the only way to have freed extents in a database is to run compact, so the first time you run it, there will always be new extents created.
Subsequent compacts will potentially reuse the freed extents.
2012-05-09 16:49:44 -04:00
Dan Crosta
4fc6bb1e17 SERVER-5791: SCons shouldn't die if HOME env var is not set 2012-05-09 14:43:16 -04:00
Eliot Horowitz
40049a3869 backport of SERVER-5303 yield when fetching a document for migrate 2012-05-09 13:56:07 -04:00
Andy Schwerin
8f38fc36d1 post 2.0.5 2012-05-09 13:45:42 -04:00
Andy Schwerin
1bb4de4630 BUMP 2.0.5 2012-05-08 10:51:28 -04:00
Andy Schwerin
935e22aaed post 2.0.5-rc1 2012-05-03 15:13:15 -04:00
Andy Schwerin
52db24582f BUMP 2.0.5-rc1 2012-05-03 10:05:46 -04:00
Andy Schwerin
dc2f8cd3df SERVER-5754: Fix erroneous assertion in db/pdfile.cpp. 2012-05-03 09:56:24 -04:00
Eliot Horowitz
98c748b295 post 2.0.5-rc0 2012-04-26 04:03:28 -04:00
Andy Schwerin
1c22afa5d0 BUMP 2.0.5-rc0 2012-04-25 10:52:34 -04:00
Eliot Horowitz
947fa6924c drop collection at end of capped6 since captrunc doesn't replicate properly 2012-04-24 21:51:17 -04:00
Eliot Horowitz
97ab12742a emptycapped can be replicated 2012-04-24 19:19:37 -04:00
Eliot Horowitz
09db1bc1be captrunc doesn't replicate, so drop collections at end of test 2012-04-24 16:03:58 -04:00
Eliot Horowitz
f53de1128d jstests shouldn't drop the "test" db 2012-04-24 10:17:40 -04:00
Eliot Horowitz
d861e27e78 backport of SERVER-5357 2012-04-23 23:49:37 -04:00
Greg Studer
6fb6a11f58 buildbot and SERVER-4526 mongos_no_detect_sharding.js split logic may change, explicitly check for shard versioning turned on 2012-04-21 14:57:30 -04:00
Greg Studer
36ae878645 SERVER-4680 sendNextBatch logic isn't correct with nonzero batch size (corrected backport) 2012-04-20 12:30:13 -04:00
Greg Studer
e51ea6f089 Revert "SERVER-4680 sendNextBatch logic isn't correct with nonzero batch size"
This reverts commit e50b2e2428.
2012-04-20 12:28:38 -04:00
Greg Studer
e50b2e2428 SERVER-4680 sendNextBatch logic isn't correct with nonzero batch size 2012-04-20 12:21:31 -04:00
Aaron
6477fd1d75 SERVER-4777 avoid 'weird case' assertion on modifier update with duplicate field names by applying updates to the first duplicate field provided by BSONObjIteratorSorted and passing through the remaining duplicates 2012-04-20 11:24:29 -04:00
Kristina
672793ce4f Better log message SERVER-4810 2012-04-20 10:53:42 -04:00
Kristina
49144209b1 Check optimes before stepping down due to priority SERVER-4810 2012-04-20 10:53:33 -04:00
Eliot Horowitz
bea6d4be20 fix test conflict 2012-04-20 10:16:54 -04:00
Ben Becker
6245495cab SERVER-5645: release lock between upserts when applying bulk xfers 2012-04-19 17:54:47 -04:00
Mathias Stearn
264b914c4b Don't check /proc/pid/exe in --shutdown SERVER-5358
It didn't mix well with updates. When the mongod binary is updated the
exe link gets " (deleted)" added to the path.
2012-04-19 17:33:04 -04:00
Eric Milkie
1911459b0d SERVER-5093 fix logic error to avoid memory corruption. 2012-04-19 17:28:36 -04:00
Greg Studer
5f49613090 SERVER-4812 use say() not sayPiggyback() when closing cursors and lazyKill is false (i.e. in mongos) 2012-04-19 15:44:57 -04:00
Andy Schwerin
e1b56eb28a Fix forgotten verify->assert conversion for 2.0.5 backport. 2012-04-19 15:40:12 -04:00
Eliot Horowitz
9bb928d020 make Extent::minSize() match allocation strategy and alloc from free list obey it 2012-04-19 15:38:15 -04:00
Mathias Stearn
d99695ccc2 Ignore --fork and --logpath when using --shutdown SERVER-5186 SERVER-5187 2012-04-19 15:37:30 -04:00
Greg Studer
df84cb3159 SERVER-4388 update version of newly sharded collection on mongod primary after first sharding 2012-04-19 15:31:56 -04:00
Mathias Stearn
87374c2c5c Don't destroy CommitJob. Causing stackdump after shutdown 2012-04-19 15:29:27 -04:00
Eric Milkie
735e498aa6 SERVER-5384 removing broken test; MongoRunner does not exist in 2.0 2012-04-19 08:45:53 -04:00
Randolph Tan
b39c6a7e18 SERVER-5384 segfault attempting mapreduce with --noscripting 2012-04-18 18:15:04 -04:00
gregs
05b07daf5b SERVER-5406 allow slaveok auth on shard with normal timeout 2012-04-18 18:03:15 -04:00
Eric Milkie
41be3168d4 SERVER-5348 backport C++ driver macro redefinition isolation 2012-04-18 17:53:57 -04:00
gregs
ba8d0f572c SERVER-2988 catch exceptions loading chunksize
Conflicts:

	s/config.cpp
2012-04-18 17:24:51 -04:00
Greg Studer
e69445666b SERVER-2988 give error message when initial version can't be written on mongos startup 2012-04-18 17:21:08 -04:00
Tad Marshall
83fa0f7bc1 SERVER-1163 Retry calls to FlushViewOfFile on error 33
FlushViewOfFile() will return error code 33 (ERROR_LOCK_VIOLATION)
in some cases, but this is a "transient" error, and just retrying
repeatedly will (supposedly) always work.  This changes the code
to retry up to one million times and for up to 60 seconds if it
continues to get ERROR_LOCK_VIOLATION.
2012-04-18 16:25:29 -04:00
renctan
7460b30455 undo SERVER-5110 chnages on log display logic 2012-04-17 16:31:23 -04:00
Randolph Tan
aee93cd91a SERVER-5110 ReplicaSetMonitor::check not thread safe wrt _master
Made chages to make sure that proper mutexes are held when modifying _master and _nodes.
Also made sure that index variables pointing to _nodes element still refers to what
it used to be after we re-acquire the mutex.
2012-04-17 16:30:06 -04:00
Kristina
b32511d875 Extend writelock during stepdown to include socket close SERVER-4619 2012-04-17 14:35:17 -04:00
Eric Milkie
30f515ac16 SERVER-5220 removing unreliable '64bit-only' check 2012-04-17 14:32:50 -04:00
Mathias Stearn
660f41ad65 Make test less sensitive to differences between time() and gettimeofday()
SERVER-5569
2012-04-17 14:29:57 -04:00
Randolph Tan
d87357cf26 SERVER-5541 crash in C++ client driver during shutdowing primary mongo server from repset 2012-04-17 14:25:36 -04:00
Daniel Pasette
a55507d21e SERVER-3875: Added auth() call to mongotop and fixed output formatting. 2012-04-17 14:18:40 -04:00
Andy Schwerin
23a1c8019a SERVER-5449: It's not an error for the write() syscall to return a non-negative value less than len.
Instead of treating it as an error for write() to return a non-negative value less than len,
keep writing in a loop until the entire buffer has been written to the log file.
2012-04-17 14:15:15 -04:00
Andy Schwerin
829e3beaa0 Backport support for building when the TERM environment variable isn't set. 2012-04-17 13:23:12 -04:00
Eliot Horowitz
dbf67c31dc assert that we have a cursor rather than segv SERVER-5541 2012-04-08 09:51:00 -04:00
Eliot Horowitz
654b5284e4 DBClientConnection::call needs to call checkConnection to reconnect if the previous socket was failed SERVER-4385 2012-04-07 09:39:35 -04:00
Kristina
6a6b4613fc Fix flaky tests and add more debugging 2012-03-26 15:31:28 -04:00
Dan Crosta
64f3b376ca python-2.4 compatible version of cleanbb.py 2012-03-26 11:40:46 -04:00
Andy Schwerin
bb76d2d736 SERVER-5140: Short-circuit smoke_python_name() if the running python interpreter is new enough.
There's no reason to search for another version of the python interpreter if the running version
is at least the minimum supported version, and this stops a build hang.
2012-03-20 15:09:05 -04:00
Eliot Horowitz
5893841d96 post 2.0.4 2012-03-19 23:54:04 -04:00
Eliot Horowitz
329f3c47fe BUMP 2.0.4 2012-03-19 12:10:40 -04:00
Eliot Horowitz
9ede2213f3 post 2.0.4-rc1 2012-03-12 15:49:07 -04:00
Eliot Horowitz
240177f3cb BUMP 2.0.4-rc1 2012-03-12 01:07:40 -04:00
Greg Studer
22ffe27906 need to have waitable ticket holder, actually wait for ticket for config server 2012-03-08 11:41:58 -05:00
Eliot Horowitz
cc61e1f8fc post 2.0.4-rc0 2012-03-08 01:04:35 -05:00
Eliot Horowitz
67c9ac45c3 BUMP 2.0.4-rc0 2012-03-06 13:08:38 -05:00
Greg Studer
d216bc37c3 SERVER-5069 replace ScopedDBConnection message with something more meaningful 2012-03-06 13:00:58 -05:00
Greg Studer
8983591f83 SERVER-5142 use ticket holder instead of mutex to allow 3 parallel refreshes, with 30s timeout 2012-03-06 12:57:59 -05:00
Greg Studer
edc6a48921 SERVER-5142 double-check in lock for new version before recreating ShardChunkManager 2012-03-06 12:57:34 -05:00
Eliot Horowitz
446f597cf4 Dont add addUser lines to shell history SERVER-3768
Conflicts:

	shell/dbshell.cpp
2012-03-04 20:13:20 -05:00
Eric Milkie
abb6284056 SERVER-5081 do not delete iterator until after it's incremented
Avoids memory reads of freed memory.
2012-03-04 20:09:23 -05:00
Mathias Stearn
d13fb74970 Fix journal compression ratio reporting SERVER-5135 2012-03-04 20:08:46 -05:00
gregs
b626e959a3 use curr collection not coll var when printing shard chunks 2012-03-04 20:07:40 -05:00
Brandon Diamond
5899a6daa5 SERVER-4729: log slow queries + improved test 2012-03-04 19:52:10 -05:00
Eliot Horowitz
816af2185c backport of SERVER-4612 - fix chhunk boundary checking on idhack queries 2012-03-02 16:03:09 -05:00
Eliot Horowitz
32cc883b29 SERVER-5177 - fetching of docs in initial sync can assert 2012-03-02 13:43:23 -05:00
Dan Crosta
c546330522 SERVER-5140: avoid a bug in SCons with subprocess.Popen
SCons overrides the subprocess module with its own custom implementation
(forked from an earlier version of Python, but with some patches).
SCons' implementation acquires a lock but does not release it during
Popen() if the command being executed cannot be found. The next
invocation of Popen() will hang indefinitely attempting to acquire the
lock.

Moving smoke_python_name() to a python module (i.e. out of the
SCons-managed files) causes "import subprocess" to find the actual,
system-installed subprocess module, which does not contain the buggy
locking.
2012-03-01 17:36:58 -05:00
Eliot Horowitz
05da017dee post 2.0.3 2012-02-27 23:43:29 -05:00
Eliot Horowitz
05bb8aa793 BUMP 2.0.3 2012-02-26 19:44:09 -05:00
Mathias Stearn
3fc4863624 Correctly count bulk inserts in opcounters SERVER-3817 2012-02-20 09:29:01 -05:00
Eliot Horowitz
a83ab12c51 post 2.0.3-rc1 2012-02-18 01:49:38 -05:00
Eliot Horowitz
ac5eb821bb BUMP 2.0.3-rc1 2012-02-17 10:49:28 -05:00
Eliot Horowitz
7948814df6 put installDir in env so can be accessed from other places 2012-02-16 22:47:54 -05:00
Richard Kreuter
3b1fecd968 Backport of fix from SERVER-3824. 2012-02-16 14:19:10 -05:00
Brandon Diamond
29cd169c4d SERVER-3112: Improved stdout/err in mongoexport 2012-02-15 16:48:45 -05:00
Brandon Diamond
f96f1c70ec CS-1535: Avoid writing to stderr unless dumping to stdout 2012-02-15 16:46:57 -05:00
Brandon Diamond
24e1f0b92e CS-1535: Added method for toggling stdout/stderr in tools 2012-02-15 16:39:20 -05:00
Kristina
8849484b70 Replication should not create _id index for capped collections SERVER-4626 2012-02-15 10:19:38 -05:00
Kristina
8c259b9984 Fix replsettest: shouldRetry should create client context SERVER-4626 2012-02-15 10:16:44 -05:00
Kristina
2bedc3cf68 Don't re-clone docs to capped collections SERVER-4626 2012-02-15 10:14:17 -05:00
Kristina
ad9f37fddb Do not require _id index for capped collection update SERVER-4546 2012-02-15 10:09:25 -05:00
Spencer T Brody
dd046106ba Calculating which shard(s) to send $in queries to was taking a long time. This fix changes mongos to stop limiting the shards to send to after the first $in clause - possibly sending the query to more shards than necessary, but saving time. SERVER-4745. 2012-02-09 19:25:00 -05:00
Dan Crosta
d77cc8d850 post 2.0.3-rc0 2012-02-07 10:43:31 -05:00
Eliot Horowitz
643c3a25c7 BUMP 2.0.3-rc0 2012-02-06 13:12:10 -05:00
Eliot Horowitz
d39bc96a0c don't print out leak message more than once per minutes SERVER-4780 2012-02-06 00:52:20 -05:00
Eliot Horowitz
43fa534919 Merge branch 'v2.0' of github.com:mongodb/mongo into v2.0 2012-02-06 00:47:36 -05:00
Eliot Horowitz
e74f5546d5 fix --use-system-snappy SERVER-4634 2012-02-06 00:21:07 -05:00
Eliot Horowitz
4ef4f1904c fix mode 2012-02-04 01:13:58 -05:00
Eliot Horowitz
0bd2737e38 try to make chmod work 2012-02-04 01:13:02 -05:00
Eliot Horowitz
5fc7c288e0 fix segfault in mongos with some replica set changes 2012-02-04 01:09:34 -05:00
Greg Studer
5c71438495 buildbot replReads.js hidden nodes now correctly updated in mongos, should disappear from config 2012-02-03 19:14:02 -05:00
gregs
9ee926acf4 buildbot primary can change after reconfig replReads.js 2012-02-03 19:06:56 -05:00
Dan Crosta
2d4f7f4c88 correct version number comparison 2012-02-03 18:39:54 -05:00
Dan Crosta
3885acaf7a python-2.4-compatible version of python version detection 2012-02-03 18:21:20 -05:00
Eliot Horowitz
6b3ab0f6e1 try to make chmod work 2012-02-02 23:47:01 -05:00
Greg Studer
6b2231a15c SERVER-4399 make replica set updating more reliable in c++ driver, remove nodes when no longer present in config 2012-02-01 14:00:05 -05:00
Greg Studer
9a09c9f1af SERVER-4712 check that query results are valid before using in case of conn error 2012-02-01 13:58:17 -05:00
Greg Studer
527d4d28df SERVER-4765 sharded_passthrough.js we need to actually pass the query to currentop via mongos 2012-02-01 13:58:04 -05:00
Dan Crosta
5e29dc25bb make python version detection quiet 2012-01-31 11:32:59 -05:00
Dan Crosta
4770f74e6e even better python version/binary detection 2012-01-31 11:20:02 -05:00
Dan Crosta
9bbdf6d86b be smarter about picking python name to invoke smoke.py 2012-01-31 10:48:03 -05:00
Dan Crosta
9bc4189471 call smoke.py with python 2.5 2012-01-31 10:37:37 -05:00
Dan Crosta
330e2a7407 roll back previous py-2.4 compatibility changes 2012-01-31 10:37:22 -05:00
Dan Crosta
6f9da3de69 python 2.4 compatibility 2012-01-31 10:21:16 -05:00
Eliot Horowitz
ab1e828dd7 fix ssl mem leak 2012-01-26 01:36:41 -05:00
Eric Milkie
076f88cf6f avoid "unused local variable" warnings from g++ 2012-01-24 10:28:12 -05:00
Eric Milkie
5ca3f27109 adding new scopeguard utility classes/macro
ScopeGuard helps make writing RAII easier.  You can avoid coding like this:
                try {
                    inRepair(true);
                    function_that_might_throw();
                    inRepair(false);
                }
                catch(...) {
                    inRepair(false);
                    throw;
                }

With scopeguard, the new code looks like this:
                {
                    inRepair(true);
                    ON_BLOCK_EXIT(inRepair, false);
                    function_that_might_throw();
                }

See the code comments for more details and examples.
2012-01-24 10:28:09 -05:00
Eric Milkie
937077b4c1 SERVER-3763 SERVER-4643 use correct connection
There were two automatic variables named "conn" in scope, with one occluding the other.  I mistakenly changed the logic in my last commit, so I have now fixed it, and removed the overlapping scopes.
2012-01-24 09:18:16 -05:00
Eric Milkie
c202889e9c SERVER-3763 SERVER-4643 catch exceptions on connect to other shards when handling multiple shard case 2012-01-24 09:18:05 -05:00
Eric Milkie
078c791acd SERVER-3763 SERVER-4643 avoid exceptions in getlasterror due to other shards being down
I had to move the creation of ShardConnection inside the try/catch because it is possible that it might throw a SocketException if the shard is down.
This change allows shard_gle_insert.js to pass on Windows, and may alleviate Linux failures with getLastError as well.
2012-01-24 09:16:42 -05:00
Eliot Horowitz
41a6f84004 ifix concurrency api when using openssl SERVER-4749 2012-01-24 00:36:10 -05:00
Dan Crosta
c3449caf1a SERVER-4591: python-2.4 compatible version of rpartition 2012-01-20 15:59:21 -08:00
Spencer T Brody
c91aa2519e Don't allow full mongorestore on sharded cluster. SERVER-4547. 2012-01-20 17:12:41 -05:00
Kristina
29f74a507c Always lock ScopedConn before returning SERVER-4714 2012-01-20 12:14:10 -05:00
Eliot Horowitz
68e305862a fix getLog auth SERVER-4695 2012-01-17 01:11:08 -05:00
Aaron
0b38e1009b SERVER-4665 backport 'ConstraintPresent' constraint type and exclusion of unhelpful recorded plans 2012-01-16 21:54:07 -08:00
Kristina
86e26ee445 "authenticate" command should not take read lock unless necessary SERVER-4673 2012-01-12 16:02:19 -08:00
Eliot Horowitz
3aaea5262d this test requries shell features in 2.2
tested with a 2.2 shell to make sure it works
2012-01-07 23:00:41 -05:00
gregs
6e95d546e2 SERVER-4387 force reload of config data after multiple exceptions for commands 2012-01-02 13:09:56 -05:00
Aaron
2d5c1aeeb4 SERVER-4401 attempt to advance to next or clause if a cursor becomes invalid on yield recovery 2011-12-24 11:30:54 -08:00
Aaron
b8447afd0e SERVER-4400 don't record query plan if a client cursor yield recovery fails; this patch violates the QueryOp abstraction a bit, but we are replacing that code soon anyway 2011-12-24 11:30:54 -08:00
Brandon Diamond
53bc8fe361 SERVER-3641 SERVER-1458: mongostat uses auth with mongos/repsets 2011-12-22 11:59:59 -05:00
Kristina
5464d74491 Auth before cloning collection during rollback SERVER-4115 2011-12-22 11:59:07 -05:00
Kristina
400d7730ef Whitespace SERVER-4238 2011-12-22 11:58:45 -05:00
Kristina
774b90baee Make sure auth is always registered for rs connections SERVER-4238 2011-12-22 11:58:39 -05:00
Kristina
45190b81b5 Ignore capped dup key error on initial sync SERVER-4474 2011-12-22 11:58:08 -05:00
Tad Marshall
8cd62bc27c SERVER-2612 -- support logRotate under windows
Add code to support the "logRotate" server command (e.g. "db.runCommand({logRotate:1})").
Windows does not support the "kill -SIGUSR1 <pid>" alternative that is available in
Linux.
2011-12-22 11:57:34 -05:00
Mathias Stearn
a719914879 use fadvise(dontneed) for log file SERVER-3380 2011-12-22 11:57:30 -05:00
Kristina
843bc2c58e allow majority to be all nodes SERVER-3672 2011-12-22 11:54:35 -05:00
Kristina
d88037845b Cloner shouldn't call logOp() when creating a collection on the secondary SERVER-3939 2011-12-22 11:53:46 -05:00
Greg Studer
3eaa472e9a don't re-use deleted connections from rset after runCommand 2011-12-19 14:49:18 -05:00
Eliot Horowitz
feb1ef76fc post 2.0.2 2011-12-14 18:03:04 -05:00
Eliot Horowitz
514b122d30 BUMP 2.0.2 2011-12-14 12:18:48 -05:00
Greg Studer
a841b2e681 buildbot sharding_rs2.js wait for replica set update in mongos before trying slaveok'd connection 2011-12-13 21:27:41 -05:00
Greg Studer
6759c3ffa1 SERVER-4465 wait for refresh if multiple retries fail for sharded count() 2011-12-12 10:51:10 -05:00
gregs
9e517db3e1 compile unused vars in v8 code 2011-12-12 10:51:10 -05:00
Greg Studer
9179db2dc8 SERVER-4465 don't abort on local version reset unless it's a meaningful reset 2011-12-11 00:06:04 -05:00
Eliot Horowitz
f8a4019253 post 2.0.2-rc2 2011-12-08 15:07:57 -05:00
Eliot Horowitz
7d32bec61f BUMP 2.0.2-rc2 2011-12-07 16:32:33 -05:00
Eliot Horowitz
4d5e2c7b4f backport of SERVER-4430 2011-12-06 00:08:53 -05:00
Kristina
b9e4db5cdc Count new RS members as up before they are initialized 2011-12-05 23:49:17 -05:00
Eliot Horowitz
85488010f7 fix test for when sockets close 2011-12-03 00:12:34 -05:00
gregs
f0d35552f7 buildbot v2.0.2 replica_set_shard_version.js reconnect after stepdown and fix other timing issues 2011-12-02 11:33:22 -05:00
Kristina
468b35887e Fix MessagingPort to register all ports in global list 2011-12-01 16:35:37 -05:00
Eliot Horowitz
d99fcfeb75 hit config server only once when loading a chunk meta data certain version SERVER-4396 2011-12-01 00:07:06 -05:00
Eliot Horowitz
bd438596e1 fix oplog replay segfault SERVER-4350 2011-11-23 02:35:32 -05:00
Eliot Horowitz
2a4486134b make profile1 test more robust 2011-11-22 14:02:53 -05:00
Eliot Horowitz
48e6b7b16e post 2.0.2-rc1 2011-11-22 10:06:28 -05:00
Eliot Horowitz
c0044c79fb Merge branch 'v2.0' of github.com:mongodb/mongo into v2.0 2011-11-22 10:05:50 -05:00
Eliot Horowitz
a91919f726 BUMP 2.0.2-rc1 2011-11-22 00:45:21 -05:00
dwight
e9ec52c686 add some extra_info for windows serverStatus output 2011-11-21 17:50:34 -05:00
gregs
bc22bd4487 track initialization of conns SERVER-4324 2011-11-21 14:53:26 -05:00
Eliot Horowitz
d69d52ceef ignore sharding state on secondaries consistently SERVER-4324 2011-11-21 13:13:17 -05:00
Eliot Horowitz
c0588190d4 handle non-sharded query not master errors SERVER-4324 2011-11-21 01:02:06 -05:00
Eliot Horowitz
415486ce5c test for SERVER-4324 2011-11-21 01:01:49 -05:00
Eliot Horowitz
f48ecaa2c6 when we get a "not master" error on a command, check for new primary SERVER-4324 2011-11-21 01:01:43 -05:00
Eliot Horowitz
163a0ede78 don't leak connections when onCreate or onHandOut hook fails SERVER-4331 2011-11-21 01:01:33 -05:00
Eliot Horowitz
3a57f18f76 post 2.0.2-rc0 2011-11-18 01:42:39 -05:00
Eliot Horowitz
ada33ce4be BUMP 2.0.2-rc0 2011-11-17 11:52:18 -05:00
Eliot Horowitz
7e3de32bcc limit number of concurrent splitVectors SERVER-4296 2011-11-16 16:11:39 -05:00
Eliot Horowitz
e82af25e9c scons flag to use each library externally --use-system-(prcre|boost) SERVER-3829
currently supported:

--use-system-all

--use-system-pcre
--use-system-sm

Conflicts:

	SConstruct
2011-11-16 13:17:32 -05:00
gregs
a695bea89c return arrays if arrays given SERVER-3661 2011-11-16 13:07:32 -05:00
gregs
771f7f7dd6 don't throw away conn on gle SERVER-4290 2011-11-16 12:34:39 -05:00
Kristina
b9e8ac58d2 Fix auth1 test 2011-11-15 15:06:43 -05:00
agirbal
84a3d7aa3d SERVER-3528: memory footprint of JS context keeps increasing as it is used, delete every 100 use 2011-11-15 12:36:52 -05:00
Eliot Horowitz
8723be4f95 backport of Make sharded killOp/curOp/unlock check auth SERVER-4250 2011-11-14 15:55:05 -05:00
agirbal
58a501e059 - SERVER-4114: also add auth hook to shardConnectionPool 2011-11-14 15:51:35 -05:00
Eliot Horowitz
d4ba20e727 make buildInfo not require auth again (back to 1.8 behavior) SERVER-3837 2011-11-14 15:49:58 -05:00
Kristina
0f14f054c2 Change replset tests to use non-static applyOperation 2011-11-14 11:24:31 -05:00
Kristina
154f5545b6 Generalize recloning docs on initial oplog application SERVER-3367
Conflicts:

	db/repl.cpp
	db/repl/rs_sync.cpp
2011-11-14 11:23:29 -05:00
Spencer T Brody
e6e308d2c0 Add test for SERVER-4196. 2011-11-11 12:02:01 -05:00
Spencer T Brody
340048ba58 Make count command on mongos error after 5 failed attempts, instead of retrying indefinitely. SERVER-4196 2011-11-11 12:01:45 -05:00
gregs
e5cd12cde3 fix for backwards compatibility and shard versioning SERVER-4240 2011-11-10 18:38:30 -05:00
Kristina
d1854d7b70 Fix test - reconnect after server restart 2011-11-10 15:00:29 -05:00
gregs
cc5021feda SERVER-4242 hide splitter function 2011-11-10 12:07:32 -05:00
gregs
bc9d59f5db fix for helper function getChunkDistribution() 2011-11-10 11:28:00 -05:00
gregs
d42cf0df2b shell helpers for some sharding operations/status across a collection 2011-11-10 11:27:32 -05:00
Kristina
6cea95fbf5 Only sync from members that build indexes unless buildIndexes=false SERVER-4160
Conflicts:

	db/repl/rs_initialsync.cpp
2011-11-09 16:33:39 -05:00
gregs
50349cb760 SERVER-4209 remove warning for sharded sub-conn, this is expected now 2011-11-09 10:10:46 -05:00
Eliot Horowitz
d2feeb87c8 make test not hard code sharding knowledge 2011-11-08 13:31:56 -05:00
Eliot Horowitz
3e5d0e345b fix some unchecked mallocs SERVER-4228 2011-11-08 09:57:11 -05:00
Eliot Horowitz
0f6d8d7e4c fix test 2011-11-07 19:06:16 -05:00
gregs
e76f527687 SERVER-4171 modified test for wbl and new sharding, avoids S*RVER-4222 2011-11-07 12:52:24 -05:00
gregs
04ba3d198a reload shard version if needed for new collections in wbl SERVER-4171 2011-11-07 12:06:08 -05:00
gregs
4b1ac7b2b6 buildbot auto1.js sort() doesn't work the way we thought it did... 2011-11-07 02:44:07 -05:00
Eliot Horowitz
4514def09a make test depend less on sharding internals 2011-11-03 09:59:28 -04:00
gregs
bcf4ca4407 force reload of config after two failed wbl checks SERVER-4118 2011-11-01 18:42:28 -04:00
Eliot Horowitz
aede6b131d Revert "when splitting chunk thas has a max inf edge, don't leave a chunk bigger than max chunk size"
This reverts commit 41e5ee7a2f.
2011-11-01 18:06:18 -04:00
Eliot Horowitz
f275d3202a better chunking at beginning 2011-11-01 17:32:46 -04:00
Mathias Stearn
5862ea06eb fix mongosniff build (for me at least) 2011-11-01 13:17:53 -04:00
Mathias Stearn
c74b40f65a Fix shared-client build 2011-11-01 13:17:52 -04:00
Eliot Horowitz
897466810d make auth test reliable 2011-11-01 08:05:47 -04:00
Eliot Horowitz
975be960bb when splitting chunk thas has a max inf edge, don't leave a chunk bigger than max chunk size 2011-11-01 00:56:47 -04:00
gregs
ebdb2b61f3 dup error code 2011-10-31 21:12:32 -04:00
gregs
d11ede1282 initialize shard connection with serverId, only setShardV on single/replsets SERVER-4020 2011-10-31 21:10:01 -04:00
gregs
3e599665f8 spelling 2011-10-31 21:09:54 -04:00
Eliot Horowitz
65e38831fe fix bad assert in sharded getLastError handling 2011-10-29 01:15:44 -04:00
Eliot Horowitz
267bb38b54 option for turning off glibc check 2011-10-27 14:15:54 -04:00
gregs
0c382de588 more error handling and msgs for gle SERVER-3763 2011-10-25 00:03:31 -04:00
Kristina
de05cdff53 Set auth hook in final MR step, if it wasn't set previously SERVER-4114 2011-10-25 00:02:58 -04:00
Mathias Stearn
db49a5ce19 Catch DBException separate from std::exception SERVER-4137 2011-10-25 00:02:19 -04:00
Kristina
d04d7d118b Initialize auth status in non-default hb ctor 2011-10-24 15:02:33 -04:00
Kristina
e65e110553 Make secondaries go into recovering state when auth is wrong SERVER-3715 2011-10-24 15:00:33 -04:00
Kristina
f74345924b ScopedConn reconnection 2011-10-24 14:45:25 -04:00
Kristina
ccc60a0948 stop initial sync once minvalid is reached SERVER-3899 2011-10-24 10:23:24 -04:00
Eliot Horowitz
774ba87717 SERVER-3842 - make all initial chunks before marking collection sharded 2011-10-23 23:54:58 -04:00
Eliot Horowitz
f6c73c58a5 fix \. in printShardingStatus when looking up collections, part of SERVER-3702 2011-10-23 23:54:46 -04:00
Eliot Horowitz
b81ad0bae0 factor number of connections into memory leak warning SERVER-4063 2011-10-23 01:27:01 -04:00
Eliot
9fa387e6f0 Merge pull request #124 from ymarkovitch/v2.0
Fix for https://jira.mongodb.org/browse/SERVER-4070
2011-10-22 09:04:19 -07:00
Eliot Horowitz
9c5824c948 post 2.0.1 2011-10-22 01:23:41 -04:00
Eliot Horowitz
3a5cf0e213 BUMP 2.0.1 2011-10-21 20:52:16 -04:00
gregs
061c8ca173 buildbot need more time for file prealloc on big migrate sharding_migrateBigObject.js 2011-10-20 17:27:20 -04:00
Yakov Markovitch
241dab901c Merge branch 'v2.0' of git://github.com/mongodb/mongo into v2.0 2011-10-21 01:09:27 +04:00
Eliot Horowitz
9bf70fe751 post 2.0.1-rc1 2011-10-18 15:01:59 -04:00
Eliot Horowitz
4f42dce0db 2.0.1-rc1 2011-10-17 16:11:07 -04:00
Eliot Horowitz
858d2ad0cd fix segfault after modifying indexes during yield SERVER-3961 3 2011-10-16 18:13:30 -04:00
Yakov Markovitch
3bf3ab3bb1 Use const void* instead of const char* as data parameter of
appendBinData/appendBinDataArrayDeprecated

There is no much sense in explicit conversion of void pointers to
char pointers only to convert them back.
2011-10-15 02:54:17 +04:00
Yakov Markovitch
6f3f2379b9 Type qualifiers are ignored on function return type.
Prevent compiler from whining.
2011-10-14 21:03:24 +04:00
Yakov Markovitch
de0632c805 Add missing operator!= for BSONObj and BSONElement classes 2011-10-14 19:08:51 +04:00
Eliot Horowitz
b2910bcc5e make spinlocks degrade better when under high contention 2011-10-13 23:30:22 -04:00
gregs
9e642f566f add messaging for shard version reset at high verbosity SERVER-3889 2011-10-13 18:15:32 -04:00
Eliot Horowitz
9e8ae84247 post 2.0.1-rc0 2011-10-12 23:54:19 -04:00
Eliot Horowitz
3c02b91d0e BUMP 2.0.1-rc0 2011-10-12 01:29:44 -04:00
Eliot Horowitz
dda9a77986 debugging fot reconfig 2011-10-11 08:22:50 -04:00
Eliot Horowitz
a7a36ecbf0 use SpinLock for DiagStr 2011-10-10 00:44:15 -04:00
Eliot Horowitz
417b9110ce don't create ShardedConnectionInfo without an id 2011-10-08 23:35:43 -04:00
Spencer T Brody
0f605b5ab3 Fix mongoimport on jsonArrays. SERVER-3834 2011-10-08 23:33:49 -04:00
gregs
35a196a13e Replace "biggest" with shard name in error message SERVER-3813 2011-10-08 23:33:24 -04:00
Kristina
56b7cf65d1 check auth on _isSelf call SERVER-3953 2011-10-08 23:32:56 -04:00
dwight
41ff2157a3 SERVER-3962 previous commit wasnt right. backport. 2011-10-08 23:32:17 -04:00
dwight
a7796c9c09 finish SERVER-3962 2011-10-08 23:32:11 -04:00
dwight
8814b71b26 SERVER-3962 very high extraneous ismaster type commands from mongos to repl set if slaveok and no pure secondary is up 2011-10-08 23:32:01 -04:00
agirbal
17caecbd77 SERVER-3909: Blank lines don't work in the mongo shell starting with 2.0 2011-10-08 23:29:51 -04:00
agirbal
7f66400562 SERVER-3909: Blank lines don't work in the mongo shell starting with 2.0 2011-10-08 23:29:45 -04:00
Eliot Horowitz
f394d2c29a backport of SERVER-3875 2011-10-08 23:22:26 -04:00
dwight
05916b4e71 SERVER-3955 bug in diagstr::operator=. backport. 2011-10-08 23:19:37 -04:00
dwight
6728c042dd SERVER-3955. concurrency bug in DiagStr.
in addition, a t hread safe map impl.
2011-10-08 23:19:31 -04:00
Eliot Horowitz
afa5bc3d0e use SimpleMutex instead of SpinLock for record 2011-10-06 14:39:34 -04:00
Greg Studer
4eff1007c9 pass errmsg by ref 2011-10-06 11:29:00 -04:00
gregs
671479a616 better logging of stale configs for parallel cursor SERVER-3982 2011-10-04 18:08:54 -04:00
gregs
59aa78ea64 add lock pinger conn timeout, to avoid hanging SERVER-3784 2011-10-04 17:39:33 -04:00
gregs
414d14dbd8 Change test to allow the creation of new locks as well SERVER-3959 2011-10-04 17:38:10 -04:00
gregs
3461007a7a share lastpings between dist locks SERVER-3959 2011-10-04 17:37:54 -04:00
Eliot Horowitz
4063312d60 setProfilingLevel(2) not always working because millis set in wrong place SERVER-3910 2011-10-02 22:52:59 -04:00
gregs
729ad802c8 test for recheck of reset shard version SERVER-3889 2011-09-30 11:41:52 -04:00
gregs
0b2cd79560 auto-reload chunk manager to check version not reset after third staleconfig SERVER-3889 2011-09-30 11:41:17 -04:00
Kristina
fec06cfe91 upgrade indexes on resync SERVER-3900 2011-09-29 23:18:35 -04:00
Eliot Horowitz
47360db9e8 don't create ShardedConnectionInfo without an id 2011-09-28 16:48:32 -04:00
dwight
6aee211334 on a missing object, thats ok as a delete may occur later 2011-09-28 08:41:16 -04:00
dwight
33342ebb76 continuation of initial sync fix 2011-09-28 08:41:09 -04:00
dwight
f5f0053a1f fix a possible issue with initial sync with replication when updates are in flight.
also correct UpdateResult in one case
2011-09-28 08:41:03 -04:00
Eliot Horowitz
44da5dff2a paranoid compiler fix 2011-09-26 00:55:42 -04:00
Eliot Horowitz
2c34a826b6 fix numa parsing issue SERVER-3496 2011-09-26 00:55:36 -04:00
Eliot Horowitz
a05db65257 mutexDebugger only in DEBUG build 2011-09-26 00:40:18 -04:00
Spencer T Brody
b6bf498b3c Fix test 2011-09-23 18:25:22 -04:00
Spencer T Brody
99b2d74eb9 Use slaveOk read in mongodump to allow dumping of secondaries. SERVER-3854. 2011-09-23 17:29:46 -04:00
Kristina
7ce5d643a0 add test for SERVER-3799 2011-09-22 23:47:52 -04:00
Kristina
1eb2d4556d check tags in member config equality func SERVER-3799 2011-09-22 23:47:27 -04:00
Eliot Horowitz
fad753ee00 try/catch around send in mini webserver SERVER-3907 2011-09-22 23:44:49 -04:00
Eliot Horowitz
2250ff90c5 fix crash in filemd5 without correct index SERVER-3913 2011-09-22 23:38:23 -04:00
Eliot Horowitz
692f4ec8df fix reIndex on secondaries SERVER-3866 2011-09-14 22:51:16 -04:00
Mathias Stearn
ade41dcba8 Strip trailing / of dbpath on windows SERVER-3557 2011-09-12 14:50:30 -04:00
Eliot Horowitz
1c064ab915 snappy license info SERVER-3805 2011-09-12 14:48:07 -04:00
Eliot Horowitz
4449aae6e4 RamLog toHTML missing newline SERVER-3811 2011-09-12 12:39:25 -04:00
Eliot Horowitz
f2bf86ff3f 2.0.1 setup 2011-09-12 00:02:17 -04:00
Eliot Horowitz
695c67dff0 BUMP 2.0.0 2011-09-11 10:09:34 -04:00
228 changed files with 6577 additions and 1719 deletions

2
.gitignore vendored
View File

@ -43,6 +43,8 @@ shell/mongo-server.cpp
*/*/Debug/
*/Release/
*/*/Release/
*/ipch/
*/*/ipch/
db/.gdb*
db/makefile.local
db/_ReSharper.db

View File

@ -25,6 +25,17 @@ import buildscripts.bb
import stat
from buildscripts import utils
def _rpartition(string, sep):
"""A replacement for str.rpartition which is missing in Python < 2.5
"""
idx = string.rfind(sep)
if idx == -1:
return '', '', string
return string[:idx], sep, string[idx + 1:]
buildscripts.bb.checkOk()
def findSettingsSetup():
@ -32,6 +43,16 @@ def findSettingsSetup():
sys.path.append( ".." )
sys.path.append( "../../" )
def getThirdPartyShortNames():
lst = []
for x in os.listdir( "third_party" ):
if not x.endswith( ".py" ) or x.find( "#" ) >= 0:
continue
lst.append( _rpartition( x, "." )[0] )
return lst
# --- options ----
options = {}
@ -135,6 +156,8 @@ add_option( "staticlibpath", "comma separated list of dirs to search for staticl
add_option( "boost-compiler", "compiler used for boost (gcc41)" , 1 , True , "boostCompiler" )
add_option( "boost-version", "boost version for linking(1_38)" , 1 , True , "boostVersion" )
add_option( "no-glibc-check" , "don't check for new versions of glibc" , 0 , False )
# experimental features
add_option( "mm", "use main memory instead of memory mapped files" , 0 , True )
add_option( "asio" , "Use Asynchronous IO (NOT READY YET)" , 0 , True )
@ -170,6 +193,11 @@ add_option( "heapcheck", "link to heap-checking malloc-lib and look for memory l
add_option("smokedbprefix", "prefix to dbpath et al. for smoke tests", 1 , False )
for shortName in getThirdPartyShortNames():
add_option( "use-system-" + shortName , "use system version of library " + shortName , 0 , True )
add_option( "use-system-all" , "use all system libraries " + shortName , 0 , True )
# --- environment setup ---
def removeIfInList( lst , thing ):
@ -317,6 +345,7 @@ class InstallSetup:
self.clientTestsDir = "client/examples/"
installSetup = InstallSetup()
env["installSetup"] = installSetup
if distBuild:
installSetup.bannerDir = "distsrc"
@ -327,7 +356,7 @@ if has_option( "full" ):
# ------ SOURCE FILE SETUP -----------
commonFiles = Split( "pch.cpp buildinfo.cpp db/indexkey.cpp db/jsobj.cpp bson/oid.cpp db/json.cpp db/lasterror.cpp db/nonce.cpp db/queryutil.cpp db/querypattern.cpp db/projection.cpp shell/mongo.cpp db/security_common.cpp db/security_commands.cpp" )
commonFiles = Split( "pch.cpp buildinfo.cpp db/indexkey.cpp db/jsobj.cpp bson/oid.cpp db/json.cpp db/lasterror.cpp db/nonce.cpp db/queryutil.cpp db/querypattern.cpp db/projection.cpp shell/mongo.cpp" )
commonFiles += [ "util/background.cpp" , "util/util.cpp" , "util/file_allocator.cpp" ,
"util/assert_util.cpp" , "util/log.cpp" , "util/ramlog.cpp" , "util/md5main.cpp" , "util/base64.cpp", "util/concurrency/vars.cpp", "util/concurrency/task.cpp", "util/debug_util.cpp",
"util/concurrency/thread_pool.cpp", "util/password.cpp", "util/version.cpp", "util/signal_handlers.cpp",
@ -343,8 +372,9 @@ coreDbFiles = [ "db/commands.cpp" ]
coreServerFiles = [ "util/net/message_server_port.cpp" ,
"client/parallel.cpp" , "db/common.cpp",
"util/net/miniwebserver.cpp" , "db/dbwebserver.cpp" ,
"db/matcher.cpp" , "db/dbcommands_generic.cpp" , "db/dbmessage.cpp" ]
"db/matcher.cpp" , "db/dbcommands_generic.cpp" , "db/dbmessage.cpp",
"db/security_common.cpp", "db/security_commands.cpp",
]
mmapFiles = [ "util/mmap.cpp" ]
if has_option( "mm" ):
@ -514,6 +544,8 @@ elif "sunos5" == os.sys.platform:
solaris = True
env.Append( CPPDEFINES=[ "__sunos__" ] )
env.Append( LIBS=["socket","resolv"] )
# Use GNU tar instead of Solaris tar
env['TAR']="/opt/local/bin/tar"
elif os.sys.platform.startswith( "freebsd" ):
nix = True
@ -683,8 +715,11 @@ if nix:
env.Append( LIBS=[] )
#make scons colorgcc friendly
env['ENV']['HOME'] = os.environ['HOME']
env['ENV']['TERM'] = os.environ['TERM']
for key in ('HOME', 'TERM'):
try:
env['ENV'][key] = os.environ[key]
except KeyError:
pass
if linux and has_option( "sharedclient" ):
env.Append( LINKFLAGS=" -Wl,--as-needed -Wl,-zdefs " )
@ -757,21 +792,20 @@ if not windows:
keyfile = "jstests/libs/key%s" % keysuffix
os.chmod( keyfile , stat.S_IWUSR|stat.S_IRUSR )
for x in os.listdir( "third_party" ):
if not x.endswith( ".py" ) or x.find( "#" ) >= 0:
continue
shortName = x.rpartition( "." )[0]
path = "third_party/%s" % x
moduleFiles = {}
for shortName in getThirdPartyShortNames():
path = "third_party/%s.py" % shortName
myModule = imp.load_module( "third_party_%s" % shortName , open( path , "r" ) , path , ( ".py" , "r" , imp.PY_SOURCE ) )
fileLists = { "commonFiles" : commonFiles , "serverOnlyFiles" : serverOnlyFiles , "scriptingFiles" : scriptingFiles }
options_topass["windows"] = windows
options_topass["nix"] = nix
myModule.configure( env , fileLists , options_topass )
if has_option( "use-system-" + shortName ) or has_option( "use-system-all" ):
print( "using system version of: " + shortName )
myModule.configureSystem( env , fileLists , options_topass )
else:
myModule.configure( env , fileLists , options_topass )
coreServerFiles += scriptingFiles
@ -911,6 +945,7 @@ def doConfigure( myenv , shell=False ):
m.configure( conf , myenv )
if solaris:
conf.CheckLib( "rt" )
conf.CheckLib( "nsl" )
if usev8:
@ -1131,7 +1166,7 @@ if darwin or clientEnv["_HAVEPCAP"]:
sniffEnv.Append( LIBS=[ "wpcap" ] )
sniffEnv.Prepend( LIBPATH=["."] )
sniffEnv.Append( LIBS=[ "mongotestfiles" ] )
sniffEnv.Prepend( LIBS=[ "mongotestfiles" ] )
sniffEnv.Program( "mongosniff" , "tools/sniffer.cpp" )
@ -1166,6 +1201,7 @@ elif not onlyServer:
shellEnv = doConfigure( shellEnv , shell=True )
shellEnv.Prepend( LIBS=[ "mongoshellfiles"] )
mongo = shellEnv.Program( "mongo" , coreShellFiles )
@ -1200,7 +1236,7 @@ def addSmoketest( name, deps ):
else:
target = name[5].lower() + name[6:]
addTest(name, deps, [ "python buildscripts/smoke.py " + " ".join(smokeFlags) + ' ' + target ])
addTest(name, deps, [ utils.smoke_python_name() + " buildscripts/smoke.py " + " ".join(smokeFlags) + ' ' + target ])
addSmoketest( "smoke", [ add_exe( "test" ) ] )
addSmoketest( "smokePerf", [ "perftest" ] )
@ -1431,7 +1467,7 @@ def installBinary( e , name ):
if (solaris or linux) and (not has_option("nostrip")):
e.AddPostAction( inst, e.Action( 'strip ' + fullInstallName ) )
if linux and len( COMMAND_LINE_TARGETS ) == 1 and str( COMMAND_LINE_TARGETS[0] ) == "s3dist":
if not has_option( "no-glibc-check" ) and linux and len( COMMAND_LINE_TARGETS ) == 1 and str( COMMAND_LINE_TARGETS[0] ) == "s3dist":
e.AddPostAction( inst , checkGlibc )
if nix:
@ -1462,7 +1498,7 @@ if installSetup.headers:
if installSetup.clientSrc:
for x in allClientFiles:
x = str(x)
env.Install( installDir + "/mongo/" + x.rpartition( "/" )[0] , x )
env.Install( installDir + "/mongo/" + _rpartition( x, "/" )[0] , x )
#lib
if installSetup.libraries:
@ -1541,7 +1577,7 @@ def s3push( localName , remoteName=None , remotePrefix=None , fixName=True , pla
remoteName = localName
if fixName:
(root,dot,suffix) = localName.rpartition( "." )
(root,dot,suffix) = _rpartition( localName, "." )
name = remoteName + "-" + getSystemInstallName()
name += remotePrefix
if dot == "." :
@ -1598,7 +1634,7 @@ def build_and_test_client(env, target, source):
call(scons_command + ["libmongoclient.a", "clientTests"], cwd=installDir)
return bool(call(["python", "buildscripts/smoke.py",
return bool(call([utils.smoke_python_name(), "buildscripts/smoke.py",
"--test-path", installDir, "client"]))
env.Alias("clientBuild", [mongod, installDir], [build_and_test_client])
env.AlwaysBuild("clientBuild")

View File

@ -308,6 +308,8 @@ namespace mongo {
bool operator==(const BSONElement& r) const {
return woCompare( r , true ) == 0;
}
/** Returns true if elements are unequal. */
bool operator!=(const BSONElement& r) const { return !operator==(r); }
/** Well ordered comparison.
@return <0: l<r. 0:l==r. >0:l>r

View File

@ -254,6 +254,11 @@ namespace mongo {
BSONElement getFieldUsingIndexNames(const char *fieldName, const BSONObj &indexKey) const;
/** arrays are bson objects with numeric and increasing field names
@return true if field names are numeric and increasing
*/
bool couldBeArray() const;
/** @return the raw data of the object */
const char *objdata() const {
return _objdata;
@ -360,6 +365,7 @@ namespace mongo {
string md5() const;
bool operator==( const BSONObj& other ) const { return equal( other ); }
bool operator!=(const BSONObj& other) const { return !operator==( other); }
enum MatchType {
Equality = 0,

View File

@ -469,17 +469,14 @@ namespace mongo {
Use BinDataGeneral if you don't care about the type.
@param data the byte array
*/
BSONObjBuilder& appendBinData( const StringData& fieldName, int len, BinDataType type, const char *data ) {
BSONObjBuilder& appendBinData( const StringData& fieldName, int len, BinDataType type, const void *data ) {
_b.appendNum( (char) BinData );
_b.appendStr( fieldName );
_b.appendNum( len );
_b.appendNum( (char) type );
_b.appendBuf( (void *) data, len );
_b.appendBuf( data, len );
return *this;
}
BSONObjBuilder& appendBinData( const StringData& fieldName, int len, BinDataType type, const unsigned char *data ) {
return appendBinData(fieldName, len, type, (const char *) data);
}
/**
Subtype 2 is deprecated.
@ -487,13 +484,13 @@ namespace mongo {
@param data a byte array
@param len the length of data
*/
BSONObjBuilder& appendBinDataArrayDeprecated( const char * fieldName , const char * data , int len ) {
BSONObjBuilder& appendBinDataArrayDeprecated( const char * fieldName , const void * data , int len ) {
_b.appendNum( (char) BinData );
_b.appendStr( fieldName );
_b.appendNum( len + 4 );
_b.appendNum( (char)0x2 );
_b.appendNum( len );
_b.appendBuf( (void *) data, len );
_b.appendBuf( data, len );
return *this;
}
@ -755,6 +752,8 @@ namespace mongo {
int len() const { return _b.len(); }
int arrSize() const { return _i; }
private:
void fill( const StringData& name ) {
char *r;

View File

@ -61,7 +61,7 @@ namespace mongo {
// accessors
const char* data() const { return _data; }
const unsigned size() const { return _size; }
unsigned size() const { return _size; }
private:
const char* const _data; // is always null terminated

View File

@ -17,6 +17,7 @@
#pragma once
#include <cfloat>
#include <string>
#include <string.h>
#include <stdio.h>
@ -36,7 +37,7 @@ namespace mongo {
const int BSONObjMaxUserSize = 16 * 1024 * 1024;
/*
Sometimeswe we need objects slightly larger - an object in the replication local.oplog
Sometimes we need objects slightly larger - an object in the replication local.oplog
is slightly larger than a user object for example.
*/
const int BSONObjMaxInternalSize = BSONObjMaxUserSize + ( 16 * 1024 );
@ -65,6 +66,8 @@ namespace mongo {
if( p == buf ) {
if( sz <= SZ ) return buf;
void *d = malloc(sz);
if ( d == 0 )
msgasserted( 15912 , "out of memory StackAllocator::Realloc" );
memcpy(d, p, SZ);
return d;
}
@ -113,6 +116,8 @@ namespace mongo {
if ( maxSize && size > maxSize ) {
al.Free(data);
data = (char*)al.Malloc(maxSize);
if ( data == 0 )
msgasserted( 15913 , "out of memory BufBuilder::reset" );
size = maxSize;
}
}
@ -226,42 +231,51 @@ namespace mongo {
void decouple(); // not allowed. not implemented.
};
namespace {
#if defined(_WIN32)
#pragma warning( push )
// warning C4996: 'sprintf': This function or variable may be unsafe. Consider using sprintf_s instead. To disable deprecation, use _CRT_SECURE_NO_WARNINGS.
#pragma warning( disable : 4996 )
int (*mongo_snprintf)(char *str, size_t size, const char *format, ...) = &sprintf_s;
#else
int (*mongo_snprintf)(char *str, size_t size, const char *format, ...) = &snprintf;
#endif
}
/** stringstream deals with locale so this is a lot faster than std::stringstream for UTF8 */
class StringBuilder {
public:
static const size_t MONGO_DBL_SIZE = 3 + DBL_MANT_DIG - DBL_MIN_EXP;
static const size_t MONGO_S32_SIZE = 12;
static const size_t MONGO_U32_SIZE = 11;
static const size_t MONGO_S64_SIZE = 23;
static const size_t MONGO_U64_SIZE = 22;
static const size_t MONGO_S16_SIZE = 7;
StringBuilder( int initsize=256 )
: _buf( initsize ) {
}
StringBuilder& operator<<( double x ) {
return SBNUM( x , 25 , "%g" );
return SBNUM( x , MONGO_DBL_SIZE , "%g" );
}
StringBuilder& operator<<( int x ) {
return SBNUM( x , 11 , "%d" );
return SBNUM( x , MONGO_S32_SIZE , "%d" );
}
StringBuilder& operator<<( unsigned x ) {
return SBNUM( x , 11 , "%u" );
return SBNUM( x , MONGO_U32_SIZE , "%u" );
}
StringBuilder& operator<<( long x ) {
return SBNUM( x , 22 , "%ld" );
return SBNUM( x , MONGO_S64_SIZE , "%ld" );
}
StringBuilder& operator<<( unsigned long x ) {
return SBNUM( x , 22 , "%lu" );
return SBNUM( x , MONGO_U64_SIZE , "%lu" );
}
StringBuilder& operator<<( long long x ) {
return SBNUM( x , 22 , "%lld" );
return SBNUM( x , MONGO_S64_SIZE , "%lld" );
}
StringBuilder& operator<<( unsigned long long x ) {
return SBNUM( x , 22 , "%llu" );
return SBNUM( x , MONGO_U64_SIZE , "%llu" );
}
StringBuilder& operator<<( short x ) {
return SBNUM( x , 8 , "%hd" );
return SBNUM( x , MONGO_S16_SIZE , "%hd" );
}
StringBuilder& operator<<( char c ) {
_buf.grow( 1 )[0] = c;
@ -269,10 +283,12 @@ namespace mongo {
}
void appendDoubleNice( double x ) {
int prev = _buf.l;
char * start = _buf.grow( 32 );
int z = sprintf( start , "%.16g" , x );
const int prev = _buf.l;
const int maxSize = 32;
char * start = _buf.grow( maxSize );
int z = mongo_snprintf( start , maxSize , "%.16g" , x );
assert( z >= 0 );
assert( z < maxSize );
_buf.l = prev + z;
if( strchr(start, '.') == 0 && strchr(start, 'E') == 0 && strchr(start, 'N') == 0 ) {
write( ".0" , 2 );
@ -304,15 +320,12 @@ namespace mongo {
template <typename T>
StringBuilder& SBNUM(T val,int maxSize,const char *macro) {
int prev = _buf.l;
int z = sprintf( _buf.grow(maxSize) , macro , (val) );
int z = mongo_snprintf( _buf.grow(maxSize) , maxSize , macro , (val) );
assert( z >= 0 );
assert( z < maxSize );
_buf.l = prev + z;
return *this;
}
};
#if defined(_WIN32)
#pragma warning( pop )
#endif
} // namespace mongo

View File

@ -1,13 +1,15 @@
import sys
import os
import os, os.path
import utils
import time
from optparse import OptionParser
cwd = os.getcwd();
if cwd.find("buildscripts" ) > 0 :
cwd = cwd.partition( "buildscripts" )[0]
# set cwd to the root mongo dir, one level up from this
# file's location (if we're not already running from there)
cwd = os.getcwd()
if os.path.basename(cwd) == 'buildscripts':
cwd = os.path.dirname(cwd)
print( "cwd [" + cwd + "]" )
@ -38,7 +40,7 @@ def killprocs( signal="" ):
if not shouldKill( x ):
continue
pid = x.partition( " " )[0]
pid = x.split( " " )[0]
print( "killing: " + x )
utils.execsys( "/bin/kill " + signal + " " + pid )
killed = killed + 1

View File

@ -3,6 +3,8 @@ import re
import socket
import time
import os
import sys
# various utilities that are handy
def getAllSourceFiles( arr=None , prefix="." ):
@ -134,3 +136,34 @@ def didMongodStart( port=27017 , timeout=20 ):
timeout = timeout - 1
return False
def smoke_python_name():
# if this script is being run by py2.5 or greater,
# then we assume that "python" points to a 2.5 or
# greater python VM. otherwise, explicitly use 2.5
# which we assume to be installed.
min_version_tuple = (2, 5)
try:
if sys.version_info >= min_version_tuple:
return sys.executable
except AttributeError:
# In case the version of Python is somehow missing sys.version_info or sys.executable.
pass
import subprocess
version = re.compile(r'[Pp]ython ([\d\.]+)', re.MULTILINE)
binaries = ['python2.5', 'python2.6', 'python2.7', 'python25', 'python26', 'python27', 'python']
for binary in binaries:
try:
# py-2.4 compatible replacement for shell backticks
out, err = subprocess.Popen([binary, '-V'], stdout=subprocess.PIPE, stderr=subprocess.PIPE).communicate()
for stream in (out, err):
match = version.search(stream)
if match:
versiontuple = tuple(map(int, match.group(1).split('.')))
if versiontuple >= min_version_tuple:
return binary
except:
pass
# if that all fails, fall back to "python"
return "python"

View File

@ -38,7 +38,7 @@ namespace mongo {
void PoolForHost::done( DBConnectionPool * pool, DBClientBase * c ) {
if ( _pool.size() >= _maxPerHost ) {
pool->onDestory( c );
pool->onDestroy( c );
delete c;
}
else {
@ -55,7 +55,7 @@ namespace mongo {
_pool.pop();
if ( ! sc.ok( now ) ) {
pool->onDestory( sc.conn );
pool->onDestroy( sc.conn );
delete sc.conn;
continue;
}
@ -145,9 +145,15 @@ namespace mongo {
PoolForHost& p = _pools[PoolKey(host,socketTimeout)];
p.createdOne( conn );
}
onCreate( conn );
onHandedOut( conn );
try {
onCreate( conn );
onHandedOut( conn );
}
catch ( std::exception& e ) {
delete conn;
throw;
}
return conn;
}
@ -155,7 +161,13 @@ namespace mongo {
DBClientBase* DBConnectionPool::get(const ConnectionString& url, double socketTimeout) {
DBClientBase * c = _get( url.toString() , socketTimeout );
if ( c ) {
onHandedOut( c );
try {
onHandedOut( c );
}
catch ( std::exception& e ) {
delete c;
throw;
}
return c;
}
@ -169,7 +181,13 @@ namespace mongo {
DBClientBase* DBConnectionPool::get(const string& host, double socketTimeout) {
DBClientBase * c = _get( host , socketTimeout );
if ( c ) {
onHandedOut( c );
try {
onHandedOut( c );
}
catch ( std::exception& e ) {
delete c;
throw;
}
return c;
}
@ -185,7 +203,7 @@ namespace mongo {
void DBConnectionPool::release(const string& host, DBClientBase *c) {
if ( c->isFailed() ) {
onDestory( c );
onDestroy( c );
delete c;
return;
}
@ -228,12 +246,12 @@ namespace mongo {
}
}
void DBConnectionPool::onDestory( DBClientBase * conn ) {
void DBConnectionPool::onDestroy( DBClientBase * conn ) {
if ( _hooks->size() == 0 )
return;
for ( list<DBConnectionHook*>::iterator i = _hooks->begin(); i != _hooks->end(); i++ ) {
(*i)->onDestory( conn );
(*i)->onDestroy( conn );
}
}
@ -357,7 +375,7 @@ namespace mongo {
for ( size_t i=0; i<toDelete.size(); i++ ) {
try {
onDestory( toDelete[i] );
onDestroy( toDelete[i] );
delete toDelete[i];
}
catch ( ... ) {
@ -387,7 +405,7 @@ namespace mongo {
if ( _conn ) {
if ( ! _conn->isFailed() ) {
/* see done() comments above for why we log this line */
log() << "~ScopedDbConnection: _conn != null" << endl;
log() << "scoped connection to " << _conn->getServerAddress() << " not being returned to the pool" << endl;
}
kill();
}

View File

@ -89,7 +89,7 @@ namespace mongo {
virtual ~DBConnectionHook() {}
virtual void onCreate( DBClientBase * conn ) {}
virtual void onHandedOut( DBClientBase * conn ) {}
virtual void onDestory( DBClientBase * conn ) {}
virtual void onDestroy( DBClientBase * conn ) {}
};
/** Database connection pool.
@ -119,7 +119,7 @@ namespace mongo {
void onCreate( DBClientBase * conn );
void onHandedOut( DBClientBase * conn );
void onDestory( DBClientBase * conn );
void onDestroy( DBClientBase * conn );
void flush();

View File

@ -247,6 +247,11 @@ namespace mongo {
return o["ok"].trueValue();
}
bool DBClientWithCommands::isNotMasterErrorString( const BSONElement& e ) {
return e.type() == String && str::contains( e.valuestr() , "not master" );
}
enum QueryOptions DBClientWithCommands::availableOptions() {
if ( !_haveCachedAvailableOptions ) {
BSONObj ret;
@ -599,6 +604,20 @@ namespace mongo {
return true;
}
inline bool DBClientConnection::runCommand(const string &dbname, const BSONObj& cmd, BSONObj &info, int options) {
if ( DBClientWithCommands::runCommand( dbname , cmd , info , options ) )
return true;
if ( clientSet && isNotMasterErrorString( info["errmsg"] ) ) {
clientSet->isntMaster();
// At this point, we've probably deleted *this* object, do *not* use afterward
}
return false;
}
void DBClientConnection::_checkConnection() {
if ( !_failed )
return;
@ -933,6 +952,7 @@ namespace mongo {
an exception. we should make it return void and just throw an exception anytime
it fails
*/
checkConnection();
try {
if ( !port().call(toSend, response) ) {
_failed = true;
@ -982,8 +1002,7 @@ namespace mongo {
if ( clientSet && nReturned ) {
assert(data);
BSONObj o(data);
BSONElement e = getErrField(o);
if ( e.type() == String && str::contains( e.valuestr() , "not master" ) ) {
if ( isNotMasterErrorString( getErrField(o) ) ) {
clientSet->isntMaster();
}
}

View File

@ -721,8 +721,12 @@ namespace mongo {
}
protected:
/** if the result of a command is ok*/
bool isOk(const BSONObj&);
/** if the element contains a not master error */
bool isNotMasterErrorString( const BSONElement& e );
BSONObj _countCmd(const string &ns, const BSONObj& query, int options, int limit, int skip );
enum QueryOptions availableOptions();
@ -892,6 +896,8 @@ namespace mongo {
unsigned long long query( boost::function<void(const BSONObj&)> f, const string& ns, Query query, const BSONObj *fieldsToReturn = 0, int queryOptions = 0);
unsigned long long query( boost::function<void(DBClientCursorBatchIterator&)> f, const string& ns, Query query, const BSONObj *fieldsToReturn = 0, int queryOptions = 0);
virtual bool runCommand(const string &dbname, const BSONObj& cmd, BSONObj &info, int options=0);
/**
@return true if this connection is currently in a failed state. When autoreconnect is on,
a connection will transition back to an ok state after reconnecting.

View File

@ -72,6 +72,15 @@ namespace mongo {
} replicaSetMonitorWatcher;
string seedString( const vector<HostAndPort>& servers ){
string seedStr;
for ( unsigned i = 0; i < servers.size(); i++ ){
seedStr += servers[i].toString();
if( i < servers.size() - 1 ) seedStr += ",";
}
return seedStr;
}
ReplicaSetMonitor::ReplicaSetMonitor( const string& name , const vector<HostAndPort>& servers )
: _lock( "ReplicaSetMonitor instance" ) , _checkConnectionLock( "ReplicaSetMonitor check connection lock" ), _name( name ) , _master(-1), _nextSlave(0) {
@ -82,28 +91,36 @@ namespace mongo {
warning() << "replica set name empty, first node: " << servers[0] << endl;
}
log() << "starting new replica set monitor for replica set " << _name << " with seed of " << seedString( servers ) << endl;
string errmsg;
for ( unsigned i = 0; i < servers.size(); i++ ) {
for ( unsigned i=0; i<servers.size(); i++ ) {
bool haveAlready = false;
for ( unsigned n = 0; n < _nodes.size() && ! haveAlready; n++ )
haveAlready = ( _nodes[n].addr == servers[i] );
if( haveAlready ) continue;
// Don't check servers we have already
if( _find_inlock( servers[i] ) >= 0 ) continue;
auto_ptr<DBClientConnection> conn( new DBClientConnection( true , 0, 5.0 ) );
if (!conn->connect( servers[i] , errmsg ) ) {
log(1) << "error connecting to seed " << servers[i] << ": " << errmsg << endl;
try{
if( ! conn->connect( servers[i] , errmsg ) ){
throw DBException( errmsg, 15928 );
}
log() << "successfully connected to seed " << servers[i] << " for replica set " << this->_name << endl;
}
catch( DBException& e ){
log() << "error connecting to seed " << servers[i] << causedBy( e ) << endl;
// skip seeds that don't work
continue;
}
_nodes.push_back( Node( servers[i] , conn.release() ) );
int myLoc = _nodes.size() - 1;
string maybePrimary;
_checkConnection( _nodes[myLoc].conn.get() , maybePrimary, false, myLoc );
_checkConnection( conn.get(), maybePrimary, false, -1 );
}
// Check everything to get the first data
_check( true );
log() << "replica set monitor for replica set " << _name << " started, address is " << getServerAddress() << endl;
}
ReplicaSetMonitor::~ReplicaSetMonitor() {
@ -164,18 +181,21 @@ namespace mongo {
}
string ReplicaSetMonitor::getServerAddress() const {
scoped_lock lk( _lock );
return _getServerAddress_inlock();
}
string ReplicaSetMonitor::_getServerAddress_inlock() const {
StringBuilder ss;
if ( _name.size() )
ss << _name << "/";
{
scoped_lock lk( _lock );
for ( unsigned i=0; i<_nodes.size(); i++ ) {
if ( i > 0 )
ss << ",";
ss << _nodes[i].addr.toString();
}
for ( unsigned i=0; i<_nodes.size(); i++ ) {
if ( i > 0 )
ss << ",";
ss << _nodes[i].addr.toString();
}
return ss.str();
}
@ -191,6 +211,7 @@ namespace mongo {
void ReplicaSetMonitor::notifyFailure( const HostAndPort& server ) {
scoped_lock lk( _lock );
if ( _master >= 0 && _master < (int)_nodes.size() ) {
if ( server == _nodes[_master].addr ) {
_nodes[_master].ok = false;
@ -204,6 +225,7 @@ namespace mongo {
HostAndPort ReplicaSetMonitor::getMaster() {
{
scoped_lock lk( _lock );
assert(_master < static_cast<int>(_nodes.size()));
if ( _master >= 0 && _nodes[_master].ok )
return _nodes[_master].addr;
}
@ -212,6 +234,7 @@ namespace mongo {
scoped_lock lk( _lock );
uassert( 10009 , str::stream() << "ReplicaSetMonitor no master found for set: " << _name , _master >= 0 );
assert(_master < static_cast<int>(_nodes.size()));
return _nodes[_master].addr;
}
@ -247,43 +270,32 @@ namespace mongo {
}
HostAndPort ReplicaSetMonitor::getSlave() {
LOG(2) << "dbclient_rs getSlave " << getServerAddress() << endl;
LOG(2) << "selecting new slave from replica set " << getServerAddress() << endl;
scoped_lock lk( _lock );
// Logic is to retry three times for any secondary node, if we can't find any secondary, we'll take
// any "ok" node
// TODO: Could this query hidden nodes?
const int MAX = 3;
for ( int xxx=0; xxx<MAX; xxx++ ) {
{
scoped_lock lk( _lock );
unsigned i = 0;
for ( ; i<_nodes.size(); i++ ) {
_nextSlave = ( _nextSlave + 1 ) % _nodes.size();
if ( _nextSlave == _master ){
LOG(2) << "not selecting " << _nodes[_nextSlave] << " as it is the current master" << endl;
continue;
}
if ( _nodes[ _nextSlave ].okForSecondaryQueries() || ( _nodes[ _nextSlave ].ok && ( xxx + 1 ) >= MAX ) )
return _nodes[ _nextSlave ].addr;
LOG(2) << "not selecting " << _nodes[_nextSlave] << " as it is not ok to use" << endl;
}
for ( unsigned ii = 0; ii < _nodes.size(); ii++ ) {
_nextSlave = ( _nextSlave + 1 ) % _nodes.size();
if ( _nextSlave != _master ) {
if ( _nodes[ _nextSlave ].okForSecondaryQueries() )
return _nodes[ _nextSlave ].addr;
LOG(2) << "dbclient_rs getSlave not selecting " << _nodes[_nextSlave] << ", not currently okForSecondaryQueries" << endl;
}
}
check(false);
if( _master >= 0 ) {
assert( static_cast<unsigned>(_master) < _nodes.size() );
LOG(2) << "dbclient_rs getSlave no member in secondary state found, returning primary " << _nodes[ _master ] << endl;
return _nodes[_master].addr;
}
LOG(2) << "no suitable slave nodes found, returning default node " << _nodes[ 0 ] << endl;
LOG(2) << "dbclient_rs getSlave no suitable member found, returning first node " << _nodes[ 0 ] << endl;
assert( _nodes.size() > 0 );
return _nodes[0].addr;
}
/**
* notify the monitor that server has faild
* notify the monitor that server has failed
*/
void ReplicaSetMonitor::notifySlaveFailure( const HostAndPort& server ) {
int x = _find( server );
@ -293,12 +305,29 @@ namespace mongo {
}
}
void ReplicaSetMonitor::_checkStatus(DBClientConnection *conn) {
void ReplicaSetMonitor::_checkStatus( const string& hostAddr ) {
BSONObj status;
if (!conn->runCommand("admin", BSON("replSetGetStatus" << 1), status) ||
!status.hasField("members") ||
status["members"].type() != Array) {
/* replSetGetStatus requires admin auth so use a connection from the pool,
* which are authenticated with the keyFile credentials.
*/
ScopedDbConnection authenticatedConn( hostAddr );
if ( !authenticatedConn->runCommand( "admin", BSON( "replSetGetStatus" << 1 ), status )) {
LOG(1) << "dbclient_rs replSetGetStatus failed" << endl;
authenticatedConn.done(); // connection worked properly, but we got an error from server
return;
}
// Make sure we return when finished
authenticatedConn.done();
if( !status.hasField("members") ) {
log() << "dbclient_rs error expected members field in replSetGetStatus result" << endl;
return;
}
if( status["members"].type() != Array) {
log() << "dbclient_rs error expected members field in replSetGetStatus result to be an array" << endl;
return;
}
@ -324,51 +353,172 @@ namespace mongo {
}
}
void ReplicaSetMonitor::_checkHosts( const BSONObj& hostList, bool& changed ) {
NodeDiff ReplicaSetMonitor::_getHostDiff_inlock( const BSONObj& hostList ){
NodeDiff diff;
set<int> nodesFound;
int index = 0;
BSONObjIterator hi( hostList );
while( hi.more() ){
string toCheck = hi.next().String();
int nodeIndex = _find_inlock( toCheck );
// Node-to-add
if( nodeIndex < 0 ) diff.first.insert( toCheck );
else nodesFound.insert( nodeIndex );
index++;
}
for( size_t i = 0; i < _nodes.size(); i++ ){
if( nodesFound.find( static_cast<int>(i) ) == nodesFound.end() ) diff.second.insert( static_cast<int>(i) );
}
return diff;
}
bool ReplicaSetMonitor::_shouldChangeHosts( const BSONObj& hostList, bool inlock ){
int origHosts = 0;
if( ! inlock ){
scoped_lock lk( _lock );
origHosts = _nodes.size();
}
else origHosts = _nodes.size();
int numHosts = 0;
bool changed = false;
BSONObjIterator hi(hostList);
while ( hi.more() ) {
string toCheck = hi.next().String();
if ( _find( toCheck ) >= 0 )
continue;
numHosts++;
int index = 0;
if( ! inlock ) index = _find( toCheck );
else index = _find_inlock( toCheck );
if ( index >= 0 ) continue;
HostAndPort h( toCheck );
DBClientConnection * newConn = new DBClientConnection( true, 0, 5.0 );
string temp;
newConn->connect( h , temp );
{
scoped_lock lk( _lock );
if ( _find_inlock( toCheck ) >= 0 ) {
// we need this check inside the lock so there isn't thread contention on adding to vector
continue;
}
_nodes.push_back( Node( h , newConn ) );
}
log() << "updated set (" << _name << ") to: " << getServerAddress() << endl;
changed = true;
break;
}
return (changed || origHosts != numHosts) && numHosts > 0;
}
void ReplicaSetMonitor::_checkHosts( const BSONObj& hostList, bool& changed ) {
// Fast path, still requires intermittent locking
if( ! _shouldChangeHosts( hostList, false ) ){
changed = false;
return;
}
// Slow path, double-checked though
scoped_lock lk( _lock );
// Our host list may have changed while waiting for another thread in the meantime,
// so double-check here
// TODO: Do we really need this much protection, this should be pretty rare and not
// triggered from lots of threads, duping old behavior for safety
if( ! _shouldChangeHosts( hostList, true ) ){
changed = false;
return;
}
// LogLevel can be pretty low, since replica set reconfiguration should be pretty rare and
// we want to record our changes
log() << "changing hosts to " << hostList << " from " << _getServerAddress_inlock() << endl;
NodeDiff diff = _getHostDiff_inlock( hostList );
set<string> added = diff.first;
set<int> removed = diff.second;
assert( added.size() > 0 || removed.size() > 0 );
changed = true;
// Delete from the end so we don't invalidate as we delete, delete indices are ascending
for( set<int>::reverse_iterator i = removed.rbegin(), end = removed.rend(); i != end; ++i ){
log() << "erasing host " << _nodes[ *i ] << " from replica set " << this->_name << endl;
_nodes.erase( _nodes.begin() + *i );
}
// Add new nodes
for( set<string>::iterator i = added.begin(), end = added.end(); i != end; ++i ){
log() << "trying to add new host " << *i << " to replica set " << this->_name << endl;
// Connect to new node
HostAndPort h( *i );
DBClientConnection * newConn = new DBClientConnection( true, 0, 5.0 );
string errmsg;
try{
if( ! newConn->connect( h , errmsg ) ){
throw DBException( errmsg, 15927 );
}
log() << "successfully connected to new host " << *i << " in replica set " << this->_name << endl;
}
catch( DBException& e ){
warning() << "cannot connect to new host " << *i << " to replica set " << this->_name << causedBy( e ) << endl;
}
_nodes.push_back( Node( h , newConn ) );
}
// Invalidate the cached _master index since the _nodes structure has
// already been modified.
_master = -1;
}
bool ReplicaSetMonitor::_checkConnection( DBClientConnection * c , string& maybePrimary , bool verbose , int nodesOffset ) {
bool ReplicaSetMonitor::_checkConnection( DBClientConnection* conn,
string& maybePrimary, bool verbose, int nodesOffset ) {
assert( conn );
scoped_lock lk( _checkConnectionLock );
bool isMaster = false;
bool changed = false;
bool errorOccured = false;
if ( nodesOffset >= 0 ){
scoped_lock lk( _lock );
if ( !_checkConnMatch_inlock( conn, nodesOffset )) {
/* Another thread modified _nodes -> invariant broken.
* This also implies that another thread just passed
* through here and refreshed _nodes. So no need to do
* duplicate work.
*/
return false;
}
}
try {
Timer t;
BSONObj o;
c->isMaster(isMaster, &o);
conn->isMaster( isMaster, &o );
if ( o["setName"].type() != String || o["setName"].String() != _name ) {
warning() << "node: " << c->getServerAddress() << " isn't a part of set: " << _name
warning() << "node: " << conn->getServerAddress()
<< " isn't a part of set: " << _name
<< " ismaster: " << o << endl;
if ( nodesOffset >= 0 )
if ( nodesOffset >= 0 ) {
scoped_lock lk( _lock );
_nodes[nodesOffset].ok = false;
}
return false;
}
if ( nodesOffset >= 0 ) {
scoped_lock lk( _lock );
_nodes[nodesOffset].pingTimeMillis = t.millis();
_nodes[nodesOffset].hidden = o["hidden"].trueValue();
_nodes[nodesOffset].secondary = o["secondary"].trueValue();
@ -377,26 +527,42 @@ namespace mongo {
_nodes[nodesOffset].lastIsMaster = o.copy();
}
log( ! verbose ) << "ReplicaSetMonitor::_checkConnection: " << c->toString() << ' ' << o << endl;
log( ! verbose ) << "ReplicaSetMonitor::_checkConnection: " << conn->toString()
<< ' ' << o << endl;
// add other nodes
BSONArrayBuilder b;
if ( o["hosts"].type() == Array ) {
if ( o["primary"].type() == String )
maybePrimary = o["primary"].String();
_checkHosts(o["hosts"].Obj(), changed);
BSONObjIterator it( o["hosts"].Obj() );
while( it.more() ) b.append( it.next() );
}
if (o.hasField("passives") && o["passives"].type() == Array) {
_checkHosts(o["passives"].Obj(), changed);
}
_checkStatus(c);
if (o.hasField("passives") && o["passives"].type() == Array) {
BSONObjIterator it( o["passives"].Obj() );
while( it.more() ) b.append( it.next() );
}
_checkHosts( b.arr(), changed);
_checkStatus( conn->getServerAddress() );
}
catch ( std::exception& e ) {
log( ! verbose ) << "ReplicaSetMonitor::_checkConnection: caught exception " << c->toString() << ' ' << e.what() << endl;
_nodes[nodesOffset].ok = false;
log( ! verbose ) << "ReplicaSetMonitor::_checkConnection: caught exception "
<< conn->toString() << ' ' << e.what() << endl;
errorOccured = true;
}
if ( errorOccured && nodesOffset >= 0 ) {
scoped_lock lk( _lock );
if (_checkConnMatch_inlock(conn, nodesOffset)) {
// Make sure _checkHosts didn't modify the _nodes structure
_nodes[nodesOffset].ok = false;
}
}
if ( changed && _hook )
@ -406,63 +572,119 @@ namespace mongo {
}
void ReplicaSetMonitor::_check( bool checkAllSecondaries ) {
bool triedQuickCheck = false;
LOG(1) << "_check : " << getServerAddress() << endl;
int newMaster = -1;
shared_ptr<DBClientConnection> nodeConn;
for ( int retry = 0; retry < 2; retry++ ) {
for ( unsigned i=0; i<_nodes.size(); i++ ) {
shared_ptr<DBClientConnection> c;
bool triedQuickCheck = false;
if ( !checkAllSecondaries ) {
scoped_lock lk( _lock );
assert(_master < static_cast<int>(_nodes.size()));
if ( _master >= 0 ) {
/* Nothing else to do since another thread already
* found the _master
*/
return;
}
}
for ( unsigned i = 0; /* should not check while outside of lock! */ ; i++ ) {
{
scoped_lock lk( _lock );
c = _nodes[i].conn;
if ( i >= _nodes.size() ) break;
nodeConn = _nodes[i].conn;
}
string maybePrimary;
if ( _checkConnection( c.get() , maybePrimary , retry , i ) ) {
_master = i;
newMaster = i;
if ( ! checkAllSecondaries )
return;
}
if ( _checkConnection( nodeConn.get(), maybePrimary, retry, i ) ) {
scoped_lock lk( _lock );
if ( _checkConnMatch_inlock( nodeConn.get(), i )) {
_master = i;
newMaster = i;
if ( ! triedQuickCheck && maybePrimary.size() ) {
int x = _find( maybePrimary );
if ( x >= 0 ) {
triedQuickCheck = true;
string dummy;
shared_ptr<DBClientConnection> testConn;
{
scoped_lock lk( _lock );
testConn = _nodes[x].conn;
}
if ( _checkConnection( testConn.get() , dummy , false , x ) ) {
_master = x;
newMaster = x;
if ( ! checkAllSecondaries )
return;
}
if ( !checkAllSecondaries )
return;
}
else {
/*
* Somebody modified _nodes and most likely set the new
* _master, so try again.
*/
break;
}
}
if ( ! triedQuickCheck && ! maybePrimary.empty() ) {
int probablePrimaryIdx = -1;
shared_ptr<DBClientConnection> probablePrimaryConn;
{
scoped_lock lk( _lock );
probablePrimaryIdx = _find_inlock( maybePrimary );
if (probablePrimaryIdx >= 0) {
probablePrimaryConn = _nodes[probablePrimaryIdx].conn;
}
}
if ( probablePrimaryIdx >= 0 ) {
triedQuickCheck = true;
string dummy;
if ( _checkConnection( probablePrimaryConn.get(), dummy,
false, probablePrimaryIdx ) ) {
scoped_lock lk( _lock );
if ( _checkConnMatch_inlock( probablePrimaryConn.get(),
probablePrimaryIdx )) {
_master = probablePrimaryIdx;
newMaster = probablePrimaryIdx;
if ( ! checkAllSecondaries )
return;
}
else {
/*
* Somebody modified _nodes and most likely set the
* new _master, so try again.
*/
break;
}
}
}
}
}
if ( newMaster >= 0 )
return;
sleepsecs(1);
sleepsecs( 1 );
}
}
void ReplicaSetMonitor::check( bool checkAllSecondaries ) {
// first see if the current master is fine
if ( _master >= 0 ) {
shared_ptr<DBClientConnection> masterConn;
{
scoped_lock lk( _lock );
// first see if the current master is fine
if ( _master >= 0 ) {
assert(_master < static_cast<int>(_nodes.size()));
masterConn = _nodes[_master].conn;
}
}
if ( masterConn.get() != NULL ) {
string temp;
if ( _checkConnection( _nodes[_master].conn.get() , temp , false , _master ) ) {
if ( _checkConnection( masterConn.get(), temp, false, _master )) {
if ( ! checkAllSecondaries ) {
// current master is fine, so we're done
return;
@ -480,21 +702,17 @@ namespace mongo {
}
int ReplicaSetMonitor::_find_inlock( const string& server ) const {
for ( unsigned i=0; i<_nodes.size(); i++ )
if ( _nodes[i].addr == server )
const size_t size = _nodes.size();
for ( unsigned i = 0; i < size; i++ ) {
if ( _nodes[i].addr == server ) {
return i;
}
}
return -1;
}
int ReplicaSetMonitor::_find( const HostAndPort& server ) const {
scoped_lock lk( _lock );
for ( unsigned i=0; i<_nodes.size(); i++ )
if ( _nodes[i].addr == server )
return i;
return -1;
}
void ReplicaSetMonitor::appendInfo( BSONObjBuilder& b ) const {
scoped_lock lk( _lock );
BSONArrayBuilder hosts( b.subarrayStart( "hosts" ) );
@ -514,6 +732,13 @@ namespace mongo {
b.append( "nextSlave" , _nextSlave );
}
bool ReplicaSetMonitor::_checkConnMatch_inlock( DBClientConnection* conn,
size_t nodeOffset ) const {
return ( nodeOffset < _nodes.size() &&
conn->getServerAddress() == _nodes[nodeOffset].conn->getServerAddress() );
}
mongo::mutex ReplicaSetMonitor::_setsLock( "ReplicaSetMonitor" );
map<string,ReplicaSetMonitorPtr> ReplicaSetMonitor::_sets;
@ -537,6 +762,7 @@ namespace mongo {
// a master is selected. let's just make sure connection didn't die
if ( ! _master->isFailed() )
return _master.get();
_monitor->notifyFailure( _masterHost );
}
@ -579,7 +805,6 @@ namespace mongo {
warning() << "cached auth failed for set: " << _monitor->getName() << " db: " << a.dbname << " user: " << a.username << endl;
}
}
DBClientConnection& DBClientReplicaSet::masterConn() {
@ -686,6 +911,8 @@ namespace mongo {
}
auto_ptr<DBClientCursor> DBClientReplicaSet::checkSlaveQueryResult( auto_ptr<DBClientCursor> result ){
if ( result.get() == NULL ) return result;
BSONObj error;
bool isError = result->peekError( &error );
if( ! isError ) return result;
@ -820,10 +1047,14 @@ namespace mongo {
bool DBClientReplicaSet::call( Message &toSend, Message &response, bool assertOk , string * actualServer ) {
const char * ns = 0;
if ( toSend.operation() == dbQuery ) {
// TODO: might be possible to do this faster by changing api
DbMessage dm( toSend );
QueryMessage qm( dm );
ns = qm.ns;
if ( qm.queryOptions & QueryOption_SlaveOk ) {
for ( int i=0; i<3; i++ ) {
try {
@ -844,7 +1075,26 @@ namespace mongo {
DBClientConnection* m = checkMaster();
if ( actualServer )
*actualServer = m->getServerAddress();
return m->call( toSend , response , assertOk );
if ( ! m->call( toSend , response , assertOk ) )
return false;
if ( ns ) {
QueryResult * res = (QueryResult*)response.singleData();
if ( res->nReturned == 1 ) {
BSONObj x(res->data() );
if ( str::contains( ns , "$cmd" ) ) {
if ( isNotMasterErrorString( x["errmsg"] ) )
isntMaster();
}
else {
if ( isNotMasterErrorString( getErrField( x ) ) )
isntMaster();
}
}
}
return true;
}
}

View File

@ -24,6 +24,7 @@ namespace mongo {
class ReplicaSetMonitor;
typedef shared_ptr<ReplicaSetMonitor> ReplicaSetMonitorPtr;
typedef pair<set<string>,set<int> > NodeDiff;
/**
* manages state about a replica set for client
@ -92,7 +93,7 @@ namespace mongo {
string getName() const { return _name; }
string getServerAddress() const;
bool contains( const string& server ) const;
void appendInfo( BSONObjBuilder& b ) const;
@ -106,13 +107,20 @@ namespace mongo {
*/
ReplicaSetMonitor( const string& name , const vector<HostAndPort>& servers );
/**
* Checks all connections from the host list and sets the current
* master.
*
* @param checkAllSecondaries if set to false, stop immediately when
* the master is found or when _master is not -1.
*/
void _check( bool checkAllSecondaries );
/**
* Use replSetGetStatus command to make sure hosts in host list are up
* and readable. Sets Node::ok appropriately.
*/
void _checkStatus(DBClientConnection *conn);
void _checkStatus( const string& hostAddr );
/**
* Add array of hosts to host list. Doesn't do anything if hosts are
@ -124,25 +132,56 @@ namespace mongo {
/**
* Updates host list.
* @param c the connection to check
* Invariant: if nodesOffset is >= 0, _nodes[nodesOffset].conn should be
* equal to conn.
*
* @param conn the connection to check
* @param maybePrimary OUT
* @param verbose
* @param nodesOffset - offset into _nodes array, -1 for not in it
* @return if the connection is good
*
* @return true if the connection is good or false if invariant
* is broken
*/
bool _checkConnection( DBClientConnection * c , string& maybePrimary , bool verbose , int nodesOffset );
bool _checkConnection( DBClientConnection* conn, string& maybePrimary,
bool verbose, int nodesOffset );
string _getServerAddress_inlock() const;
NodeDiff _getHostDiff_inlock( const BSONObj& hostList );
bool _shouldChangeHosts( const BSONObj& hostList, bool inlock );
/**
* @return the index to _nodes corresponding to the server address.
*/
int _find( const string& server ) const ;
int _find_inlock( const string& server ) const ;
int _find( const HostAndPort& server ) const ;
mutable mongo::mutex _lock; // protects _nodes
/**
* Checks whether the given connection matches the connection stored in _nodes.
* Mainly used for sanity checking to confirm that nodeOffset still
* refers to the right connection after releasing and reacquiring
* a mutex.
*/
bool _checkConnMatch_inlock( DBClientConnection* conn, size_t nodeOffset ) const;
// protects _nodes and indices pointing to it (_master & _nextSlave)
mutable mongo::mutex _lock;
/**
* "Synchronizes" the _checkConnection method. Should ideally be one mutex per
* connection object being used. The purpose of this lock is to make sure that
* the reply from the connection the lock holder got is the actual response
* to what it sent.
*
* Deadlock WARNING: never acquire this while holding _lock
*/
mutable mongo::mutex _checkConnectionLock;
string _name;
struct Node {
Node( const HostAndPort& a , DBClientConnection* c )
: addr( a ) , conn(c) , ok(true) ,
: addr( a ) , conn(c) , ok( c != NULL ),
ismaster(false), secondary( false ) , hidden( false ) , pingTimeMillis(0) {
}

View File

@ -138,9 +138,10 @@ namespace mongo {
assert( !haveLimit );
auto_ptr<Message> response(new Message());
assert( _client );
_client->recv(*response);
b.m = response;
dataReceived();
if ( _client->recv(*response) ) {
b.m = response;
dataReceived();
}
}
void DBClientCursor::dataReceived( bool& retry, string& host ) {
@ -290,12 +291,23 @@ namespace mongo {
m.setData( dbKillCursors , b.buf() , b.len() );
if ( _client ) {
_client->sayPiggyBack( m );
// Kill the cursor the same way the connection itself would. Usually, non-lazily
if( DBClientConnection::getLazyKillCursor() )
_client->sayPiggyBack( m );
else
_client->say( m );
}
else {
assert( _scopedHost.size() );
ScopedDbConnection conn( _scopedHost );
conn->sayPiggyBack( m );
if( DBClientConnection::getLazyKillCursor() )
conn->sayPiggyBack( m );
else
conn->say( m );
conn.done();
}
}

View File

@ -22,6 +22,7 @@
namespace mongo {
LabeledLevel DistributedLock::logLvl( 1 );
DistributedLock::LastPings DistributedLock::lastPings;
ThreadLocalValue<string> distLockIds("");
@ -84,7 +85,7 @@ namespace mongo {
Date_t pingTime;
try {
ScopedDbConnection conn( addr );
ScopedDbConnection conn( addr, 30.0 );
pingTime = jsTime();
@ -110,6 +111,9 @@ namespace mongo {
// replace it for a quite a while)
// if the lock is taken, the take-over mechanism should handle the situation
auto_ptr<DBClientCursor> c = conn->query( DistributedLock::locksNS , BSONObj() );
// TODO: Would be good to make clear whether query throws or returns empty on errors
uassert( 16060, str::stream() << "cannot query locks collection on config server " << conn.getHost(), c.get() );
set<string> pids;
while ( c->more() ) {
BSONObj lock = c->next();
@ -224,7 +228,7 @@ namespace mongo {
string s = pingThreadId( conn, processId );
// Ignore if we already have a pinging thread for this process.
if ( _seen.count( s ) > 0 ) return "";
if ( _seen.count( s ) > 0 ) return s;
// Check our clock skew
try {
@ -300,9 +304,22 @@ namespace mongo {
_lockTimeout( lockTimeout == 0 ? LOCK_TIMEOUT : lockTimeout ), _maxClockSkew( _lockTimeout / LOCK_SKEW_FACTOR ), _maxNetSkew( _maxClockSkew ), _lockPing( _maxClockSkew ),
_mutex( "DistributedLock" )
{
log( logLvl - 1 ) << "created new distributed lock for " << name << " on " << conn
<< " ( lock timeout : " << _lockTimeout
<< ", ping interval : " << _lockPing << ", process : " << asProcess << " )" << endl;
log( logLvl ) << "created new distributed lock for " << name << " on " << conn
<< " ( lock timeout : " << _lockTimeout
<< ", ping interval : " << _lockPing << ", process : " << asProcess << " )"
<< endl;
}
DistributedLock::PingData DistributedLock::LastPings::getLastPing( const ConnectionString& conn, const string& lockName ){
scoped_lock lock( _mutex );
return _lastPings[ std::pair< string, string >( conn.toString(), lockName ) ];
}
void DistributedLock::LastPings::setLastPing( const ConnectionString& conn, const string& lockName, const PingData& pd ){
scoped_lock lock( _mutex );
_lastPings[ std::pair< string, string >( conn.toString(), lockName ) ] = pd;
}
Date_t DistributedLock::getRemoteTime() {
@ -458,6 +475,11 @@ namespace mongo {
// This should always be true, if not, we are using the lock incorrectly.
assert( _name != "" );
log( logLvl ) << "trying to acquire new distributed lock for " << _name << " on " << _conn
<< " ( lock timeout : " << _lockTimeout
<< ", ping interval : " << _lockPing << ", process : " << _processId << " )"
<< endl;
// write to dummy if 'other' is null
BSONObj dummyOther;
if ( other == NULL )
@ -512,6 +534,7 @@ namespace mongo {
unsigned long long elapsed = 0;
unsigned long long takeover = _lockTimeout;
PingData _lastPingCheck = getLastPing();
log( logLvl ) << "checking last ping for lock '" << lockName << "'" << " against process " << _lastPingCheck.get<0>() << " and ping " << _lastPingCheck.get<1>() << endl;
@ -527,8 +550,7 @@ namespace mongo {
if( recPingChange || recTSChange ) {
// If the ping has changed since we last checked, mark the current date and time
scoped_lock lk( _mutex );
_lastPingCheck = boost::tuple<string, Date_t, Date_t, OID>( lastPing["_id"].String().c_str(), lastPing["ping"].Date(), remote, o["ts"].OID() );
setLastPing( PingData( lastPing["_id"].String().c_str(), lastPing["ping"].Date(), remote, o["ts"].OID() ) );
}
else {
@ -540,7 +562,6 @@ namespace mongo {
else
elapsed = remote - _lastPingCheck.get<2>();
}
}
catch( LockException& e ) {

View File

@ -71,6 +71,22 @@ namespace mongo {
static LabeledLevel logLvl;
typedef boost::tuple<string, Date_t, Date_t, OID> PingData;
class LastPings {
public:
LastPings() : _mutex( "DistributedLock::LastPings" ) {}
~LastPings(){}
PingData getLastPing( const ConnectionString& conn, const string& lockName );
void setLastPing( const ConnectionString& conn, const string& lockName, const PingData& pd );
mongo::mutex _mutex;
map< std::pair<string, string>, PingData > _lastPings;
};
static LastPings lastPings;
/**
* The constructor does not connect to the configdb yet and constructing does not mean the lock was acquired.
* Construction does trigger a lock "pinging" mechanism, though.
@ -145,16 +161,12 @@ namespace mongo {
private:
void resetLastPing(){
scoped_lock lk( _mutex );
_lastPingCheck = boost::tuple<string, Date_t, Date_t, OID>();
}
void resetLastPing(){ lastPings.setLastPing( _conn, _name, PingData() ); }
void setLastPing( const PingData& pd ){ lastPings.setLastPing( _conn, _name, pd ); }
PingData getLastPing(){ return lastPings.getLastPing( _conn, _name ); }
mongo::mutex _mutex;
// Data from last check of process with ping time
boost::tuple<string, Date_t, Date_t, OID> _lastPingCheck;
// May or may not exist, depending on startup
mongo::mutex _mutex;
string _threadId;
};

View File

@ -195,6 +195,7 @@ namespace mongo {
boost::variate_generator<boost::mt19937&, boost::uniform_int<> > randomSkew(gen, boost::uniform_int<>(0, skewRange));
boost::variate_generator<boost::mt19937&, boost::uniform_int<> > randomWait(gen, boost::uniform_int<>(1, threadWait));
boost::variate_generator<boost::mt19937&, boost::uniform_int<> > randomSleep(gen, boost::uniform_int<>(1, threadSleep));
boost::variate_generator<boost::mt19937&, boost::uniform_int<> > randomNewLock(gen, boost::uniform_int<>(0, 3));
int skew = 0;
@ -262,7 +263,7 @@ namespace mongo {
}
else {
log() << "**** Not unlocking for thread " << threadId << endl;
DistributedLock::killPinger( *myLock );
assert( DistributedLock::killPinger( *myLock ) );
// We're simulating a crashed process...
break;
}
@ -274,6 +275,12 @@ namespace mongo {
break;
}
// Create a new lock 1/3 of the time
if( randomNewLock() > 1 ){
lock.reset(new DistributedLock( hostConn, lockName, takeoverMS, true ));
myLock = lock.get();
}
sleepmillis(randomSleep());
}

View File

@ -130,6 +130,12 @@ namespace mongo {
}
BSONObj GridFS::insertFile(const string& name, const OID& id, gridfs_offset length, const string& contentType) {
// Wait for any pending writebacks to finish
string err = _client.getLastError();
uassert( 16428,
str::stream() << "Error storing GridFS chunk for file: " << name
<< ", error: " << err,
err == "" );
BSONObj res;
if ( ! _client.runCommand( _dbName.c_str() , BSON( "filemd5" << id << "root" << _prefix ) , res ) )

View File

@ -67,7 +67,7 @@ namespace mongo {
assert( cursor );
if ( cursor->hasResultFlag( ResultFlag_ShardConfigStale ) ) {
throw StaleConfigException( _ns , "ClusteredCursor::query" );
throw StaleConfigException( _ns , "ClusteredCursor::_checkCursor" );
}
if ( cursor->hasResultFlag( ResultFlag_ErrSet ) ) {
@ -90,7 +90,7 @@ namespace mongo {
if ( conn.setVersion() ) {
conn.done();
throw StaleConfigException( _ns , "ClusteredCursor::query ShardConnection had to change" , true );
throw StaleConfigException( _ns , "ClusteredCursor::query" , true );
}
LOG(5) << "ClusteredCursor::query (" << type() << ") server:" << server
@ -365,6 +365,7 @@ namespace mongo {
void ParallelSortClusteredCursor::_finishCons() {
_numServers = _servers.size();
_lastFrom = 0;
_cursors = 0;
if ( ! _sortKey.isEmpty() && ! _fields.isEmpty() ) {
@ -490,7 +491,7 @@ namespace mongo {
if ( conns[i]->setVersion() ) {
conns[i]->done();
staleConfigExs.push_back( StaleConfigException( _ns , "ClusteredCursor::query ShardConnection had to change" , true ).what() + errLoc );
staleConfigExs.push_back( (string)"stale config detected for " + StaleConfigException( _ns , "ParallelCursor::_init" , true ).what() + errLoc );
break;
}
@ -503,7 +504,19 @@ namespace mongo {
0 , // nToSkip
_fields.isEmpty() ? 0 : &_fields , // fieldsToReturn
_options ,
_batchSize == 0 ? 0 : _batchSize + _needToSkip // batchSize
// NtoReturn is weird.
// If zero, it means use default size, so we do that for all cursors
// If positive, it's the batch size (we don't want this cursor limiting results), tha
// done at a higher level
// If negative, it's the batch size, but we don't create a cursor - so we don't want
// to create a child cursor either.
// Either way, if non-zero, we want to pull back the batch size + the skip amount as
// quickly as possible. Potentially, for a cursor on a single shard or if we keep be
// chunks, we can actually add the skip value into the cursor and/or make some assump
// return value size ( (batch size + skip amount) / num_servers ).
_batchSize == 0 ? 0 :
( _batchSize > 0 ? _batchSize + _needToSkip :
_batchSize - _needToSkip ) // batchSize
) );
try{
@ -592,7 +605,7 @@ namespace mongo {
// when we throw our exception
allConfigStale = true;
staleConfigExs.push_back( e.what() + errLoc );
staleConfigExs.push_back( (string)"stale config detected for " + e.what() + errLoc );
_cursors[i].reset( NULL );
conns[i]->done();
continue;
@ -681,7 +694,13 @@ namespace mongo {
BSONObj best = BSONObj();
int bestFrom = -1;
for ( int i=0; i<_numServers; i++) {
for( int j = 0; j < _numServers; j++ ){
// Iterate _numServers times, starting one past the last server we used.
// This means we actually start at server #1, not #0, but shouldn't matter
int i = ( j + _lastFrom + 1 ) % _numServers;
if ( ! _cursors[i].more() )
continue;
@ -702,6 +721,8 @@ namespace mongo {
bestFrom = i;
}
_lastFrom = bestFrom;
uassert( 10019 , "no more elements" , ! best.isEmpty() );
_cursors[bestFrom].next();

View File

@ -241,6 +241,7 @@ namespace mongo {
virtual void _explain( map< string,list<BSONObj> >& out );
int _numServers;
int _lastFrom;
set<ServerAndQuery> _servers;
BSONObj _sortKey;

View File

@ -1,4 +1,4 @@
/** @file redef_macros.h macros the implementation uses.
/** @file redef_macros.h macros for mongo internals
@see undef_macros.h undefines these after use to minimize name pollution.
*/
@ -20,42 +20,83 @@
// If you define a new global un-prefixed macro, please add it here and in undef_macros
// #pragma once // this file is intended to be processed multiple times
#if defined(MONGO_MACROS_CLEANED)
#define MONGO_MACROS_PUSHED 1
// util/allocator.h
#pragma push_macro("malloc")
#undef malloc
#define malloc MONGO_malloc
#pragma push_macro("realloc")
#undef realloc
#define realloc MONGO_realloc
// util/assert_util.h
#pragma push_macro("assert")
#undef assert
#define assert MONGO_assert
#pragma push_macro("verify")
#undef verify
#define verify MONGO_verify
#pragma push_macro("dassert")
#undef dassert
#define dassert MONGO_dassert
#pragma push_macro("wassert")
#undef wassert
#define wassert MONGO_wassert
#pragma push_macro("massert")
#undef massert
#define massert MONGO_massert
#pragma push_macro("uassert")
#undef uassert
#define uassert MONGO_uassert
#define BOOST_CHECK_EXCEPTION MONGO_BOOST_CHECK_EXCEPTION
#pragma push_macro("DESTRUCTOR_GUARD")
#undef DESTRUCTOR_GUARD
#define DESTRUCTOR_GUARD MONGO_DESTRUCTOR_GUARD
// util/goodies.h
#pragma push_macro("PRINT")
#undef PRINT
#define PRINT MONGO_PRINT
#pragma push_macro("PRINTFL")
#undef PRINTFL
#define PRINTFL MONGO_PRINTFL
#pragma push_macro("asctime")
#undef asctime
#define asctime MONGO_asctime
#pragma push_macro("gmtime")
#undef gmtime
#define gmtime MONGO_gmtime
#pragma push_macro("localtime")
#undef localtime
#define localtime MONGO_localtime
#pragma push_macro("ctime")
#undef ctime
#define ctime MONGO_ctime
// util/debug_util.h
#pragma push_macro("DEV")
#undef DEV
#define DEV MONGO_DEV
#pragma push_macro("DEBUGGING")
#undef DEBUGGING
#define DEBUGGING MONGO_DEBUGGING
#pragma push_macro("SOMETIMES")
#undef SOMETIMES
#define SOMETIMES MONGO_SOMETIMES
#pragma push_macro("OCCASIONALLY")
#undef OCCASIONALLY
#define OCCASIONALLY MONGO_OCCASIONALLY
#pragma push_macro("RARELY")
#undef RARELY
#define RARELY MONGO_RARELY
#pragma push_macro("ONCE")
#undef ONCE
#define ONCE MONGO_ONCE
// util/log.h
#pragma push_macro("LOG")
#undef LOG
#define LOG MONGO_LOG
#undef MONGO_MACROS_CLEANED
#endif

View File

@ -19,43 +19,65 @@
// #pragma once // this file is intended to be processed multiple times
#if !defined (MONGO_EXPOSE_MACROS)
/** MONGO_EXPOSE_MACROS - when defined, indicates that you are compiling a mongo program rather
than just using the C++ driver.
*/
#if !defined(MONGO_EXPOSE_MACROS) && !defined(MONGO_MACROS_CLEANED)
#ifdef MONGO_MACROS_PUSHED
// util/allocator.h
#undef malloc
#pragma pop_macro("malloc")
#undef realloc
#pragma pop_macro("realloc")
// util/assert_util.h
#undef assert
#pragma pop_macro("assert")
#undef dassert
#pragma pop_macro("dassert")
#undef wassert
#pragma pop_macro("wassert")
#undef massert
#pragma pop_macro("massert")
#undef uassert
#pragma pop_macro("uassert")
#undef BOOST_CHECK_EXCEPTION
#undef verify
#pragma pop_macro("verify")
#undef DESTRUCTOR_GUARD
#pragma pop_macro("DESTRUCTOR_GUARD")
// util/goodies.h
#undef PRINT
#pragma pop_macro("PRINT")
#undef PRINTFL
#pragma pop_macro("PRINTFL")
#undef asctime
#pragma pop_macro("asctime")
#undef gmtime
#pragma pop_macro("gmtime")
#undef localtime
#pragma pop_macro("localtime")
#undef ctime
#pragma pop_macro("ctime")
// util/debug_util.h
#undef DEV
#pragma pop_macro("DEV")
#undef DEBUGGING
#pragma pop_macro("DEBUGGING")
#undef SOMETIMES
#pragma pop_macro("SOMETIMES")
#undef OCCASIONALLY
#pragma pop_macro("OCCASIONALLY")
#undef RARELY
#pragma pop_macro("RARELY")
#undef ONCE
#pragma pop_macro("ONCE")
// util/log.h
#undef LOG
#pragma pop_macro("LOG")
#define MONGO_MACROS_CLEANED
#undef MONGO_MACROS_PUSHED
#endif
#endif

View File

@ -572,8 +572,8 @@ namespace mongo {
if ( readers )
*readers = r;
int time = r * 100;
time += w * 500;
int time = r * 10; // we have to be nice to readers since they don't have priority
time += w; // writers are greedy, so we can be mean tot hem
time = min( time , 1000000 );

View File

@ -457,7 +457,9 @@ namespace mongo {
if ( yielded ) {
*yielded = true;
}
return yield( yieldSuggest() , rec );
bool res = yield( yieldSuggest() , rec );
_yieldSometimesTracker.resetLastTime();
return res;
}
return true;
}
@ -467,12 +469,16 @@ namespace mongo {
if ( yielded ) {
*yielded = true;
}
return yield( micros , _recordForYield( need ) );
bool res = yield( micros , _recordForYield( need ) );
_yieldSometimesTracker.resetLastTime();
return res;
}
return true;
}
void ClientCursor::staticYield( int micros , const StringData& ns , Record * rec ) {
bool haveReadLock = dbMutex.atLeastReadLocked() && ! dbMutex.isWriteLocked();
killCurrentOp.checkForInterrupt( false );
{
auto_ptr<RWLockRecursive::Shared> lk;
@ -481,10 +487,16 @@ namespace mongo {
dbtempreleasecond unlock;
if ( unlock.unlocked() ) {
if ( micros == -1 )
micros = Client::recommendedYieldMicros();
if ( micros > 0 )
sleepmicros( micros );
if ( haveReadLock ) {
// don't sleep with a read lock
}
else {
if ( micros == -1 )
micros = Client::recommendedYieldMicros();
if ( micros > 0 )
sleepmicros( micros );
}
}
else {
CurOp * c = cc().curop();

View File

@ -68,7 +68,7 @@ namespace mongo {
/** copy the entire database */
bool go(const char *masterHost, string& errmsg, const string& fromdb, bool logForRepl, bool slaveOk, bool useReplAuth, bool snapshot, bool mayYield, bool mayBeInterrupted, int *errCode = 0);
bool copyCollection( const string& from , const string& ns , const BSONObj& query , string& errmsg , bool mayYield, bool mayBeInterrupted, bool copyIndexes = true, bool logForRepl = true );
bool copyCollection( const string& ns , const BSONObj& query , string& errmsg , bool mayYield, bool mayBeInterrupted, bool copyIndexes = true, bool logForRepl = true );
};
/* for index info object:
@ -83,6 +83,12 @@ namespace mongo {
BSONElement e = i.next();
if ( e.eoo() )
break;
// for now, skip the "v" field so that v:0 indexes will be upgraded to v:1
if ( string("v") == e.fieldName() ) {
continue;
}
if ( string("ns") == e.fieldName() ) {
uassert( 10024 , "bad ns field for index during dbcopy", e.type() == String);
const char *p = strchr(e.valuestr(), '.');
@ -163,7 +169,8 @@ namespace mongo {
getDur().commitIfNeeded();
}
catch( UserException& e ) {
log() << "warning: exception cloning object in " << from_collection << ' ' << e.what() << " obj:" << js.toString() << '\n';
error() << "error: exception cloning object in " << from_collection << ' ' << e.what() << " obj:" << js.toString() << '\n';
throw;
}
RARELY if ( time( 0 ) - saveLast > 60 ) {
@ -232,24 +239,26 @@ namespace mongo {
getDur().commitIfNeeded();
}
catch( UserException& e ) {
log() << "warning: exception cloning object in " << from_collection << ' ' << e.what() << " obj:" << js.toString() << '\n';
error() << "error: exception cloning object in " << from_collection << ' ' << e.what() << " obj:" << js.toString() << '\n';
throw;
}
}
}
}
bool copyCollectionFromRemote(const string& host, const string& ns, const BSONObj& query, string& errmsg, bool logForRepl, bool mayYield, bool mayBeInterrupted) {
bool copyCollectionFromRemote(const string& host, const string& ns, string& errmsg) {
Cloner c;
return c.copyCollection(host, ns, query, errmsg, mayYield, mayBeInterrupted, /*copyIndexes*/ true, logForRepl);
DBClientConnection *conn = new DBClientConnection();
// cloner owns conn in auto_ptr
c.setConnection(conn);
uassert(15908, errmsg, conn->connect(host, errmsg) && replAuthenticate(conn));
return c.copyCollection(ns, BSONObj(), errmsg, true, false, /*copyIndexes*/ true, false);
}
bool Cloner::copyCollection( const string& from , const string& ns , const BSONObj& query , string& errmsg , bool mayYield, bool mayBeInterrupted, bool copyIndexes, bool logForRepl ) {
auto_ptr<DBClientConnection> myconn;
myconn.reset( new DBClientConnection() );
if ( ! myconn->connect( from , errmsg ) )
return false;
conn.reset( myconn.release() );
bool Cloner::copyCollection( const string& ns, const BSONObj& query, string& errmsg,
bool mayYield, bool mayBeInterrupted, bool copyIndexes, bool logForRepl ) {
writelock lk(ns); // TODO: make this lower down
Client::Context ctx(ns);
@ -259,7 +268,7 @@ namespace mongo {
string temp = ctx.db()->name + ".system.namespaces";
BSONObj config = conn->findOne( temp , BSON( "name" << ns ) );
if ( config["options"].isABSONObj() )
if ( ! userCreateNS( ns.c_str() , config["options"].Obj() , errmsg, true , 0 ) )
if ( ! userCreateNS( ns.c_str() , config["options"].Obj() , errmsg, logForRepl , 0 ) )
return false;
}
@ -515,7 +524,14 @@ namespace mongo {
<< " query: " << query << " " << ( copyIndexes ? "" : ", not copying indexes" ) << endl;
Cloner c;
return c.copyCollection( fromhost , collection , query, errmsg , true, false, copyIndexes );
auto_ptr<DBClientConnection> myconn;
myconn.reset( new DBClientConnection() );
if ( ! myconn->connect( fromhost , errmsg ) )
return false;
c.setConnection( myconn.release() );
return c.copyCollection( collection , query, errmsg , true, false, copyIndexes );
}
} cmdclonecollection;

View File

@ -34,6 +34,6 @@ namespace mongo {
bool slaveOk, bool useReplAuth, bool snapshot, bool mayYield,
bool mayBeInterrupted, int *errCode = 0);
bool copyCollectionFromRemote(const string& host, const string& ns, const BSONObj& query, string& errmsg, bool logForRepl, bool mayYield, bool mayBeInterrupted);
bool copyCollectionFromRemote(const string& host, const string& ns, string& errmsg);
} // namespace mongo

View File

@ -239,7 +239,7 @@ namespace mongo {
cmdLine.noUnixSocket = true;
}
if (params.count("fork")) {
if (params.count("fork") && !params.count("shutdown")) {
if ( ! params.count( "logpath" ) ) {
cout << "--fork has to be used with --logpath" << endl;
::exit(-1);
@ -304,7 +304,7 @@ namespace mongo {
}
#endif
if (params.count("logpath")) {
if (params.count("logpath") && !params.count("shutdown")) {
if ( logpath.size() == 0 )
logpath = params["logpath"].as<string>();
uassert( 10033 , "logpath has to be non-zero" , logpath.size() );

View File

@ -4,6 +4,7 @@
#include "../../util/net/listen.h"
#include "../commands.h"
#include "../../client/dbclient.h"
#include "../security.h"
#ifndef _WIN32
# ifndef __sunos__
@ -211,6 +212,11 @@ namespace mongo {
return false;
}
if (!noauth && cmdLine.keyFile &&
!conn.auth("local", internalSecurity.user, internalSecurity.pwd, errmsg, false)) {
return false;
}
BSONObj out;
bool ok = conn.simpleCommand( "admin" , &out , "_isSelf" );

View File

@ -940,6 +940,7 @@ namespace mongo {
log(1) << "mr ns: " << config.ns << endl;
uassert( 16149 , "cannot run map reduce without the js engine", globalScriptEngine );
bool shouldHaveData = false;
long long num = 0;
@ -1119,6 +1120,7 @@ namespace mongo {
virtual LockType locktype() const { return NONE; }
bool run(const string& dbname , BSONObj& cmdObj, int, string& errmsg, BSONObjBuilder& result, bool) {
ShardedConnectionInfo::addHook();
string shardedOutputCollection = cmdObj["shardedOutputCollection"].valuestrsafe();
string postProcessCollection = cmdObj["postProcessCollection"].valuestrsafe();
bool postProcessOnly = !(postProcessCollection.empty());
@ -1205,7 +1207,7 @@ namespace mongo {
BSONObj res = config.reducer->finalReduce( values , config.finalizer.get());
if (state.isOnDisk())
state.insertToInc(res);
state.insert( config.tempLong , res );
else
state.emit(res);
values.clear();

View File

@ -180,6 +180,11 @@ namespace mongo {
d->deletedList[i].writing().Null();
}
// Start over from scratch with our extent sizing and growth
d->lastExtentSize=0;
// before dropping indexes, at least make sure we can allocate one extent!
uassert(14025, "compact error no space available to allocate", !allocateSpaceForANewRecord(ns, d, Record::HeaderSize+1, false).isNull());

View File

@ -708,6 +708,12 @@ int main(int argc, char* argv[]) {
else {
dbpath = "/data/db/";
}
#ifdef _WIN32
if (dbpath.size() > 1 && dbpath[dbpath.size()-1] == '/') {
// size() check is for the unlikely possibility of --dbpath "/"
dbpath = dbpath.erase(dbpath.size()-1);
}
#endif
if ( params.count("directoryperdb")) {
directoryperdb = true;
@ -983,22 +989,6 @@ int main(int argc, char* argv[]) {
procPath = (str::stream() << "/proc/" << pid);
if (!boost::filesystem::exists(procPath))
failed = true;
string exePath = procPath + "/exe";
if (boost::filesystem::exists(exePath)){
char buf[256];
int ret = readlink(exePath.c_str(), buf, sizeof(buf)-1);
buf[ret] = '\0'; // readlink doesn't terminate string
if (ret == -1) {
int e = errno;
cerr << "Error resolving " << exePath << ": " << errnoWithDescription(e);
failed = true;
}
else if (!endsWith(buf, "mongod")){
cerr << "Process " << pid << " is running " << buf << " not mongod" << endl;
::exit(-1);
}
}
}
catch (const std::exception& e){
cerr << "Error reading pid from lock file [" << name << "]: " << e.what() << endl;
@ -1065,14 +1055,6 @@ namespace mongo {
namespace mongo {
void pipeSigHandler( int signal ) {
#ifdef psignal
psignal( signal, "Signal Received : ");
#else
cout << "got pipe signal:" << signal << endl;
#endif
}
void abruptQuit(int x) {
ostringstream ossSig;
ossSig << "Got signal: " << x << " (" << strsignal( x ) << ")." << endl;
@ -1144,7 +1126,7 @@ namespace mongo {
assert( signal(SIGABRT, abruptQuit) != SIG_ERR );
assert( signal(SIGQUIT, abruptQuit) != SIG_ERR );
assert( signal(SIGPIPE, pipeSigHandler) != SIG_ERR );
assert( signal(SIGPIPE, SIG_IGN) != SIG_ERR );
setupSIGTRAPforGDB();
@ -1164,31 +1146,41 @@ namespace mongo {
}
#else
void ctrlCTerminate() {
log() << "got kill or ctrl-c signal, will terminate after current cmd ends" << endl;
Client::initThread( "ctrlCTerminate" );
void consoleTerminate( const char* controlCodeName ) {
Client::initThread( "consoleTerminate" );
log() << "got " << controlCodeName << ", will terminate after current cmd ends" << endl;
exitCleanly( EXIT_KILL );
}
BOOL CtrlHandler( DWORD fdwCtrlType ) {
switch( fdwCtrlType ) {
case CTRL_C_EVENT:
rawOut("Ctrl-C signal");
ctrlCTerminate();
return( TRUE );
rawOut( "Ctrl-C signal" );
consoleTerminate( "CTRL_C_EVENT" );
return TRUE ;
case CTRL_CLOSE_EVENT:
rawOut("CTRL_CLOSE_EVENT signal");
ctrlCTerminate();
return( TRUE );
rawOut( "CTRL_CLOSE_EVENT signal" );
consoleTerminate( "CTRL_CLOSE_EVENT" );
return TRUE ;
case CTRL_BREAK_EVENT:
rawOut("CTRL_BREAK_EVENT signal");
ctrlCTerminate();
rawOut( "CTRL_BREAK_EVENT signal" );
consoleTerminate( "CTRL_BREAK_EVENT" );
return TRUE;
case CTRL_LOGOFF_EVENT:
rawOut("CTRL_LOGOFF_EVENT signal (ignored)");
return FALSE;
rawOut( "CTRL_LOGOFF_EVENT signal" );
consoleTerminate( "CTRL_LOGOFF_EVENT" );
return TRUE;
case CTRL_SHUTDOWN_EVENT:
rawOut("CTRL_SHUTDOWN_EVENT signal (ignored)");
return FALSE;
rawOut( "CTRL_SHUTDOWN_EVENT signal" );
consoleTerminate( "CTRL_SHUTDOWN_EVENT" );
return TRUE;
default:
return FALSE;
}

View File

@ -333,6 +333,11 @@ namespace mongo {
virtual LockType locktype() const { return WRITE; }
CmdDropDatabase() : Command("dropDatabase") {}
bool run(const string& dbname, BSONObj& cmdObj, int, string& errmsg, BSONObjBuilder& result, bool fromRepl) {
// disallow dropping the config database
if ( cmdLine.configsvr && ( dbname == "config" ) ) {
errmsg = "Cannot drop 'config' database if mongod started with --configsvr";
return false;
}
BSONElement e = cmdObj.firstElement();
log() << "dropDatabase " << dbname << endl;
int p = (int) e.number();
@ -510,9 +515,19 @@ namespace mongo {
t.appendNumber( "mappedWithJournal" , m );
}
if( v - m > 5000 ) {
int overhead = v - m - connTicketHolder.used();
if( overhead > 4000 ) {
t.append("note", "virtual minus mapped is large. could indicate a memory leak");
log() << "warning: virtual size (" << v << "MB) - mapped size (" << m << "MB) is large. could indicate a memory leak" << endl;
static time_t last = 0;
time_t now = time(0);
if ( last + 60 < now ) {
last = now;
log() << "warning: virtual size (" << v << "MB) - mapped size (" << m << "MB) is large (" << overhead << "MB). could indicate a memory leak" << endl;
}
}
t.done();
@ -949,7 +964,7 @@ namespace mongo {
}
list<BSONObj> all;
auto_ptr<DBClientCursor> i = db.getIndexes( toDeleteNs );
auto_ptr<DBClientCursor> i = db.query( dbname + ".system.indexes" , BSON( "ns" << toDeleteNs ) , 0 , 0 , 0 , QueryOption_SlaveOk );
BSONObjBuilder b;
while ( i->more() ) {
BSONObj o = i->next().removeField("v").getOwned();
@ -1104,6 +1119,10 @@ namespace mongo {
BSONObj sort = BSON( "files_id" << 1 << "n" << 1 );
shared_ptr<Cursor> cursor = bestGuessCursor(ns.c_str(), query, sort);
if ( ! cursor ) {
errmsg = "need an index on { files_id : 1 , n : 1 }";
return false;
}
auto_ptr<ClientCursor> cc (new ClientCursor(QueryOption_NoCursorTimeout, cursor, ns.c_str()));
int n = 0;
@ -1746,6 +1765,7 @@ namespace mongo {
virtual bool slaveOk() const { return false; }
virtual LockType locktype() const { return WRITE; }
virtual bool requiresAuth() { return true; }
virtual bool logTheOp() { return true; }
virtual bool run(const string& dbname , BSONObj& cmdObj, int, string& errmsg, BSONObjBuilder& result, bool) {
string coll = cmdObj[ "emptycapped" ].valuestrsafe();
uassert( 13428, "emptycapped must specify a collection", !coll.empty() );

View File

@ -51,7 +51,8 @@ namespace mongo {
public:
CmdBuildInfo() : Command( "buildInfo", true, "buildinfo" ) {}
virtual bool slaveOk() const { return true; }
virtual bool adminOnly() const { return true; }
virtual bool adminOnly() const { return false; }
virtual bool requiresAuth() { return false; }
virtual LockType locktype() const { return NONE; }
virtual void help( stringstream &help ) const {
help << "get version #, etc.\n";
@ -333,7 +334,7 @@ namespace mongo {
virtual bool slaveOk() const { return true; }
virtual LockType locktype() const { return NONE; }
virtual bool requiresAuth() { return false; }
virtual bool requiresAuth() { return true; }
virtual bool adminOnly() const { return true; }
virtual void help( stringstream& help ) const {

View File

@ -157,6 +157,7 @@ namespace mongo {
}
DiskLoc Helpers::findById(NamespaceDetails *d, BSONObj idquery) {
assert(d);
int idxNo = d->findIdIndex();
uassert(13430, "no _id index", idxNo>=0);
IndexDetails& i = d->idx( idxNo );

View File

@ -79,11 +79,10 @@ namespace mongo {
}
bool allowed( const char * rq , vector<string>& headers, const SockAddr &from ) {
if ( from.isLocalHost() )
return true;
if ( ! _webUsers->haveAdminUsers() )
if ( from.isLocalHost() || !_webUsers->haveAdminUsers() ) {
cmdAuthenticate.authenticate( "admin", "RestUser", false );
return true;
}
string auth = getHeader( rq , "Authorization" );
@ -118,8 +117,10 @@ namespace mongo {
r << ha2;
string r1 = md5simpledigest( r.str() );
if ( r1 == parms["response"] )
if ( r1 == parms["response"] ) {
cmdAuthenticate.authenticate( "admin", user["user"].str(), user[ "readOnly" ].isBoolean() && user[ "readOnly" ].boolean() );
return true;
}
}
}

View File

@ -83,7 +83,7 @@ namespace mongo {
*/
static void groupCommit();
CommitJob commitJob;
CommitJob& commitJob = *(new CommitJob()); // don't destroy
Stats stats;
@ -434,7 +434,17 @@ namespace mongo {
fraction = 1;
lastRemap = now;
#if defined(_WIN32)
// Note that this negatively affects performance.
// We must grab the exclusive lock here because remapThePrivateView() on Windows needs
// to grab it as well, due to the lack of a non-atomic way to remap a memory mapped file.
// See SERVER-5723 for performance improvement.
// See SERVER-5680 to see why this code is necessary.
RWLockRecursive::Exclusive lk(MongoFile::mmmutex);
#else
RWLockRecursive::Shared lk(MongoFile::mmmutex);
#endif
set<MongoFile*>& files = MongoFile::getAllFiles();
unsigned sz = files.size();
if( sz == 0 )

View File

@ -164,6 +164,8 @@ namespace mongo {
CommitJob();
~CommitJob(){ assert(!"shouldn't destroy CommitJob!"); }
/** record/note an intent to write */
void note(void* p, int len);
@ -212,7 +214,7 @@ namespace mongo {
unsigned _nSinceCommitIfNeededCall;
};
extern CommitJob commitJob;
extern CommitJob& commitJob;
}
}

View File

@ -687,7 +687,7 @@ namespace mongo {
// must already be open -- so that _curFileId is correct for previous buffer building
assert( _curLogFile );
stats.curr->_uncompressedBytes += b.len();
stats.curr->_uncompressedBytes += uncompressed.len();
unsigned w = b.len();
_written += w;
assert( w <= L );

View File

@ -18,6 +18,10 @@
#include "pch.h"
#if defined(_WIN32)
# include <io.h>
#endif
#include "extsort.h"
#include "namespace-inl.h"
#include "../util/file.h"
@ -25,6 +29,7 @@
#include <sys/stat.h>
#include <fcntl.h>
namespace mongo {
IndexInterface *BSONObjExternalSorter::extSortIdxInterface;
@ -217,24 +222,87 @@ namespace mongo {
// -----------------------------------
BSONObjExternalSorter::FileIterator::FileIterator( string file ) {
unsigned long long length;
_buf = (char*)_file.map( file.c_str() , length , MemoryMappedFile::SEQUENTIAL );
massert( 10308 , "mmap failed" , _buf );
assert( length == (unsigned long long) file_size( file ) );
_end = _buf + length;
#ifdef _WIN32
_file = ::_open( file.c_str(), _O_BINARY | _O_RDWR | _O_CREAT , _S_IREAD | _S_IWRITE );
#else
_file = ::open( file.c_str(), O_CREAT | O_RDWR | O_NOATIME , S_IRUSR | S_IWUSR );
#endif
massert( 16392,
str::stream() << "FileIterator can't open file: "
<< file << errnoWithDescription(),
_file >= 0 );
#ifdef POSIX_FADV_DONTNEED
int err = posix_fadvise(_file, 0, 0, POSIX_FADV_SEQUENTIAL );
if ( err )
log() << "posix_fadvise failed: " << err << endl;
#endif
_length = (unsigned long long)boost::filesystem::file_size( file );
_readSoFar = 0;
}
BSONObjExternalSorter::FileIterator::~FileIterator() {
if ( _file >= 0 ) {
#ifdef _WIN32
_close( _file );
#else
::close( _file );
#endif
}
}
BSONObjExternalSorter::FileIterator::~FileIterator() {}
bool BSONObjExternalSorter::FileIterator::more() {
return _buf < _end;
return _readSoFar < _length;
}
bool BSONObjExternalSorter::FileIterator::_read( char* buf, long long count ) {
long long total = 0;
while ( total < count ) {
#ifdef _WIN32
long long now = ::_read( _file, buf, count );
#else
long long now = ::read( _file, buf, count );
#endif
if ( now < 0 ) {
log() << "read failed for BSONObjExternalSorter " << errnoWithDescription() << endl;
return false;
}
if ( now == 0 ) {
return false;
}
total += now;
buf += now;
}
return true;
}
BSONObjExternalSorter::Data BSONObjExternalSorter::FileIterator::next() {
BSONObj o( _buf );
_buf += o.objsize();
DiskLoc * l = (DiskLoc*)_buf;
_buf += 8;
return Data( o , *l );
// read BSONObj
int size;
assert( _read( reinterpret_cast<char*>(&size), 4 ) );
char* buf = reinterpret_cast<char*>( malloc( sizeof(unsigned) + size ) );
assert( buf );
memset( buf, 0, 4 ); // for Holder
memcpy( buf+sizeof(unsigned), reinterpret_cast<char*>(&size), sizeof(int) ); // size of doc
if ( ! _read( buf + sizeof(unsigned) + sizeof(int), size-sizeof(int) ) ) { // doc content
free( buf );
msgasserted( 16394, std::string("reading doc for external sort failed:") + errnoWithDescription() );
}
// read DiskLoc
DiskLoc l;
if ( ! _read( reinterpret_cast<char*>(&l), 8 ) ) {
free( buf );
msgasserted( 16393, std::string("reading DiskLoc for external sort failed") + errnoWithDescription() );
}
_readSoFar += 8 + size;
BSONObj::Holder* h = reinterpret_cast<BSONObj::Holder*>(buf);
return Data( BSONObj(h), l );
}
}

View File

@ -76,9 +76,11 @@ namespace mongo {
bool more();
Data next();
private:
MemoryMappedFile _file;
char * _buf;
char * _end;
bool _read( char* buf, long long count );
int _file;
unsigned long long _length;
unsigned long long _readSoFar;
};
public:

View File

@ -2647,7 +2647,10 @@ namespace mongo {
BSONObjBuilder bb( arr.subobjStart( BSONObjBuilder::numStr( x++ ) ) );
bb.append( "dis" , dis );
if( includeLocs ) bb.append( "loc" , p._pt );
if( includeLocs ){
if( p._pt.couldBeArray() ) bb.append( "loc", BSONArray( p._pt ) );
else bb.append( "loc" , p._pt );
}
bb.append( "obj" , p._o );
bb.done();
}

View File

@ -353,20 +353,19 @@ namespace mongo {
}
currentOp.ensureStarted();
currentOp.done();
int ms = currentOp.totalTimeMillis();
debug.executionTime = currentOp.totalTimeMillis();
//DEV log = true;
if ( log || ms > logThreshold ) {
if( logLevel < 3 && op == dbGetMore && strstr(ns, ".oplog.") && ms < 4300 && !log ) {
if ( log || debug.executionTime > logThreshold ) {
if( logLevel < 3 && op == dbGetMore && strstr(ns, ".oplog.") && debug.executionTime < 4300 && !log ) {
/* it's normal for getMore on the oplog to be slow because of use of awaitdata flag. */
}
else {
debug.executionTime = ms;
mongo::tlog() << debug << endl;
}
}
if ( currentOp.shouldDBProfile( ms ) ) {
if ( currentOp.shouldDBProfile( debug.executionTime ) ) {
// performance profiling is on
if ( dbMutex.getState() < 0 ) {
mongo::log(1) << "note: not profiling because recursive read lock" << endl;
@ -606,6 +605,8 @@ namespace mongo {
break;
js = d.nextJsObj(); // TODO: refactor to do objcheck outside of writelock
}
globalOpCounters.incInsertInWriteLock(n);
}
void receivedInsert(Message& m, CurOp& op) {
@ -873,6 +874,15 @@ namespace mongo {
}
catch (...) { }
#ifdef _WIN32
// Windows Service Controller wants to be told when we are down,
// so don't call ::exit() yet, or say "really exiting now"
//
if ( rc == EXIT_WINDOWS_SERVICE_STOP ) {
if ( c ) c->shutdown();
return;
}
#endif
tryToOutputFatal( "dbexit: really exiting now" );
if ( c ) c->shutdown();
::exit(rc);

View File

@ -753,6 +753,21 @@ namespace mongo {
return n;
}
bool BSONObj::couldBeArray() const {
BSONObjIterator i( *this );
int index = 0;
while( i.moreWithEOO() ){
BSONElement e = i.next();
if( e.eoo() ) break;
// TODO: If actually important, may be able to do int->char* much faster
if( strcmp( e.fieldName(), ((string)( str::stream() << index )).c_str() ) != 0 )
return false;
index++;
}
return true;
}
BSONObj BSONObj::clientReadable() const {
BSONObjBuilder b;
BSONObjIterator i( *this );

View File

@ -64,12 +64,21 @@ namespace mongo {
size_t protectSize = protectEnd - protectStart;
dassert(protectSize>0&&protectSize<=MemoryMappedFile::ChunkSize);
DWORD old;
bool ok = VirtualProtect((void*)protectStart, protectSize, PAGE_WRITECOPY, &old);
if( !ok ) {
DWORD e = GetLastError();
log() << "VirtualProtect failed (mcw) " << mmf->filename() << ' ' << chunkno << hex << protectStart << ' ' << protectSize << ' ' << errnoWithDescription(e) << endl;
assert(false);
DWORD oldProtection;
bool ok = VirtualProtect( reinterpret_cast<void*>( protectStart ),
protectSize,
PAGE_WRITECOPY,
&oldProtection );
if ( !ok ) {
DWORD dosError = GetLastError();
log() << "VirtualProtect for " << mmf->filename()
<< " chunk " << chunkno
<< " failed with " << errnoWithDescription( dosError )
<< " (chunk size is " << protectSize
<< ", address is " << hex << protectStart << dec << ")"
<< " in mongo::makeChunkWritable, terminating"
<< endl;
::abort();
}
}
@ -79,19 +88,25 @@ namespace mongo {
void* MemoryMappedFile::createPrivateMap() {
assert( maphandle );
scoped_lock lk(mapViewMutex);
void *p = MapViewOfFile(maphandle, FILE_MAP_READ, 0, 0, 0);
if ( p == 0 ) {
DWORD e = GetLastError();
log() << "createPrivateMap failed " << filename() << " " <<
errnoWithDescription(e) << " filelen:" << len <<
((sizeof(void*) == 4 ) ? " (32 bit build)" : "") <<
endl;
LPVOID thisAddress = getNextMemoryMappedFileLocation( len );
void* privateMapAddress = MapViewOfFileEx(
maphandle, // file mapping handle
FILE_MAP_READ, // access
0, 0, // file offset, high and low
0, // bytes to map, 0 == all
thisAddress ); // address to place file
if ( privateMapAddress == 0 ) {
DWORD dosError = GetLastError();
log() << "MapViewOfFileEx for " << filename()
<< " failed with " << errnoWithDescription( dosError )
<< " (file size is " << len << ")"
<< " in MemoryMappedFile::createPrivateMap, terminating"
<< endl;
::abort();
}
else {
clearWritableBits(p);
views.push_back(p);
}
return p;
clearWritableBits( privateMapAddress );
views.push_back( privateMapAddress );
return privateMapAddress;
}
void* MemoryMappedFile::remapPrivateView(void *oldPrivateAddr) {
@ -100,37 +115,34 @@ namespace mongo {
// the mapViewMutex is to assure we get the same address on the remap
scoped_lock lk(mapViewMutex);
RWLockRecursive::Exclusive lockMongoFiles(mmmutex);
clearWritableBits(oldPrivateAddr);
#if 1
// https://jira.mongodb.org/browse/SERVER-2942
DWORD old;
bool ok = VirtualProtect(oldPrivateAddr, (SIZE_T) len, PAGE_READONLY, &old);
if( !ok ) {
DWORD e = GetLastError();
log() << "VirtualProtect failed in remapPrivateView " << filename() << hex << oldPrivateAddr << ' ' << len << ' ' << errnoWithDescription(e) << endl;
assert(false);
}
return oldPrivateAddr;
#else
if( !UnmapViewOfFile(oldPrivateAddr) ) {
DWORD e = GetLastError();
log() << "UnMapViewOfFile failed " << filename() << ' ' << errnoWithDescription(e) << endl;
assert(false);
DWORD dosError = GetLastError();
log() << "UnMapViewOfFile for " << filename()
<< " failed with " << errnoWithDescription( dosError )
<< " in MemoryMappedFile::remapPrivateView, terminating"
<< endl;
::abort();
}
// we want the new address to be the same as the old address in case things keep pointers around (as namespaceindex does).
void *p = MapViewOfFileEx(maphandle, FILE_MAP_READ, 0, 0,
/*dwNumberOfBytesToMap 0 means to eof*/0 /*len*/,
oldPrivateAddr);
if ( p == 0 ) {
DWORD e = GetLastError();
log() << "MapViewOfFileEx failed " << filename() << " " << errnoWithDescription(e) << endl;
assert(p);
void* newPrivateView = MapViewOfFileEx(
maphandle, // file mapping handle
FILE_MAP_READ, // access
0, 0, // file offset, high and low
0, // bytes to map, 0 == all
oldPrivateAddr ); // we want the same address we had before
if ( oldPrivateAddr != newPrivateView ) {
DWORD dosError = GetLastError();
log() << "MapViewOfFileEx for " << filename()
<< " failed with " << errnoWithDescription( dosError )
<< " (file size is " << len << ")"
<< " in MemoryMappedFile::remapPrivateView, terminating"
<< endl;
::abort();
}
assert(p == oldPrivateAddr);
return p;
#endif
return newPrivateView;
}
#endif

View File

@ -625,9 +625,56 @@ namespace mongo {
}
}
void applyOperation_inlock(const BSONObj& op , bool fromRepl ) {
bool shouldRetry(const BSONObj& o, const string& hn) {
OplogReader missingObjReader;
const char *ns = o.getStringField("ns");
// should already have write lock
Client::Context ctx(ns);
// capped collections
NamespaceDetails *nsd = nsdetails(ns);
if (nsd && nsd->capped) {
log() << "replication missing doc, but this is okay for a capped collection (" << ns << ")" << endl;
return false;
}
// we don't have the object yet, which is possible on initial sync. get it.
log() << "replication info adding missing object" << endl; // rare enough we can log
uassert(15916, str::stream() << "Can no longer connect to initial sync source: " << hn, missingObjReader.connect(hn));
// might be more than just _id in the update criteria
BSONObj query = BSONObjBuilder().append(o.getObjectField("o2")["_id"]).obj();
BSONObj missingObj;
try {
missingObj = missingObjReader.findOne(ns, query);
} catch(DBException& e) {
log() << "replication assertion fetching missing object: " << e.what() << endl;
throw;
}
if( missingObj.isEmpty() ) {
log() << "replication missing object not found on source. presumably deleted later in oplog" << endl;
log() << "replication o2: " << o.getObjectField("o2").toString() << endl;
log() << "replication o firstfield: " << o.getObjectField("o").firstElementFieldName() << endl;
return false;
}
else {
DiskLoc d = theDataFileMgr.insert(ns, (void*) missingObj.objdata(), missingObj.objsize());
uassert(15917, "Got bad disk location when attempting to insert", !d.isNull());
return true;
}
}
/** @param fromRepl false if from ApplyOpsCmd
@return true if was and update should have happened and the document DNE. see replset initial sync code.
*/
bool applyOperation_inlock(const BSONObj& op , bool fromRepl ) {
assertInWriteLock();
LOG(6) << "applying op: " << op << endl;
bool failedUpdate = false;
OpCounters * opCounters = fromRepl ? &replOpCounters : &globalOpCounters;
@ -640,6 +687,7 @@ namespace mongo {
o = fields[0].embeddedObject();
const char *ns = fields[1].valuestrsafe();
NamespaceDetails *nsd = nsdetails(ns);
// operation type -- see logOp() comments for types
const char *opType = fields[2].valuestrsafe();
@ -660,29 +708,71 @@ namespace mongo {
if( !o.getObjectID(_id) ) {
/* No _id. This will be very slow. */
Timer t;
updateObjects(ns, o, o, true, false, false, debug );
updateObjects(ns, o, o, true, false, false, debug, true );
if( t.millis() >= 2 ) {
RARELY OCCASIONALLY log() << "warning, repl doing slow updates (no _id field) for " << ns << endl;
}
}
else {
/* erh 10/16/2009 - this is probably not relevant any more since its auto-created, but not worth removing */
RARELY ensureHaveIdIndex(ns); // otherwise updates will be slow
RARELY if (nsd && !nsd->capped) { ensureHaveIdIndex(ns); } // otherwise updates will be slow
/* todo : it may be better to do an insert here, and then catch the dup key exception and do update
then. very few upserts will not be inserts...
*/
BSONObjBuilder b;
b.append(_id);
updateObjects(ns, o, b.done(), true, false, false , debug );
updateObjects(ns, o, b.done(), true, false, false , debug, true );
}
}
}
else if ( *opType == 'u' ) {
opCounters->gotUpdate();
RARELY ensureHaveIdIndex(ns); // otherwise updates will be super slow
// dm do we create this for a capped collection?
// - if not, updates would be slow
// - but if were by id would be slow on primary too so maybe ok
// - if on primary was by another key and there are other indexes, this could be very bad w/out an index
// - if do create, odd to have on secondary but not primary. also can cause secondary to block for
// quite a while on creation.
RARELY if (nsd && !nsd->capped) { ensureHaveIdIndex(ns); } // otherwise updates will be super slow
OpDebug debug;
updateObjects(ns, o, op.getObjectField("o2"), /*upsert*/ fields[3].booleanSafe(), /*multi*/ false, /*logop*/ false , debug );
BSONObj updateCriteria = op.getObjectField("o2");
bool upsert = fields[3].booleanSafe();
UpdateResult ur = updateObjects(ns, o, updateCriteria, upsert, /*multi*/ false, /*logop*/ false , debug, true );
if( ur.num == 0 ) {
if( ur.mod ) {
if( updateCriteria.nFields() == 1 ) {
// was a simple { _id : ... } update criteria
failedUpdate = true;
// todo: probably should assert in these failedUpdate cases if not in initialSync
}
// need to check to see if it isn't present so we can set failedUpdate correctly.
// note that adds some overhead for this extra check in some cases, such as an updateCriteria
// of the form
// { _id:..., { x : {$size:...} }
// thus this is not ideal.
else {
if (nsd == NULL ||
(nsd->findIdIndex() >= 0 && Helpers::findById(nsd, updateCriteria).isNull()) ||
// capped collections won't have an _id index
(nsd->findIdIndex() < 0 && Helpers::findOne(ns, updateCriteria, false).isNull())) {
failedUpdate = true;
}
// Otherwise, it's present; zero objects were updated because of additional specifiers
// in the query for idempotence
}
}
else {
// this could happen benignly on an oplog duplicate replay of an upsert
// (because we are idempotent),
// if an regular non-mod update fails the item is (presumably) missing.
if( !upsert ) {
failedUpdate = true;
}
}
}
}
else if ( *opType == 'd' ) {
opCounters->gotDelete();
@ -703,7 +793,7 @@ namespace mongo {
else {
throw MsgAssertionException( 14825 , ErrorMsg("error in applyOperation : unknown opType ", *opType) );
}
return failedUpdate;
}
class ApplyOpsCmd : public Command {

View File

@ -129,6 +129,12 @@ namespace mongo {
* take an op and apply locally
* used for applying from an oplog
* @param fromRepl really from replication or for testing/internal/command/etc...
* Returns if the op was an update that could not be applied (true on failure)
*/
void applyOperation_inlock(const BSONObj& op , bool fromRepl = true );
bool applyOperation_inlock(const BSONObj& op , bool fromRepl = true );
/**
* If applyOperation_inlock should be called again after an update fails.
*/
bool shouldRetry(const BSONObj& op , const string& hn);
}

View File

@ -221,7 +221,8 @@ namespace mongo {
_skip( spec["skip"].numberLong() ),
_limit( spec["limit"].numberLong() ),
_nscanned(),
_bc() {
_bc(),
_yieldRecoveryFailed() {
}
virtual void _init() {
@ -251,6 +252,7 @@ namespace mongo {
virtual void recoverFromYield() {
if ( _cc && !ClientCursor::recoverFromYield( _yieldData ) ) {
_yieldRecoveryFailed = true;
_c.reset();
_cc.reset();
@ -309,7 +311,7 @@ namespace mongo {
}
long long count() const { return _count; }
virtual bool mayRecordPlan() const {
return ( _myCount > _limit / 2 ) || ( complete() && !stopRequested() );
return !_yieldRecoveryFailed && ( ( _myCount > _limit / 2 ) || ( complete() && !stopRequested() ) );
}
private:
@ -343,6 +345,7 @@ namespace mongo {
ClientCursor::CleanupPointer _cc;
ClientCursor::YieldData _yieldData;
bool _yieldRecoveryFailed;
};
/* { count: "collectionname"[, query: <query>] }
@ -474,7 +477,8 @@ namespace mongo {
_oplogReplay( pq.hasOption( QueryOption_OplogReplay) ),
_response( response ),
_eb( eb ),
_curop( curop )
_curop( curop ),
_yieldRecoveryFailed()
{}
virtual void _init() {
@ -531,6 +535,7 @@ namespace mongo {
_findingStartCursor->recoverFromYield();
}
else if ( _cc && !ClientCursor::recoverFromYield( _yieldData ) ) {
_yieldRecoveryFailed = true;
_c.reset();
_cc.reset();
_so.reset();
@ -723,7 +728,7 @@ namespace mongo {
}
virtual bool mayRecordPlan() const {
return ( _pq.getNumToReturn() != 1 ) && ( ( _n > _pq.getNumToReturn() / 2 ) || ( complete() && !stopRequested() ) );
return !_yieldRecoveryFailed && ( _pq.getNumToReturn() != 1 ) && ( ( _n > _pq.getNumToReturn() / 2 ) || ( complete() && !stopRequested() ) );
}
virtual QueryOp *_createChild() const {
@ -791,6 +796,8 @@ namespace mongo {
ExplainBuilder &_eb;
CurOp &_curop;
OpTime _slaveReadTill;
bool _yieldRecoveryFailed;
};
/* run a query -- includes checking for and running a Command \
@ -809,6 +816,7 @@ namespace mongo {
curop.debug().ns = ns;
curop.debug().ntoreturn = pq.getNumToReturn();
curop.debug().query = jsobj;
curop.setQuery(jsobj);
if ( pq.couldBeCommand() ) {
@ -909,6 +917,19 @@ namespace mongo {
Client& c = cc();
bool found = Helpers::findById( c, ns , query , resObject , &nsFound , &indexFound );
if ( nsFound == false || indexFound == true ) {
if ( shardingState.needShardChunkManager( ns ) ) {
ShardChunkManagerPtr m = shardingState.getShardChunkManager( ns );
if ( m && ! m->belongsToMe( resObject ) ) {
// I have something this _id
// but it doesn't belong to me
// so return nothing
resObject = BSONObj();
found = false;
}
}
BufBuilder bb(sizeof(QueryResult)+resObject.objsize()+32);
bb.skip(sizeof(QueryResult));

View File

@ -623,6 +623,17 @@ namespace mongo {
template< class Builder >
void ModSetState::_appendNewFromMods( const string& root , ModState& m , Builder& b , set<string>& onedownseen ) {
Mod& m2 = *((Mod*)(m.m)); // HACK
switch (m2.op) {
// unset/pull/pullAll on nothing does nothing, so don't append anything
case Mod::UNSET:
case Mod::PULL:
case Mod::PULL_ALL:
return;
default:
;// fall through
}
const char * temp = m.fieldName();
temp += root.size();
const char * dot = strchr( temp , '.' );
@ -642,6 +653,14 @@ namespace mongo {
}
bool ModSetState::duplicateFieldName( const BSONElement &a, const BSONElement &b ) {
return
!a.eoo() &&
!b.eoo() &&
( a.rawdata() != b.rawdata() ) &&
( a.fieldName() == string( b.fieldName() ) );
}
template< class Builder >
void ModSetState::createNewFromMods( const string& root , Builder& b , const BSONObj &obj ) {
DEBUGUPDATE( "\t\t createNewFromMods root: " << root );
@ -654,8 +673,18 @@ namespace mongo {
ModStateHolder::iterator mend = _mods.lower_bound( buf.str() );
set<string> onedownseen;
BSONElement prevE;
while ( e.type() && m != mend ) {
if ( duplicateFieldName( prevE, e ) ) {
// Just copy through an element with a duplicate field name.
b.append( e );
prevE = e;
e = es.next();
continue;
}
prevE = e;
string field = root + e.fieldName();
FieldCompareResult cmp = compareDottedFieldNames( m->second.m->fieldName , field );
@ -684,11 +713,9 @@ namespace mongo {
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);
massert( 16062 , "ModSet::createNewFromMods - "
"SERVER-4777 unhandled duplicate field" , 0 );
}
continue;
}
@ -1070,7 +1097,7 @@ namespace mongo {
return UpdateResult( 1 , 0 , 1 );
}
UpdateResult _updateObjects(bool god, const char *ns, const BSONObj& updateobj, BSONObj patternOrig, bool upsert, bool multi, bool logop , OpDebug& debug, RemoveSaver* rs ) {
UpdateResult _updateObjects(bool god, const char *ns, const BSONObj& updateobj, BSONObj patternOrig, bool upsert, bool multi, bool logop , OpDebug& debug, RemoveSaver* rs, bool hintIdElseNatural ) {
DEBUGUPDATE( "update: " << ns << " update: " << updateobj << " query: " << patternOrig << " upsert: " << upsert << " multi: " << multi );
Client& client = cc();
int profile = client.database()->profile;
@ -1119,7 +1146,7 @@ namespace mongo {
int numModded = 0;
long long nscanned = 0;
shared_ptr< MultiCursor::CursorOp > opPtr( new UpdateOp( mods.get() && mods->hasDynamicArray() ) );
shared_ptr< MultiCursor > c( new MultiCursor( ns, patternOrig, BSONObj(), opPtr, true ) );
shared_ptr< MultiCursor > c( new MultiCursor( ns, patternOrig, BSONObj(), opPtr, true, hintIdElseNatural ) );
d = nsdetails(ns);
nsdt = &NamespaceDetailsTransient::get_w(ns);
@ -1354,16 +1381,17 @@ namespace mongo {
logOp( "i", ns, no );
return UpdateResult( 0 , 0 , 1 , no );
}
return UpdateResult( 0 , 0 , 0 );
return UpdateResult( 0 , isOperatorUpdate , 0 );
}
UpdateResult updateObjects(const char *ns, const BSONObj& updateobj, BSONObj patternOrig, bool upsert, bool multi, bool logop , OpDebug& debug ) {
UpdateResult updateObjects(const char *ns, const BSONObj& updateobj, BSONObj patternOrig, bool upsert, bool multi, bool logop , OpDebug& debug, bool hintIdElseNatural ) {
uassert( 10155 , "cannot update reserved $ collection", strchr(ns, '$') == 0 );
if ( strstr(ns, ".system.") ) {
/* dm: it's very important that system.indexes is never updated as IndexDetails has pointers into it */
uassert( 10156 , str::stream() << "cannot update system collection: " << ns << " q: " << patternOrig << " u: " << updateobj , legalClientSystemNS( ns , true ) );
}
return _updateObjects(false, ns, updateobj, patternOrig, upsert, multi, logop, debug);
return _updateObjects(false, ns, updateobj, patternOrig, upsert, multi, logop, debug, 0, hintIdElseNatural);
}
}

View File

@ -50,9 +50,10 @@ namespace mongo {
multi - update multiple objects - mostly useful with things like $set
god - allow access to system namespaces
*/
UpdateResult updateObjects(const char *ns, const BSONObj& updateobj, BSONObj pattern, bool upsert, bool multi , bool logop , OpDebug& debug );
UpdateResult updateObjects(const char *ns, const BSONObj& updateobj, BSONObj pattern, bool upsert, bool multi , bool logop , OpDebug& debug, bool hintIdElseNatural = false );
UpdateResult _updateObjects(bool god, const char *ns, const BSONObj& updateobj, BSONObj pattern,
bool upsert, bool multi , bool logop , OpDebug& debug , RemoveSaver * rs = 0 );
bool upsert, bool multi , bool logop , OpDebug& debug , RemoveSaver * rs = 0,
bool hintIdElseNatural = false);
@ -623,6 +624,9 @@ namespace mongo {
}
/** @return true iff the elements aren't eoo(), are distinct, and share a field name. */
static bool duplicateFieldName( const BSONElement &a, const BSONElement &b );
public:
bool canApplyInPlace() const {

View File

@ -434,6 +434,7 @@ namespace mongo {
}
Extent* MongoDataFile::createExtent(const char *ns, int approxSize, bool newCapped, int loops) {
assert( approxSize <= Extent::maxSize() );
{
// make sizes align with VM page size
int newSize = (approxSize + 0xfff) & 0xfffff000;
@ -491,6 +492,10 @@ namespace mongo {
// overflowed
high = max(approxSize, Extent::maxSize());
}
if ( high <= Extent::minSize() ) {
// the minimum extent size is 4097
high = Extent::minSize() + 1;
}
int n = 0;
Extent *best = 0;
int bestDiff = 0x7fffffff;

View File

@ -313,7 +313,7 @@ namespace mongo {
Extent* getPrevExtent() { return xprev.isNull() ? 0 : DataFileMgr::getExtent(xprev); }
static int maxSize();
static int minSize() { return 0x100; }
static int minSize() { return 0x1000; }
/**
* @param len lengt of record we need
* @param lastRecord size of last extent which is a factor in next extent size

View File

@ -214,22 +214,6 @@ doneCheckOrder:
if ( willScanTable() ) {
if ( _frs.nNontrivialRanges() ) {
checkTableScanAllowed( _frs.ns() );
// if we are doing a table scan on _id
// and its a capped collection
// we disallow as its a common user error
// .system. and local collections are exempt
if ( _d && _d->capped && _frs.range( "_id" ).nontrivial() ) {
if ( cc().isSyncThread() ||
str::contains( _frs.ns() , ".system." ) ||
str::startsWith( _frs.ns() , "local." ) ) {
// ok
}
else {
warning() << "_id query on capped collection without an _id index, performance will be poor collection: " << _frs.ns() << endl;
//uassert( 14820, str::stream() << "doing _id query on a capped collection without an index is not allowed: " << _frs.ns() ,
}
}
}
return findTableScan( _frs.ns(), _order, startLoc );
}
@ -482,16 +466,18 @@ doneCheckOrder:
}
massert( 10368 , "Unable to locate previously recorded index", p.get() );
if ( !( _bestGuessOnly && p->scanAndOrderRequired() ) ) {
if ( !p->unhelpful() && !( _bestGuessOnly && p->scanAndOrderRequired() ) ) {
_usingPrerecordedPlan = true;
_mayRecordPlan = false;
_plans.push_back( p );
warnOnCappedIdTableScan();
return;
}
}
}
addOtherPlans( false );
warnOnCappedIdTableScan();
}
void QueryPlanSet::addOtherPlans( bool checkFirst ) {
@ -633,6 +619,31 @@ doneCheckOrder:
}
return _plans[0];
}
void QueryPlanSet::warnOnCappedIdTableScan() const {
// if we are doing a table scan on _id
// and it's a capped collection
// we warn as it's a common user error
// .system. and local collections are exempt
const char *ns = _frsp->ns();
NamespaceDetails *d = nsdetails( ns );
if ( d &&
d->capped &&
nPlans() == 1 &&
firstPlan()->willScanTable() &&
firstPlan()->multikeyFrs().range( "_id" ).nontrivial() ) {
if ( cc().isSyncThread() ||
str::contains( ns , ".system." ) ||
str::startsWith( ns , "local." ) ) {
// ok
}
else {
warning()
<< "unindexed _id query on capped collection, "
<< "performance will be poor collection: " << ns << endl;
}
}
}
QueryPlanSet::Runner::Runner( QueryPlanSet &plans, QueryOp &op ) :
_op( op ),
@ -995,8 +1006,12 @@ doneCheckOrder:
return QueryUtilIndexed::uselessOr( *_org, nsd, -1 );
}
MultiCursor::MultiCursor( const char *ns, const BSONObj &pattern, const BSONObj &order, shared_ptr<CursorOp> op, bool mayYield )
: _mps( new MultiPlanScanner( ns, pattern, order, 0, true, BSONObj(), BSONObj(), !op.get(), mayYield ) ), _nscanned() {
MultiCursor::MultiCursor( const char *ns, const BSONObj &pattern, const BSONObj &order, shared_ptr<CursorOp> op, bool mayYield, bool hintIdElseNatural ) :
_hint( hintIdElseNatural ? idElseNaturalHint( ns ) : BSONObj() ),
_hintElt( _hint.firstElement() ),
_mps( new MultiPlanScanner( ns, pattern, order, _hintElt.eoo() ? 0 : &_hintElt, true,
BSONObj(), BSONObj(), !op.get(), mayYield ) ),
_nscanned() {
if ( op.get() ) {
_op = op;
}
@ -1035,7 +1050,15 @@ doneCheckOrder:
_matcher = best->matcher( _c );
_op = best;
}
BSONObj MultiCursor::idElseNaturalHint( const char *ns ) {
NamespaceDetails *nsd = nsdetails( ns );
if ( !nsd || !nsd->haveIdIndex() ) {
return BSON( "$hint" << BSON( "$natural" << 1 ) );
}
return BSON( "$hint" << nsd->idx( nsd->findIdIndex() ).indexName() );
}
bool indexWorks( const BSONObj &idxPattern, const BSONObj &sampleKey, int direction, int firstSignificantField ) {
BSONObjIterator p( idxPattern );
BSONObjIterator k( sampleKey );
@ -1247,8 +1270,12 @@ doneCheckOrder:
void QueryUtilIndexed::clearIndexesForPatterns( const FieldRangeSetPair &frsp, const BSONObj &order ) {
SimpleMutex::scoped_lock lk(NamespaceDetailsTransient::_qcMutex);
NamespaceDetailsTransient& nsd = NamespaceDetailsTransient::get_inlock( frsp.ns() );
nsd.registerIndexForPattern( frsp._singleKey.pattern( order ), BSONObj(), 0 );
nsd.registerIndexForPattern( frsp._multiKey.pattern( order ), BSONObj(), 0 );
if ( frsp._singleKey.matchPossible() ) {
nsd.registerIndexForPattern( frsp._singleKey.pattern( order ), BSONObj(), 0 );
}
if ( frsp._multiKey.matchPossible() ) {
nsd.registerIndexForPattern( frsp._multiKey.pattern( order ), BSONObj(), 0 );
}
}
pair< BSONObj, long long > QueryUtilIndexed::bestIndexForPatterns( const FieldRangeSetPair &frsp, const BSONObj &order ) {

View File

@ -314,6 +314,7 @@ namespace mongo {
}
void init();
void addHint( IndexDetails &id );
void warnOnCappedIdTableScan() const;
class Runner {
public:
Runner( QueryPlanSet &plans, QueryOp &op );
@ -478,7 +479,7 @@ namespace mongo {
virtual shared_ptr<Cursor> newCursor() const = 0;
};
/** takes ownership of 'op' */
MultiCursor( const char *ns, const BSONObj &pattern, const BSONObj &order, shared_ptr<CursorOp> op = shared_ptr<CursorOp>(), bool mayYield = false );
MultiCursor( const char *ns, const BSONObj &pattern, const BSONObj &order, shared_ptr<CursorOp> op = shared_ptr<CursorOp>(), bool mayYield = false, bool hintIdElseNatural = false );
/**
* Used
* 1. To handoff a query to a getMore()
@ -538,8 +539,11 @@ namespace mongo {
virtual long long nscanned() { assert( false ); return 0; }
};
void nextClause();
static BSONObj idElseNaturalHint( const char *ns );
shared_ptr<CursorOp> _op;
shared_ptr<Cursor> _c;
BSONObj _hint;
BSONElement _hintElt;
auto_ptr<MultiPlanScanner> _mps;
shared_ptr<CoveredIndexMatcher> _matcher;
long long _nscanned;

View File

@ -35,7 +35,9 @@ namespace mongo {
* @param aggregateNscanned - shared int counting total nscanned for
* query ops for all cursors.
*/
QueryOptimizerCursorOp( long long &aggregateNscanned ) : _matchCount(), _mustAdvance(), _nscanned(), _aggregateNscanned( aggregateNscanned ) {}
QueryOptimizerCursorOp( long long &aggregateNscanned ) :
_matchCount(), _mustAdvance(), _nscanned(), _capped(),
_aggregateNscanned( aggregateNscanned ), _yieldRecoveryFailed() {}
virtual void _init() {
if ( qp().scanAndOrderRequired() ) {
@ -64,6 +66,7 @@ namespace mongo {
virtual void recoverFromYield() {
if ( _cc && !ClientCursor::recoverFromYield( _yieldData ) ) {
_yieldRecoveryFailed = true;
_c.reset();
_cc.reset();
@ -113,12 +116,15 @@ namespace mongo {
DiskLoc currLoc() const { return _c ? _c->currLoc() : DiskLoc(); }
BSONObj currKey() const { return _c ? _c->currKey() : BSONObj(); }
virtual bool mayRecordPlan() const {
return complete() && !stopRequested();
return !_yieldRecoveryFailed && complete() && !stopRequested();
}
shared_ptr<Cursor> cursor() const { return _c; }
private:
void mayAdvance() {
if ( _mustAdvance && _c ) {
if ( !_c ) {
return;
}
if ( _mustAdvance ) {
_c->advance();
_mustAdvance = false;
}
@ -134,6 +140,7 @@ namespace mongo {
DiskLoc _posBeforeYield;
ClientCursor::YieldData _yieldData;
long long &_aggregateNscanned;
bool _yieldRecoveryFailed;
};
/**
@ -181,36 +188,7 @@ namespace mongo {
return DiskLoc();
}
virtual bool advance() {
if ( _takeover ) {
return _takeover->advance();
}
// Ok to advance if currOp in an error state due to failed yield recovery.
// This may be the case when advance() is called by recoverFromYield().
if ( !( _currOp && _currOp->error() ) && !ok() ) {
return false;
}
_currOp = 0;
shared_ptr<QueryOp> op = _mps->nextOp();
rethrowOnError( op );
QueryOptimizerCursorOp *qocop = dynamic_cast<QueryOptimizerCursorOp*>( op.get() );
if ( !op->complete() ) {
// 'qocop' will be valid until we call _mps->nextOp() again.
_currOp = qocop;
}
else if ( op->stopRequested() ) {
if ( qocop->cursor() ) {
_takeover.reset( new MultiCursor( _mps,
qocop->cursor(),
op->matcher( qocop->cursor() ),
*op,
_nscanned - qocop->cursor()->nscanned() ) );
}
}
return ok();
return _advance( false );
}
virtual BSONObj currKey() const {
if ( _takeover ) {
@ -252,9 +230,9 @@ namespace mongo {
}
if ( _currOp ) {
_mps->recoverFromYield();
if ( _currOp->error() ) {
// See if we can advance to a non error op.
advance();
if ( _currOp->error() || !ok() ) {
// Advance to a non error op or a following $or clause if possible.
_advance( true );
}
}
}
@ -304,6 +282,36 @@ namespace mongo {
}
private:
bool _advance( bool force ) {
if ( _takeover ) {
return _takeover->advance();
}
if ( !force && !ok() ) {
return false;
}
_currOp = 0;
shared_ptr<QueryOp> op = _mps->nextOp();
rethrowOnError( op );
QueryOptimizerCursorOp *qocop = dynamic_cast<QueryOptimizerCursorOp*>( op.get() );
if ( !op->complete() ) {
// 'qocop' will be valid until we call _mps->nextOp() again.
_currOp = qocop;
}
else if ( op->stopRequested() ) {
if ( qocop->cursor() ) {
_takeover.reset( new MultiCursor( _mps,
qocop->cursor(),
op->matcher( qocop->cursor() ),
*op,
_nscanned - qocop->cursor()->nscanned() ) );
}
}
return ok();
}
void rethrowOnError( const shared_ptr< QueryOp > &op ) {
// If all plans have erred out, assert.
if ( op->error() ) {

View File

@ -36,7 +36,8 @@ namespace mongo {
Equality,
LowerBound,
UpperBound,
UpperAndLowerBound
UpperAndLowerBound,
ConstraintPresent
};
bool operator<( const QueryPattern &other ) const;
/** for testing only */

View File

@ -1007,6 +1007,8 @@ namespace mongo {
qp._fieldTypes[ i->first ] = QueryPattern::UpperBound;
else if ( lower )
qp._fieldTypes[ i->first ] = QueryPattern::LowerBound;
else
qp._fieldTypes[ i->first ] = QueryPattern::ConstraintPresent;
}
}
qp.setSort( sort );
@ -1019,13 +1021,13 @@ namespace mongo {
BoundBuilders builders;
builders.push_back( make_pair( shared_ptr<BSONObjBuilder>( new BSONObjBuilder() ), shared_ptr<BSONObjBuilder>( new BSONObjBuilder() ) ) );
BSONObjIterator i( keyPattern );
bool ineq = false; // until ineq is true, we are just dealing with equality and $in bounds
bool equalityOnly = true; // until equalityOnly is false, we are just dealing with equality (no range or $in querys).
while( i.more() ) {
BSONElement e = i.next();
const FieldRange &fr = range( e.fieldName() );
int number = (int) e.number(); // returns 0.0 if not numeric
bool forward = ( ( number >= 0 ? 1 : -1 ) * ( direction >= 0 ? 1 : -1 ) > 0 );
if ( !ineq ) {
if ( equalityOnly ) {
if ( fr.equality() ) {
for( BoundBuilders::const_iterator j = builders.begin(); j != builders.end(); ++j ) {
j->first->appendAs( fr.min(), "" );
@ -1033,9 +1035,8 @@ namespace mongo {
}
}
else {
if ( !fr.inQuery() ) {
ineq = true;
}
equalityOnly = false;
BoundBuilders newBuilders;
const vector<FieldInterval> &intervals = fr.intervals();
for( BoundBuilders::const_iterator i = builders.begin(); i != builders.end(); ++i ) {

View File

@ -328,7 +328,7 @@ namespace mongo {
bool matchesElement( const BSONElement &e, int i, bool direction ) const;
bool matchesKey( const BSONObj &key ) const;
vector<FieldRange> _ranges;
const IndexSpec &_indexSpec;
IndexSpec _indexSpec;
int _direction;
vector<BSONObj> _queries; // make sure mem owned
friend class FieldRangeVectorIterator;

View File

@ -112,7 +112,8 @@ namespace mongo {
class Rolling {
public:
Rolling() {
Rolling()
: _lock( "ps::Rolling" ){
_curSlice = 0;
_lastRotate = Listener::getElapsedTimeMillis();
}
@ -126,8 +127,8 @@ namespace mongo {
bool access( size_t region , short offset , bool doHalf ) {
int regionHash = hash(region);
scoped_spinlock lk( _lock );
SimpleMutex::scoped_lock lk( _lock );
static int rarely_count = 0;
if ( rarely_count++ % 2048 == 0 ) {
long long now = Listener::getElapsedTimeMillis();
@ -174,7 +175,7 @@ namespace mongo {
long long _lastRotate;
Slice _slices[NumSlices];
SpinLock _lock;
SimpleMutex _lock;
} rolling;
}

View File

@ -508,12 +508,12 @@ namespace mongo {
return;
}
DatabaseIgnorer ___databaseIgnorer;
void DatabaseIgnorer::doIgnoreUntilAfter( const string &db, const OpTime &futureOplogTime ) {
if ( futureOplogTime > _ignores[ db ] ) {
_ignores[ db ] = futureOplogTime;
_ignores[ db ] = futureOplogTime;
}
}
@ -533,28 +533,28 @@ namespace mongo {
bool ReplSource::handleDuplicateDbName( const BSONObj &op, const char *ns, const char *db ) {
if ( dbHolder.isLoaded( ns, dbpath ) ) {
// Database is already present.
return true;
return true;
}
BSONElement ts = op.getField( "ts" );
if ( ( ts.type() == Date || ts.type() == Timestamp ) && ___databaseIgnorer.ignoreAt( db, ts.date() ) ) {
// Database is ignored due to a previous indication that it is
// missing from master after optime "ts".
return false;
return false;
}
if ( Database::duplicateUncasedName( db, dbpath ).empty() ) {
// No duplicate database names are present.
return true;
}
OpTime lastTime;
bool dbOk = false;
{
dbtemprelease release;
// We always log an operation after executing it (never before), so
// a database list will always be valid as of an oplog entry generated
// before it was retrieved.
BSONObj last = oplogReader.findOne( this->ns().c_str(), Query().sort( BSON( "$natural" << -1 ) ) );
if ( !last.isEmpty() ) {
BSONElement ts = last.getField( "ts" );
@ -568,34 +568,34 @@ namespace mongo {
BSONObjIterator i( info.getField( "databases" ).embeddedObject() );
while( i.more() ) {
BSONElement e = i.next();
const char * name = e.embeddedObject().getField( "name" ).valuestr();
if ( strcasecmp( name, db ) != 0 )
continue;
if ( strcmp( name, db ) == 0 ) {
// The db exists on master, still need to check that no conflicts exist there.
dbOk = true;
continue;
}
// The master has a db name that conflicts with the requested name.
dbOk = false;
break;
}
}
if ( !dbOk ) {
___databaseIgnorer.doIgnoreUntilAfter( db, lastTime );
incompleteCloneDbs.erase(db);
addDbNextPass.erase(db);
return false;
return false;
}
// Check for duplicates again, since we released the lock above.
set< string > duplicates;
Database::duplicateUncasedName( db, dbpath, &duplicates );
// The database is present on the master and no conflicting databases
// are present on the master. Drop any local conflicts.
for( set< string >::const_iterator i = duplicates.begin(); i != duplicates.end(); ++i ) {
@ -605,7 +605,7 @@ namespace mongo {
Client::Context ctx(*i);
dropDatabase(*i);
}
massert( 14034, "Duplicate database names present after attempting to delete duplicates",
Database::duplicateUncasedName( db, dbpath ).empty() );
return true;
@ -613,7 +613,11 @@ namespace mongo {
void ReplSource::applyOperation(const BSONObj& op) {
try {
applyOperation_inlock( op );
bool failedUpdate = applyOperation_inlock( op );
if (failedUpdate && shouldRetry(op, hostName)) {
failedUpdate = applyOperation_inlock( op );
uassert(15914, "Failure retrying initial sync update", ! failedUpdate );
}
}
catch ( UserException& e ) {
log() << "sync: caught user assertion " << e << " while applying op: " << op << endl;;
@ -705,9 +709,9 @@ namespace mongo {
}
if ( !handleDuplicateDbName( op, ns, clientName ) ) {
return;
return;
}
Client::Context ctx( ns );
ctx.getClient()->curop()->reset();
@ -943,7 +947,7 @@ namespace mongo {
}
// otherwise, break out of loop so we can set to completed or clone more dbs
}
if( oplogReader.awaitCapable() && tailing )
okResultCode = 0; // don't sleep
syncedTo = nextOpTime;
@ -1077,7 +1081,7 @@ namespace mongo {
BSONObj me;
{
dblock l;
// local.me is an identifier for a server for getLastError w:2+
if ( ! Helpers::getSingleton( "local.me" , me ) ||
@ -1111,7 +1115,7 @@ namespace mongo {
bool OplogReader::commonConnect(const string& hostName) {
if( conn() == 0 ) {
_conn = shared_ptr<DBClientConnection>(new DBClientConnection( false, 0, 0 /* tcp timeout */));
_conn = shared_ptr<DBClientConnection>(new DBClientConnection( false, 0, 60*10 /* tcp timeout */));
string errmsg;
ReplInfo r("trying to connect to sync source");
if ( !_conn->connect(hostName.c_str(), errmsg) ||
@ -1123,7 +1127,7 @@ namespace mongo {
}
return true;
}
bool OplogReader::connect(string hostName) {
if (conn() != 0) {
return true;

View File

@ -122,11 +122,11 @@ namespace mongo {
* @return true iff an op with the specified ns may be applied.
*/
bool handleDuplicateDbName( const BSONObj &op, const char *ns, const char *db );
public:
OplogReader oplogReader;
static void applyOperation(const BSONObj& op);
void applyOperation(const BSONObj& op);
string hostName; // ip addr or hostname plus optionally, ":<port>"
string _sourceName; // a logical source name.
string sourceName() const { return _sourceName.empty() ? "main" : _sourceName; }

View File

@ -47,6 +47,10 @@ namespace mongo {
~ScopedConn() {
// conLock releases...
}
void reconnect() {
conn()->port().shutdown();
connect();
}
/* 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
@ -61,9 +65,6 @@ namespace mongo {
BSONObj findOne(const string &ns, const Query& q, const BSONObj *fieldsToReturn = 0, int queryOptions = 0) {
return conn()->findOne(ns, q, fieldsToReturn, queryOptions);
}
void setTimeout(double to) {
conn()->setSoTimeout(to);
}
private:
auto_ptr<scoped_lock> connLock;
@ -71,42 +72,63 @@ namespace mongo {
struct X {
mongo::mutex z;
DBClientConnection cc;
X() : z("X"), cc(/*reconnect*/ true, 0, /*timeout*/ 10.0) {
bool connected;
X() : z("X"), cc(/*reconnect*/ true, 0, /*timeout*/ 10.0), connected(false) {
cc._logLevel = 2;
}
} *x;
typedef map<string,ScopedConn::X*> M;
static M& _map;
DBClientConnection* conn() { return &x->cc; }
const string _hostport;
// we should already be locked...
bool connect() {
string err;
if (!x->cc.connect(_hostport, err)) {
log() << "couldn't connect to " << _hostport << ": " << err << rsLog;
return false;
}
x->connected = true;
// if we cannot authenticate against a member, then either its key file
// or our key file has to change. if our key file has to change, we'll
// be rebooting. if their file has to change, they'll be rebooted so the
// connection created above will go dead, reconnect, and reauth.
if (!noauth && !x->cc.auth("local", internalSecurity.user, internalSecurity.pwd, err, false)) {
log() << "could not authenticate against " << _hostport << ", " << err << rsLog;
return false;
}
return true;
}
};
inline ScopedConn::ScopedConn(string hostport) {
inline ScopedConn::ScopedConn(string hostport) : _hostport(hostport) {
bool first = false;
{
scoped_lock lk(mapMutex);
x = _map[hostport];
x = _map[_hostport];
if( x == 0 ) {
x = _map[hostport] = new X();
x = _map[_hostport] = new X();
first = true;
connLock.reset( new scoped_lock(x->z) );
}
}
if( !first ) {
connLock.reset( new scoped_lock(x->z) );
// already locked connLock above
if (first) {
connect();
return;
}
// we already locked above...
string err;
if (!x->cc.connect(hostport, err)) {
log() << "couldn't connect to " << hostport << ": " << err << rsLog;
connLock.reset( new scoped_lock(x->z) );
if (x->connected) {
return;
}
if (!noauth && !x->cc.auth("local", internalSecurity.user, internalSecurity.pwd, err, false)) {
log() << "could not authenticate against " << conn()->toString() << ", " << err << rsLog;
return;
}
// Keep trying to connect if we're not yet connected
connect();
}
}

View File

@ -402,6 +402,11 @@ namespace mongo {
string s = m->lhb();
if( !s.empty() )
bb.append("errmsg", s);
if (m->hbinfo().authIssue) {
bb.append("authenticated", false);
}
v.push_back(bb.obj());
m = m->next();
}

View File

@ -51,11 +51,14 @@ namespace mongo {
/* { replSetHeartbeat : <setname> } */
class CmdReplSetHeartbeat : public ReplSetCommand {
public:
virtual bool adminOnly() const { return false; }
CmdReplSetHeartbeat() : ReplSetCommand("replSetHeartbeat") { }
virtual bool run(const string& , BSONObj& cmdObj, int, string& errmsg, BSONObjBuilder& result, bool fromRepl) {
if( replSetBlind )
if( replSetBlind ) {
if (theReplSet) {
errmsg = str::stream() << theReplSet->selfFullName() << " is blind";
}
return false;
}
/* we don't call ReplSetCommand::check() here because heartbeat
checks many things that are pre-initialization. */
@ -99,8 +102,8 @@ namespace mongo {
if( !from.empty() ) {
replSettings.discoveredSeeds.insert(from);
}
errmsg = "still initializing";
return false;
result.append("hbmsg", "still initializing");
return true;
}
if( theReplSet->name() != cmdObj.getStringField("replSetHeartbeat") ) {
@ -123,32 +126,54 @@ namespace mongo {
}
} cmdReplSetHeartbeat;
/* throws dbexception */
bool requestHeartbeat(string setName, string from, string memberFullName, BSONObj& result, int myCfgVersion, int& theirCfgVersion, bool checkEmpty) {
bool requestHeartbeat(string setName, string from, string memberFullName, BSONObj& result,
int myCfgVersion, int& theirCfgVersion, bool checkEmpty) {
if( replSetBlind ) {
//sleepmillis( rand() );
return false;
}
BSONObj cmd = BSON( "replSetHeartbeat" << setName << "v" << myCfgVersion << "pv" << 1 << "checkEmpty" << checkEmpty << "from" << from );
BSONObj cmd = BSON( "replSetHeartbeat" << setName <<
"v" << myCfgVersion <<
"pv" << 1 <<
"checkEmpty" << checkEmpty <<
"from" << from );
// we might be talking to ourself - generally not a great idea to do outbound waiting calls in a write lock
assert( !dbMutex.isWriteLocked() );
// these are slow (multisecond to respond), so generally we don't want to be locked, at least not without
// generally not a great idea to do outbound waiting calls in a
// write lock. heartbeats can be slow (multisecond to respond), so
// generally we don't want to be locked, at least not without
// thinking acarefully about it first.
assert( theReplSet == 0 || !theReplSet->lockedByMe() );
uassert(15900, "can't heartbeat: too much lock",
!dbMutex.isWriteLocked() || theReplSet == 0 || !theReplSet->lockedByMe() );
ScopedConn conn(memberFullName);
return conn.runCommand("admin", cmd, result, 0);
}
/* poll every other set member to check its status */
/**
* Poll every other set member to check its status.
*
* A detail about local machines and authentication: suppose we have 2
* members, A and B, on the same machine using different keyFiles. A is
* primary. If we're just starting the set, there are no admin users, so A
* and B can access each other because it's local access.
*
* Then we add a user to A. B cannot sync this user from A, because as soon
* as we add a an admin user, A requires auth. However, A can still
* heartbeat B, because B *doesn't* have an admin user. So A can reach B
* but B cannot reach A.
*
* Once B is restarted with the correct keyFile, everything should work as
* expected.
*/
class ReplSetHealthPollTask : public task::Task {
private:
HostAndPort h;
HeartbeatInfo m;
int tries;
const int threshold;
public:
ReplSetHealthPollTask(const HostAndPort& hh, const HeartbeatInfo& mm) : h(hh), m(mm) { }
ReplSetHealthPollTask(const HostAndPort& hh, const HeartbeatInfo& mm)
: h(hh), m(mm), tries(0), threshold(15) { }
string name() const { return "rsHealthPoll"; }
void doWork() {
@ -163,16 +188,7 @@ namespace mongo {
BSONObj info;
int theirConfigVersion = -10000;
Timer timer;
bool ok = requestHeartbeat(theReplSet->name(), theReplSet->selfFullName(), h.toString(), info, theReplSet->config().version, theirConfigVersion);
mem.ping = (unsigned int)timer.millis();
time_t before = timer.startTime() / 1000000;
// we set this on any response - we don't get this far if
// couldn't connect because exception is thrown
time_t after = mem.lastHeartbeat = before + (mem.ping / 1000);
bool ok = _requestHeartbeat(mem, info, theirConfigVersion);
// weight new ping with old pings
// on the first ping, just use the ping value
@ -180,68 +196,12 @@ namespace mongo {
mem.ping = (unsigned int)((old.ping * .8) + (mem.ping * .2));
}
if ( info["time"].isNumber() ) {
long long t = info["time"].numberLong();
if( t > after )
mem.skew = (int) (t - after);
else if( t < before )
mem.skew = (int) (t - before); // negative
}
else {
// it won't be there if remote hasn't initialized yet
if( info.hasElement("time") )
warning() << "heatbeat.time isn't a number: " << info << endl;
mem.skew = INT_MIN;
}
{
be state = info["state"];
if( state.ok() )
mem.hbstate = MemberState(state.Int());
}
if( ok ) {
HeartbeatInfo::numPings++;
if( mem.upSince == 0 ) {
log() << "replSet info member " << h.toString() << " is up" << rsLog;
mem.upSince = mem.lastHeartbeat;
}
mem.health = 1.0;
mem.lastHeartbeatMsg = info["hbmsg"].String();
if( info.hasElement("opTime") )
mem.opTime = info["opTime"].Date();
// see if this member is in the electable set
if( info["e"].eoo() ) {
// for backwards compatibility
const Member *member = theReplSet->findById(mem.id());
if (member && member->config().potentiallyHot()) {
theReplSet->addToElectable(mem.id());
}
else {
theReplSet->rmFromElectable(mem.id());
}
}
// add this server to the electable set if it is within 10
// seconds of the latest optime we know of
else if( info["e"].trueValue() &&
mem.opTime >= theReplSet->lastOpTimeWritten.getSecs() - 10) {
unsigned lastOp = theReplSet->lastOtherOpTime().getSecs();
if (lastOp > 0 && mem.opTime >= lastOp - 10) {
theReplSet->addToElectable(mem.id());
}
}
else {
theReplSet->rmFromElectable(mem.id());
}
be cfg = info["config"];
if( cfg.ok() ) {
// received a new config
boost::function<void()> f =
boost::bind(&Manager::msgReceivedNewConfig, theReplSet->mgr, cfg.Obj().copy());
theReplSet->mgr->send(f);
}
up(info, mem);
}
else if (!info["errmsg"].eoo() &&
info["errmsg"].str() == "need to login") {
authIssue(mem);
}
else {
down(mem, info.getStringField("errmsg"));
@ -271,7 +231,58 @@ namespace mongo {
}
private:
bool _requestHeartbeat(HeartbeatInfo& mem, BSONObj& info, int& theirConfigVersion) {
if (tries++ % threshold == (threshold - 1)) {
ScopedConn conn(h.toString());
conn.reconnect();
}
Timer timer;
bool ok = requestHeartbeat(theReplSet->name(), theReplSet->selfFullName(),
h.toString(), info, theReplSet->config().version, theirConfigVersion);
mem.ping = (unsigned int)timer.millis();
time_t before = timer.startTime() / 1000000;
// we set this on any response - we don't get this far if
// couldn't connect because exception is thrown
time_t after = mem.lastHeartbeat = before + (mem.ping / 1000);
if ( info["time"].isNumber() ) {
long long t = info["time"].numberLong();
if( t > after )
mem.skew = (int) (t - after);
else if( t < before )
mem.skew = (int) (t - before); // negative
}
else {
// it won't be there if remote hasn't initialized yet
if( info.hasElement("time") )
warning() << "heatbeat.time isn't a number: " << info << endl;
mem.skew = INT_MIN;
}
{
be state = info["state"];
if( state.ok() )
mem.hbstate = MemberState(state.Int());
}
return ok;
}
void authIssue(HeartbeatInfo& mem) {
mem.authIssue = true;
mem.hbstate = MemberState::RS_UNKNOWN;
// set health to 0 so that this doesn't count towards majority
mem.health = 0.0;
theReplSet->rmFromElectable(mem.id());
}
void down(HeartbeatInfo& mem, string msg) {
mem.authIssue = false;
mem.health = 0.0;
mem.ping = 0;
if( mem.upSince || mem.downSince == 0 ) {
@ -283,6 +294,52 @@ namespace mongo {
mem.lastHeartbeatMsg = msg;
theReplSet->rmFromElectable(mem.id());
}
void up(const BSONObj& info, HeartbeatInfo& mem) {
HeartbeatInfo::numPings++;
mem.authIssue = false;
if( mem.upSince == 0 ) {
log() << "replSet member " << h.toString() << " is up" << rsLog;
mem.upSince = mem.lastHeartbeat;
}
mem.health = 1.0;
mem.lastHeartbeatMsg = info["hbmsg"].String();
if( info.hasElement("opTime") )
mem.opTime = info["opTime"].Date();
// see if this member is in the electable set
if( info["e"].eoo() ) {
// for backwards compatibility
const Member *member = theReplSet->findById(mem.id());
if (member && member->config().potentiallyHot()) {
theReplSet->addToElectable(mem.id());
}
else {
theReplSet->rmFromElectable(mem.id());
}
}
// add this server to the electable set if it is within 10
// seconds of the latest optime we know of
else if( info["e"].trueValue() &&
mem.opTime >= theReplSet->lastOpTimeWritten.getSecs() - 10) {
unsigned lastOp = theReplSet->lastOtherOpTime().getSecs();
if (lastOp > 0 && mem.opTime >= lastOp - 10) {
theReplSet->addToElectable(mem.id());
}
}
else {
theReplSet->rmFromElectable(mem.id());
}
be cfg = info["config"];
if( cfg.ok() ) {
// received a new config
boost::function<void()> f =
boost::bind(&Manager::msgReceivedNewConfig, theReplSet->mgr, cfg.Obj().copy());
theReplSet->mgr->send(f);
}
}
};
void ReplSetImpl::endOldHealthTasks() {

View File

@ -98,8 +98,14 @@ namespace mongo {
const Member *primary = rs->box.getPrimary();
if (primary && highestPriority &&
highestPriority->config().priority > primary->config().priority) {
log() << "stepping down " << primary->fullName() << endl;
highestPriority->config().priority > primary->config().priority &&
// if we're stepping down to allow another member to become primary, we
// better have another member (otherOp), and it should be up-to-date
otherOp != 0 && highestPriority->hbinfo().opTime.getSecs() >= otherOp - 10) {
log() << "stepping down " << primary->fullName() << " (priority " <<
primary->config().priority << "), " << highestPriority->fullName() <<
" is priority " << highestPriority->config().priority << " and " <<
(otherOp - highestPriority->hbinfo().opTime.getSecs()) << " seconds behind" << endl;
if (primary->h().isSelf()) {
// replSetStepDown tries to acquire the same lock
@ -119,6 +125,39 @@ namespace mongo {
}
}
void Manager::checkAuth() {
int down = 0, authIssue = 0, total = 0;
for( Member *m = rs->head(); m; m=m->next() ) {
total++;
// all authIssue servers will also be not up
if (!m->hbinfo().up()) {
down++;
if (m->hbinfo().authIssue) {
authIssue++;
}
}
}
// if all nodes are down or failed auth AND at least one failed
// auth, go into recovering. If all nodes are down, stay a
// secondary.
if (authIssue > 0 && down == total) {
log() << "replset error could not reach/authenticate against any members" << endl;
if (rs->box.getPrimary() == rs->_self) {
log() << "auth problems, relinquishing primary" << rsLog;
rs->relinquish();
}
rs->blockSync(true);
}
else {
rs->blockSync(false);
}
}
/** called as the health threads get new results */
void Manager::msgCheckNewState() {
{
@ -130,7 +169,8 @@ namespace mongo {
if( busyWithElectSelf ) return;
checkElectableSet();
checkAuth();
const Member *p = rs->box.getPrimary();
if( p && p != rs->_self ) {
if( !p->hbinfo().up() ||

View File

@ -100,24 +100,25 @@ namespace mongo {
lock lk(this);
Member *max = 0;
for (set<unsigned>::iterator it = _electableSet.begin(); it != _electableSet.end(); it++) {
set<unsigned>::iterator it = _electableSet.begin();
while ( it != _electableSet.end() ) {
const Member *temp = findById(*it);
if (!temp) {
log() << "couldn't find member: " << *it << endl;
_electableSet.erase(*it);
set<unsigned>::iterator it_delete = it;
it++;
_electableSet.erase(it_delete);
continue;
}
if (!max || max->config().priority < temp->config().priority) {
max = (Member*)temp;
}
it++;
}
return max;
}
const bool closeOnRelinquish = true;
void ReplSetImpl::relinquish() {
LOG(2) << "replSet attempting to relinquish" << endl;
if( box.getState().primary() ) {
@ -126,9 +127,7 @@ namespace mongo {
log() << "replSet relinquishing primary state" << rsLog;
changeState(MemberState::RS_SECONDARY);
}
if( closeOnRelinquish ) {
/* close sockets that were talking to us so they don't blithly send many writes that will fail
with "not master" (of course client could check result code, but in case they are not)
*/
@ -329,6 +328,7 @@ namespace mongo {
ReplSetImpl::ReplSetImpl(ReplSetCmdline& replSetCmdline) : elect(this),
_currentSyncTarget(0),
_blockSync(false),
_hbmsgTime(0),
_self(0),
_maintenanceMode(0),

View File

@ -93,6 +93,7 @@ namespace mongo {
void noteARemoteIsPrimary(const Member *);
void checkElectableSet();
void checkAuth();
virtual void starting();
public:
Manager(ReplSetImpl *rs);
@ -348,6 +349,9 @@ namespace mongo {
const Member* getMemberToSyncTo();
Member* _currentSyncTarget;
bool _blockSync;
void blockSync(bool block);
// set of electable members' _ids
set<unsigned> _electableSet;
protected:
@ -491,7 +495,7 @@ namespace mongo {
void _syncThread();
bool tryToGoLiveAsASecondary(OpTime&); // readlocks
void syncTail();
void syncApply(const BSONObj &o);
bool syncApply(const BSONObj &o);
unsigned _syncRollback(OplogReader& r);
void syncRollback(OplogReader& r);
void syncFixUp(HowToFixUp& h, OplogReader& r);
@ -577,7 +581,7 @@ namespace mongo {
* that still need to be checked for auth.
*/
bool checkAuth(string& errmsg, BSONObjBuilder& result) {
if( !noauth && adminOnly() ) {
if( !noauth ) {
AuthenticationInfo *ai = cc().getAuthenticationInfo();
if (!ai->isAuthorizedForLock("admin", locktype())) {
errmsg = "replSet command unauthorized";

View File

@ -296,6 +296,26 @@ namespace mongo {
_ok = false;
}
void ReplSetConfig::setMajority() {
int total = members.size();
int nonArbiters = total;
int strictMajority = total/2+1;
for (vector<MemberCfg>::iterator it = members.begin(); it < members.end(); it++) {
if ((*it).arbiterOnly) {
nonArbiters--;
}
}
// majority should be all "normal" members if we have something like 4
// arbiters & 3 normal members
_majority = (strictMajority > nonArbiters) ? nonArbiters : strictMajority;
}
int ReplSetConfig::getMajority() const {
return _majority;
}
void ReplSetConfig::checkRsConfig() const {
uassert(13132,
"nonmatching repl set name in _id field; check --replSet command line",
@ -533,6 +553,9 @@ namespace mongo {
try { getLastErrorDefaults = settings["getLastErrorDefaults"].Obj().copy(); }
catch(...) { }
}
// figure out the majority for this config
setMajority();
}
static inline void configAssert(bool expr) {

View File

@ -80,6 +80,22 @@ namespace mongo {
}
}
bool operator==(const MemberCfg& r) const {
if (!tags.empty() || !r.tags.empty()) {
if (tags.size() != r.tags.size()) {
return false;
}
// if they are the same size and not equal, at least one
// element in A must be different in B
for (map<string,string>::const_iterator lit = tags.begin(); lit != tags.end(); lit++) {
map<string,string>::const_iterator rit = r.tags.find((*lit).first);
if (rit == r.tags.end() || (*lit).second != (*rit).second) {
return false;
}
}
}
return _id==r._id && votes == r.votes && h == r.h && priority == r.priority &&
arbiterOnly == r.arbiterOnly && slaveDelay == r.slaveDelay && hidden == r.hidden &&
buildIndexes == buildIndexes;
@ -119,9 +135,20 @@ namespace mongo {
BSONObj asBson() const;
/**
* Getter and setter for _majority. This is almost always
* members.size()/2+1, but can be the number of non-arbiter members if
* there are more arbiters than non-arbiters (writing to 3 out of 7
* servers is safe if 4 of the servers are arbiters).
*/
void setMajority();
int getMajority() const;
bool _constructed;
private:
bool _ok;
int _majority;
void from(BSONObj);
void clear();

View File

@ -43,18 +43,24 @@ namespace mongo {
}
void ReplSetImpl::syncDoInitialSync() {
const static int maxFailedAttempts = 3;
createOplog();
while( 1 ) {
int failedAttempts = 0;
while ( failedAttempts < maxFailedAttempts ) {
try {
_syncDoInitialSync();
break;
}
catch(DBException& e) {
sethbmsg("initial sync exception " + e.toString(), 0);
failedAttempts++;
str::stream msg;
msg << "initial sync exception: ";
msg << e.toString() << " " << (maxFailedAttempts - failedAttempts) << " attempts remaining" ;
sethbmsg(msg, 0);
sleepsecs(30);
}
}
if ( failedAttempts >= maxFailedAttempts ) ::abort();
}
/* todo : progress metering to sethbmsg. */
@ -80,7 +86,8 @@ namespace mongo {
}
const Member* ReplSetImpl::getMemberToSyncTo() {
Member *closest = 0;
bool buildIndexes = true;
// wait for 2N pings before choosing a sync target
if (_cfg) {
@ -90,16 +97,35 @@ namespace mongo {
OCCASIONALLY log() << "waiting for " << needMorePings << " pings from other members before syncing" << endl;
return NULL;
}
buildIndexes = myConfig().buildIndexes;
}
Member *closest = 0;
// find the member with the lowest ping time that has more data than me
for (Member *m = _members.head(); m; m = m->next()) {
if (m->hbinfo().up() &&
(m->state() == MemberState::RS_PRIMARY ||
(m->state() == MemberState::RS_SECONDARY && m->hbinfo().opTime > lastOpTimeWritten)) &&
(!closest || m->hbinfo().ping < closest->hbinfo().ping)) {
closest = m;
// Make two attempts. The first attempt, we ignore those nodes with
// slave delay higher than our own. The second attempt includes such
// nodes, in case those are the only ones we can reach.
for (int attempts = 0; attempts < 2; ++attempts) {
for (Member *m = _members.head(); m; m = m->next()) {
if (m->hbinfo().up() &&
// make sure members with buildIndexes sync from other members w/indexes
(!buildIndexes || (buildIndexes && m->config().buildIndexes)) &&
(m->state() == MemberState::RS_PRIMARY ||
(m->state() == MemberState::RS_SECONDARY &&
m->hbinfo().opTime > lastOpTimeWritten)) &&
(!closest || m->hbinfo().ping < closest->hbinfo().ping)) {
if ( attempts == 0 &&
myConfig().slaveDelay < m->config().slaveDelay ) {
break; // skip this one in the first attempt
}
closest = m;
}
}
if (closest) break; // no need for second attempt
}
{

View File

@ -69,7 +69,8 @@ namespace mongo {
class HeartbeatInfo {
unsigned _id;
public:
HeartbeatInfo() : _id(0xffffffff),hbstate(MemberState::RS_UNKNOWN),health(-1.0),downSince(0),skew(INT_MIN) { }
HeartbeatInfo() : _id(0xffffffff), hbstate(MemberState::RS_UNKNOWN), health(-1.0),
downSince(0), skew(INT_MIN), authIssue(false) { }
HeartbeatInfo(unsigned id);
unsigned id() const { return _id; }
MemberState hbstate;
@ -80,6 +81,7 @@ namespace mongo {
DiagStr lastHeartbeatMsg;
OpTime opTime;
int skew;
bool authIssue;
unsigned int ping; // milliseconds
static unsigned int numPings;
@ -94,7 +96,7 @@ namespace mongo {
bool changed(const HeartbeatInfo& old) const;
};
inline HeartbeatInfo::HeartbeatInfo(unsigned id) : _id(id) {
inline HeartbeatInfo::HeartbeatInfo(unsigned id) : _id(id), authIssue(false) {
hbstate = MemberState::RS_UNKNOWN;
health = -1.0;
downSince = 0;

View File

@ -388,24 +388,18 @@ namespace mongo {
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);
try {
Client::Context c(ns);
{
bob res;
string errmsg;
dropCollection(ns, errmsg, res);
{
dbtemprelease r;
bool ok = copyCollectionFromRemote(them->getServerAddress(), ns, bo(), errmsg, false, true, false);
if( !ok ) {
log() << "replSet rollback error resyncing collection " << ns << ' ' << errmsg << rsLog;
throw "rollback error resyncing rollection [1]";
}
bool ok = copyCollectionFromRemote(them->getServerAddress(), ns, errmsg);
uassert(15909, str::stream() << "replSet rollback error resyncing collection " << ns << ' ' << errmsg, ok);
}
}
catch(...) {
log() << "replset rollback error resyncing collection " << ns << rsLog;
throw "rollback error resyncing rollection [2]";
}
}
/* we did more reading from primary, so check it again for a rollback (which would mess us up), and
@ -423,7 +417,7 @@ namespace mongo {
setMinValid(newMinValid);
}
}
catch(...) {
catch (DBException& e) {
err = "can't get/set minvalid";
}
if( h.rbid != getRBID(r.conn()) ) {

View File

@ -32,17 +32,19 @@ namespace mongo {
}
}
/* apply the log op that is in param o */
void ReplSetImpl::syncApply(const BSONObj &o) {
/* apply the log op that is in param o
@return bool failedUpdate
*/
bool ReplSetImpl::syncApply(const BSONObj &o) {
const char *ns = o.getStringField("ns");
if ( *ns == '.' || *ns == 0 ) {
blank(o);
return;
return false;
}
Client::Context ctx(ns);
ctx.getClient()->curop()->reset();
applyOperation_inlock(o);
return applyOperation_inlock(o);
}
/* initial oplog application, during initial sync, after cloning.
@ -57,6 +59,7 @@ namespace mongo {
const string hn = source->h().toString();
OplogReader r;
try {
if( !r.connect(hn) ) {
log() << "replSet initial sync error can't connect to " << hn << " to read " << rsoplog << rsLog;
@ -113,12 +116,9 @@ namespace mongo {
if( !r.more() )
break;
BSONObj o = r.nextSafe(); /* note we might get "not master" at some point */
{
ts = o["ts"]._opTime();
ts = o["ts"]._opTime();
/* if we have become primary, we dont' want to apply things from elsewhere
anymore. assumePrimary is in the db lock so we are safe as long as
we check after we locked above. */
{
if( (source->state() != MemberState::RS_PRIMARY &&
source->state() != MemberState::RS_SECONDARY) ||
replSetForceInitialSyncFailure ) {
@ -133,9 +133,12 @@ namespace mongo {
throw DBException("primary changed",0);
}
if( ts >= applyGTE ) {
// optimes before we started copying need not be applied.
syncApply(o);
if( ts >= applyGTE ) { // optimes before we started copying need not be applied.
bool failedUpdate = syncApply(o);
if( failedUpdate && shouldRetry(o, hn)) {
failedUpdate = syncApply(o);
uassert(15915, "replSet update still fails after adding missing object", !failedUpdate);
}
}
_logOpObjRS(o); /* with repl sets we write the ops to our oplog too */
}
@ -149,15 +152,19 @@ namespace mongo {
start = now;
}
}
if ( ts > minValid ) {
break;
}
getDur().commitIfNeeded();
}
catch (DBException& e) {
// skip duplicate key exceptions
if( e.getCode() == 11000 || e.getCode() == 11001 ) {
if( e.getCode() == 11000 || e.getCode() == 11001 || e.getCode() == 12582) {
continue;
}
// handle cursor not found (just requery)
if( e.getCode() == 13127 ) {
r.resetCursor();
@ -290,7 +297,7 @@ namespace mongo {
target = 0;
}
}
// no server found
if (target == 0) {
// if there is no one to sync from
@ -298,7 +305,7 @@ namespace mongo {
tryToGoLiveAsASecondary(minvalid);
return;
}
r.tailingQueryGTE(rsoplog, lastOpTimeWritten);
// if target cut connections between connecting and querying (for
// example, because it stepped down) we might not have a cursor
@ -408,7 +415,7 @@ namespace mongo {
if( !target->hbinfo().hbstate.readable() ) {
break;
}
if( myConfig().slaveDelay != sd ) // reconf
break;
}
@ -429,7 +436,7 @@ namespace mongo {
}
syncApply(o);
_logOpObjRS(o); // with repl sets we write the ops to our oplog too
_logOpObjRS(o); // with repl sets we write the ops to our oplog too
}
catch (DBException& e) {
sethbmsg(str::stream() << "syncTail: " << e.toString() << ", syncing: " << o);
@ -444,7 +451,7 @@ namespace mongo {
// TODO : reuse our connection to the primary.
return;
}
if( !target->hbinfo().hbstate.readable() ) {
return;
}
@ -458,7 +465,7 @@ namespace mongo {
sleepsecs(1);
return;
}
if( sp.state.fatal() || sp.state.startup() ) {
if( _blockSync || sp.state.fatal() || sp.state.startup() ) {
sleepsecs(5);
return;
}
@ -530,6 +537,15 @@ namespace mongo {
replLocalAuth();
}
void ReplSetImpl::blockSync(bool block) {
_blockSync = block;
if (_blockSync) {
// syncing is how we get into SECONDARY state, so we'll be stuck in
// RECOVERING until we unblock
changeState(MemberState::RS_RECOVERING);
}
}
void GhostSync::associateSlave(const BSONObj& id, const int memberId) {
const OID rid = id["_id"].OID();
rwlock lk( _lock , true );
@ -556,10 +572,10 @@ namespace mongo {
OCCASIONALLY warning() << "couldn't update slave " << rid << " no entry" << rsLog;
return;
}
GhostSlave& slave = i->second;
if (!slave.init) {
OCCASIONALLY log() << "couldn't update slave " << rid << " not init" << rsLog;
OCCASIONALLY log() << "couldn't update slave " << rid << " not init" << rsLog;
return;
}

View File

@ -175,7 +175,7 @@ namespace mongo {
if (wStr == "majority") {
// use the entire set, including arbiters, to prevent writing
// to a majority of the set but not a majority of voters
return replicatedToNum(op, theReplSet->config().members.size()/2+1);
return replicatedToNum(op, theReplSet->config().getMajority());
}
map<string,ReplSetConfig::TagRule*>::const_iterator it = theReplSet->config().rules.find(wStr);

View File

@ -83,6 +83,9 @@ namespace mongo {
string systemUsers = dbname + ".system.users";
// OCCASIONALLY Helpers::ensureIndex(systemUsers.c_str(), userPattern, false, "user_1");
{
mongolock lk(false);
Client::Context c(systemUsers, dbpath, &lk, false);
BSONObjBuilder b;
b << "user" << user;
BSONObj query = b.done();
@ -101,10 +104,10 @@ namespace mongo {
AuthenticationInfo *ai = cc().getAuthenticationInfo();
if ( readOnly ) {
ai->authorizeReadOnly( cc().database()->name.c_str() , user );
ai->authorizeReadOnly( dbname.c_str() , user );
}
else {
ai->authorize( cc().database()->name.c_str() , user );
ai->authorize( dbname.c_str() , user );
}
}

View File

@ -57,14 +57,16 @@ namespace mongo {
virtual bool slaveOk() const {
return true;
}
virtual LockType locktype() const { return READ; }
virtual LockType locktype() const { return NONE; }
virtual void help(stringstream& ss) const { ss << "internal"; }
CmdAuthenticate() : Command("authenticate") {}
bool run(const string& dbname , BSONObj& cmdObj, int options, string& errmsg, BSONObjBuilder& result, bool fromRepl);
void authenticate(const string& dbname, const string& user, const bool readOnly);
private:
bool getUserObj(const string& dbname, const string& user, BSONObj& userObj, string& pwd);
void authenticate(const string& dbname, const string& user, const bool readOnly);
};
extern CmdAuthenticate cmdAuthenticate;
class CmdLogout : public Command {
public:

View File

@ -22,26 +22,16 @@
# error malloc defined 0
#endif
#ifdef assert
# error assert defined 1
#endif
#include "../client/parallel.h" //uses assert
#ifdef assert
# error assert defined 2
#endif
#include "../client/redef_macros.h"
#ifndef assert
# error assert not defined 3
#ifndef malloc
# error malloc not defined
#endif
#include "../client/undef_macros.h"
#ifdef assert
# error assert defined 3
#ifdef malloc
# error malloc defined 1
#endif

View File

@ -38,7 +38,7 @@ namespace mongo {
runQuery( m, q, response );
}
void __forceLinkGeoPlugin();
shared_ptr<Cursor> newQueryOptimizerCursor( const char *ns, const BSONObj &query, const BSONObj &order = BSONObj() );
boost::shared_ptr<Cursor> newQueryOptimizerCursor( const char *ns, const BSONObj &query, const BSONObj &order = BSONObj() );
} // namespace mongo
namespace QueryOptimizerTests {
@ -51,8 +51,6 @@ namespace QueryOptimizerTests {
namespace QueryPlanTests {
using boost::shared_ptr;
class Base {
public:
Base() : _ctx( ns() ) , indexNum_( 0 ) {
@ -935,9 +933,11 @@ namespace QueryOptimizerTests {
protected:
static const char *ns() { return "unittests.QueryOptimizerTests"; }
static NamespaceDetails *nsd() { return nsdetails( ns() ); }
DBDirectClient &client() { return _client; }
private:
dblock lk_;
Client::Context _ctx;
DBDirectClient _client;
};
class BestGuess : public Base {
@ -969,10 +969,81 @@ namespace QueryOptimizerTests {
}
};
namespace MultiCursorTests {
/**
* Helper class for validating a set of attempted candidate plans The boiler plate
* implementation is similar to MultiCursor::NoOp.
*/
class PlanValidatingCursorOp : public MultiCursor::CursorOp {
public:
PlanValidatingCursorOp( const BSONObj &expectedIndexKey ) :
_expectedIndexKey( expectedIndexKey ) {
}
virtual void _init() {
ASSERT_EQUALS( _expectedIndexKey, qp().indexKey() );
}
virtual void next() { setComplete(); }
virtual bool mayRecordPlan() const { return false; }
virtual QueryOp *_createChild() const {
return new PlanValidatingCursorOp( _expectedIndexKey );
}
virtual boost::shared_ptr<Cursor> newCursor() const { return qp().newCursor(); }
virtual long long nscanned() { return 0; }
private:
BSONObj _expectedIndexKey;
};
/** Test MultiCursor with hintIdElseNatural set to true. */
class HintIdElseNaturalBase : public Base {
public:
virtual ~HintIdElseNaturalBase() {}
void run() {
client().insert( ns(), BSON( "a" << 1 << "b" << 1 ) );
client().insert( ns(), BSON( "a" << 1 << "b" << 1 ) );
client().ensureIndex( ns(), BSON( "a" << 1 ) );
// Create a MultiCursor and validate its plans in the planValidator.
boost::shared_ptr<MultiCursor::CursorOp> planValidator
( new PlanValidatingCursorOp( expectedPlanIndexKey() ) );
MultiCursor cursor( ns(), BSON( "a" << 1 << "b" << 1 ), BSONObj(), planValidator,
false, /* hintIdElseNatural */ true );
// Validate the index key returned by the cursor iterates.
do {
ASSERT_EQUALS( expectedCursorIndexKey(), cursor.indexKeyPattern() );
} while( cursor.advance() );
}
protected:
virtual BSONObj expectedPlanIndexKey() const = 0;
virtual BSONObj expectedCursorIndexKey() const { return expectedPlanIndexKey(); }
};
/** An _id hint is used when possible if hintIdElseNatural is specified. */
class IdHint : public HintIdElseNaturalBase {
virtual BSONObj expectedPlanIndexKey() const { return BSON( "_id" << 1 ); }
};
/**
* An $natural hint is used when hintIdElseNatural is specified and no _id index is
* available.
*/
class NaturalHintFallback : public HintIdElseNaturalBase {
public:
NaturalHintFallback() {
client().dropCollection( ns() );
// Recreate the collection as capped, without an _id index.
client().createCollection( ns(), 5000, true );
}
private:
virtual BSONObj expectedPlanIndexKey() const { return BSON( "$natural" << 1 ); }
virtual BSONObj expectedCursorIndexKey() const { return BSONObj(); }
};
} // namespace MultiCursorTests
namespace QueryOptimizerCursorTests {
using boost::shared_ptr;
class Base {
public:
Base() {
@ -1019,10 +1090,10 @@ namespace QueryOptimizerTests {
advance();
}
}
shared_ptr<Cursor> c() { return _c; }
boost::shared_ptr<Cursor> c() { return _c; }
long long nscanned() const { return _c->nscanned(); }
private:
shared_ptr<Cursor> _c;
boost::shared_ptr<Cursor> _c;
};
/** No results for empty collection. */
@ -1031,7 +1102,7 @@ namespace QueryOptimizerTests {
void run() {
dblock lk;
Client::Context ctx( ns() );
shared_ptr<Cursor> c = newQueryOptimizerCursor( ns(), BSONObj() );
boost::shared_ptr<Cursor> c = newQueryOptimizerCursor( ns(), BSONObj() );
ASSERT( !c->ok() );
ASSERT_EXCEPTION( c->_current(), AssertionException );
ASSERT_EXCEPTION( c->current(), AssertionException );
@ -1371,7 +1442,7 @@ namespace QueryOptimizerTests {
dblock lk;
Client::Context ctx( ns() );
shared_ptr< Cursor > c = newQueryOptimizerCursor( ns(), BSON( "_id" << GT << 5 << "a" << GT << 5 ) );
boost::shared_ptr< Cursor > c = newQueryOptimizerCursor( ns(), BSON( "_id" << GT << 5 << "a" << GT << 5 ) );
ASSERT( c->ok() );
// _id 10 {_id:1}
@ -1464,7 +1535,7 @@ namespace QueryOptimizerTests {
dblock lk;
Client::Context ctx( ns() );
shared_ptr< Cursor > c = newQueryOptimizerCursor( ns(), fromjson( "{_id:/a/}" ) );
boost::shared_ptr< Cursor > c = newQueryOptimizerCursor( ns(), fromjson( "{_id:/a/}" ) );
ASSERT( c->ok() );
// "a"
ASSERT( c->matcher()->matchesCurrent( c.get() ) );
@ -1496,7 +1567,7 @@ namespace QueryOptimizerTests {
dblock lk;
Client::Context ctx( ns() );
shared_ptr< Cursor > c = newQueryOptimizerCursor( ns(), BSON( "$or" << BSON_ARRAY( BSON( "_id" << LT << 300 ) << BSON( "a" << 1 ) ) ) );
boost::shared_ptr< Cursor > c = newQueryOptimizerCursor( ns(), BSON( "$or" << BSON_ARRAY( BSON( "_id" << LT << 300 ) << BSON( "a" << 1 ) ) ) );
for( int i = 0; i < 151; ++i ) {
ASSERT( c->ok() );
ASSERT( c->matcher()->matchesCurrent( c.get() ) );
@ -1516,7 +1587,7 @@ namespace QueryOptimizerTests {
dblock lk;
Client::Context ctx( ns() );
shared_ptr< Cursor > c = newQueryOptimizerCursor( ns(), BSON( "a" << GT << 1 << LT << 5 ) );
boost::shared_ptr< Cursor > c = newQueryOptimizerCursor( ns(), BSON( "a" << GT << 1 << LT << 5 ) );
// Two sided bounds work.
ASSERT( !c->ok() );
}
@ -1551,7 +1622,7 @@ namespace QueryOptimizerTests {
dblock lk;
Client::Context ctx( ns() );
shared_ptr<Cursor> c = newQueryOptimizerCursor( ns(), BSON( "a" << 0 << "b" << 0 ) );
boost::shared_ptr<Cursor> c = newQueryOptimizerCursor( ns(), BSON( "a" << 0 << "b" << 0 ) );
ASSERT_EQUALS( BSON( "_id" << 0 << "a" << 0 << "b" << 0 ), c->current() );
ASSERT( c->advance() );
@ -1583,7 +1654,7 @@ namespace QueryOptimizerTests {
dblock lk;
Client::Context ctx( ns() );
shared_ptr<Cursor> c = newQueryOptimizerCursor( ns(), BSON( "$or" << BSON_ARRAY( BSON( "_id" << GT << 0 ) << BSON( "_id" << 1 ) ) ) );
boost::shared_ptr<Cursor> c = newQueryOptimizerCursor( ns(), BSON( "$or" << BSON_ARRAY( BSON( "_id" << GT << 0 ) << BSON( "_id" << 1 ) ) ) );
ASSERT( c->ok() );
ASSERT( !c->advance() );
}
@ -1600,7 +1671,7 @@ namespace QueryOptimizerTests {
dblock lk;
Client::Context ctx( ns() );
shared_ptr<Cursor> c = newQueryOptimizerCursor( ns(), BSON( "$or" << BSON_ARRAY( BSON( "_id" << LT << 140 ) << BSON( "_id" << 145 ) << BSON( "a" << 145 ) ) ) );
boost::shared_ptr<Cursor> c = newQueryOptimizerCursor( ns(), BSON( "$or" << BSON_ARRAY( BSON( "_id" << LT << 140 ) << BSON( "_id" << 145 ) << BSON( "a" << 145 ) ) ) );
while( c->current().getIntField( "_id" ) < 140 ) {
ASSERT( c->advance() );
@ -1644,7 +1715,7 @@ namespace QueryOptimizerTests {
dblock lk;
Client::Context ctx( ns() );
shared_ptr<Cursor> c = newQueryOptimizerCursor( ns(), BSON( "$or" << BSON_ARRAY( BSON( "_id" << LTE << 147 ) << BSON( "_id" << 148 ) << BSON( "_id" << 149 ) ) ) );
boost::shared_ptr<Cursor> c = newQueryOptimizerCursor( ns(), BSON( "$or" << BSON_ARRAY( BSON( "_id" << LTE << 147 ) << BSON( "_id" << 148 ) << BSON( "_id" << 149 ) ) ) );
for( int i = 0; i < 150; ++i ) {
ASSERT( c->ok() );
ASSERT_EQUALS( i, c->current().getIntField( "_id" ) );
@ -1664,7 +1735,7 @@ namespace QueryOptimizerTests {
dblock lk;
Client::Context ctx( ns() );
shared_ptr<Cursor> c = newQueryOptimizerCursor( ns(), BSON( "$or" << BSON_ARRAY( BSON( "a" << LT << 6 << "b" << 4 ) << BSON( "a" << GTE << 6 << "b" << 4 ) ) ) );
boost::shared_ptr<Cursor> c = newQueryOptimizerCursor( ns(), BSON( "$or" << BSON_ARRAY( BSON( "a" << LT << 6 << "b" << 4 ) << BSON( "a" << GTE << 6 << "b" << 4 ) ) ) );
ASSERT( c->ok() );
@ -1921,6 +1992,33 @@ namespace QueryOptimizerTests {
}
};
/** Yield and remove document with $or query. */
class YieldRemoveOr : public Base {
public:
void run() {
_cli.insert( ns(), BSON( "_id" << 1 ) );
_cli.insert( ns(), BSON( "_id" << 2 ) );
{
dblock lk;
Client::Context ctx( ns() );
setQueryOptimizerCursor( BSON( "$or" << BSON_ARRAY( BSON( "_id" << 1 ) << BSON( "_id" << 2 ) ) ) );
ASSERT_EQUALS( 1, current().getIntField( "_id" ) );
ASSERT( prepareToYield() );
}
_cli.remove( ns(), BSON( "_id" << 1 ) );
{
dblock lk;
Client::Context ctx( ns() );
recoverFromYield();
ASSERT( ok() );
ASSERT_EQUALS( 2, current().getIntField( "_id" ) );
}
}
};
/** Yield and overwrite current in capped collection. */
class YieldCappedOverwrite : public Base {
public:
@ -2074,6 +2172,68 @@ namespace QueryOptimizerTests {
}
};
/** Yielding with delete, multiple plans active, and $or clause. */
class YieldMultiplePlansDeleteOr : public Base {
public:
void run() {
_cli.insert( ns(), BSON( "_id" << 1 << "a" << 2 ) );
_cli.insert( ns(), BSON( "_id" << 2 << "a" << 1 ) );
_cli.ensureIndex( ns(), BSON( "a" << 1 ) );
{
dblock lk;
Client::Context ctx( ns() );
setQueryOptimizerCursor( BSON( "$or" << BSON_ARRAY( BSON( "_id" << 1 << "a" << 2 ) << BSON( "_id" << 2 << "a" << 1 ) ) ) );
ASSERT_EQUALS( 1, current().getIntField( "_id" ) );
ASSERT( prepareToYield() );
}
_cli.remove( ns(), BSON( "_id" << 1 ) );
{
dblock lk;
Client::Context ctx( ns() );
c()->recoverFromYield();
ASSERT( ok() );
ASSERT_EQUALS( 2, current().getIntField( "_id" ) );
ASSERT( !advance() );
ASSERT( !ok() );
}
}
};
/** Yielding with delete, multiple plans active with advancement to the second, and $or clause. */
class YieldMultiplePlansDeleteOrAdvance : public Base {
public:
void run() {
_cli.insert( ns(), BSON( "_id" << 1 << "a" << 2 ) );
_cli.insert( ns(), BSON( "_id" << 2 << "a" << 1 ) );
_cli.ensureIndex( ns(), BSON( "a" << 1 ) );
{
dblock lk;
Client::Context ctx( ns() );
setQueryOptimizerCursor( BSON( "$or" << BSON_ARRAY( BSON( "_id" << 1 << "a" << 2 ) << BSON( "_id" << 2 << "a" << 1 ) ) ) );
ASSERT_EQUALS( 1, current().getIntField( "_id" ) );
ASSERT( prepareToYield() );
c()->advance();
ASSERT_EQUALS( 1, current().getIntField( "_id" ) );
}
_cli.remove( ns(), BSON( "_id" << 1 ) );
{
dblock lk;
Client::Context ctx( ns() );
c()->recoverFromYield();
ASSERT( ok() );
ASSERT_EQUALS( 2, current().getIntField( "_id" ) );
ASSERT( !advance() );
ASSERT( !ok() );
}
}
};
/** Yielding with multiple plans and capped overwrite. */
class YieldMultiplePlansCappedOverwrite : public Base {
public:
@ -2118,7 +2278,7 @@ namespace QueryOptimizerTests {
_cli.insert( ns(), BSON( "a" << 1 << "b" << 1 ) );
_cli.ensureIndex( ns(), BSON( "a" << 1 ) );
shared_ptr<Cursor> c;
boost::shared_ptr<Cursor> c;
{
dblock lk;
Client::Context ctx( ns() );
@ -2159,7 +2319,7 @@ namespace QueryOptimizerTests {
_cli.insert( ns(), BSON( "_id" << 1 << "a" << 1 ) );
_cli.ensureIndex( ns(), BSON( "_id" << 1 ) );
shared_ptr<Cursor> c;
boost::shared_ptr<Cursor> c;
{
dblock lk;
Client::Context ctx( ns() );
@ -2429,7 +2589,7 @@ namespace QueryOptimizerTests {
dblock lk;
Client::Context ctx( ns() );
shared_ptr<Cursor> c = newQueryOptimizerCursor( ns(), BSON( "a" << 2 ), BSON( "b" << 1 ) );
boost::shared_ptr<Cursor> c = newQueryOptimizerCursor( ns(), BSON( "a" << 2 ), BSON( "b" << 1 ) );
// Check that we are scanning {b:1} not {a:1}.
for( int i = 0; i < 3; ++i ) {
ASSERT( c->ok() );
@ -2466,7 +2626,7 @@ namespace QueryOptimizerTests {
mongolock lk( false );
Client::Context ctx( ns() );
shared_ptr<Cursor> c = newQueryOptimizerCursor( ns(), BSON( "$or" << BSON_ARRAY( BSON( "_id" << GT << 0 ) << BSON( "b" << GT << 0 ) ) ) );
boost::shared_ptr<Cursor> c = newQueryOptimizerCursor( ns(), BSON( "$or" << BSON_ARRAY( BSON( "_id" << GT << 0 ) << BSON( "b" << GT << 0 ) ) ) );
ASSERT( c->ok() );
cc().curop()->kill();
// First advance() call throws, subsequent calls just fail.
@ -2484,7 +2644,7 @@ namespace QueryOptimizerTests {
dblock lk;
Client::Context ctx( ns() );
shared_ptr<Cursor> c = newQueryOptimizerCursor( ns(), BSON( "_id" << GTE << 0 << "a" << GTE << 0 ) );
boost::shared_ptr<Cursor> c = newQueryOptimizerCursor( ns(), BSON( "_id" << GTE << 0 << "a" << GTE << 0 ) );
ASSERT( c->ok() );
ASSERT_EQUALS( 2, c->nscanned() );
c->advance();
@ -2511,7 +2671,7 @@ namespace QueryOptimizerTests {
void run() {
dblock lk;
Client::Context ctx( ns() );
shared_ptr<Cursor> c = NamespaceDetailsTransient::getCursor( ns(), query(), order() );
boost::shared_ptr<Cursor> c = NamespaceDetailsTransient::getCursor( ns(), query(), order() );
string type = c->toString().substr( 0, expectedType().length() );
ASSERT_EQUALS( expectedType(), type );
check( c );
@ -2520,7 +2680,7 @@ namespace QueryOptimizerTests {
virtual string expectedType() const = 0;
virtual BSONObj query() const { return BSONObj(); }
virtual BSONObj order() const { return BSONObj(); }
virtual void check( const shared_ptr<Cursor> &c ) {
virtual void check( const boost::shared_ptr<Cursor> &c ) {
ASSERT( c->ok() );
ASSERT( !c->matcher() );
ASSERT_EQUALS( 5, c->current().getIntField( "_id" ) );
@ -2551,7 +2711,7 @@ namespace QueryOptimizerTests {
}
string expectedType() const { return "BtreeCursor a_1"; }
BSONObj query() const { return BSON( "a" << GTE << 5 ); }
void check( const shared_ptr<Cursor> &c ) {
void check( const boost::shared_ptr<Cursor> &c ) {
ASSERT( c->ok() );
ASSERT( c->matcher() );
ASSERT_EQUALS( 5, c->current().getIntField( "a" ) );
@ -2571,7 +2731,7 @@ namespace QueryOptimizerTests {
}
string expectedType() const { return "GeoSearchCursor"; }
BSONObj query() const { return fromjson( "{ loc : { $near : [50,50] } }" ); }
void check( const shared_ptr<Cursor> &c ) {
void check( const boost::shared_ptr<Cursor> &c ) {
ASSERT( c->ok() );
ASSERT( c->matcher() );
ASSERT( c->matcher()->matchesCurrent( c.get() ) );
@ -2586,7 +2746,7 @@ namespace QueryOptimizerTests {
_cli.insert( ns(), BSON( "_id" << 5 ) );
dblock lk;
Client::Context ctx( ns() );
shared_ptr<Cursor> c = NamespaceDetailsTransient::getCursor( ns(), BSONObj(), BSON( "b" << 1 ) );
boost::shared_ptr<Cursor> c = NamespaceDetailsTransient::getCursor( ns(), BSONObj(), BSON( "b" << 1 ) );
ASSERT( !c );
}
};
@ -2601,7 +2761,7 @@ namespace QueryOptimizerTests {
ASSERT( _cli.query( ns(), QUERY( "_id" << GT << 0 << "b" << GT << 0 ).sort( "b" ) )->more() );
dblock lk;
Client::Context ctx( ns() );
shared_ptr<Cursor> c = NamespaceDetailsTransient::getCursor( ns(), BSON( "_id" << GT << 0 << "b" << GT << 0 ), BSON( "b" << 1 ) );
boost::shared_ptr<Cursor> c = NamespaceDetailsTransient::getCursor( ns(), BSON( "_id" << GT << 0 << "b" << GT << 0 ), BSON( "b" << 1 ) );
// {_id:1} requires scan and order, so {b:1} must be chosen.
ASSERT( c );
ASSERT_EQUALS( 5, c->current().getIntField( "_id" ) );
@ -2615,7 +2775,7 @@ namespace QueryOptimizerTests {
}
string expectedType() const { return "QueryOptimizerCursor"; }
BSONObj query() const { return BSON( "_id" << GT << 0 << "a" << GT << 0 ); }
void check( const shared_ptr<Cursor> &c ) {}
void check( const boost::shared_ptr<Cursor> &c ) {}
};
} // namespace GetCursor
@ -2666,6 +2826,8 @@ namespace QueryOptimizerTests {
add<QueryPlanSetTests::EqualityThenIn>();
add<QueryPlanSetTests::NotEqualityThenIn>();
add<BestGuess>();
add<MultiCursorTests::IdHint>();
add<MultiCursorTests::NaturalHintFallback>();
add<QueryOptimizerCursorTests::Empty>();
add<QueryOptimizerCursorTests::Unindexed>();
add<QueryOptimizerCursorTests::Basic>();
@ -2703,11 +2865,14 @@ namespace QueryOptimizerTests {
add<QueryOptimizerCursorTests::YieldUpdate>();
add<QueryOptimizerCursorTests::YieldDrop>();
add<QueryOptimizerCursorTests::YieldDropOr>();
add<QueryOptimizerCursorTests::YieldRemoveOr>();
add<QueryOptimizerCursorTests::YieldCappedOverwrite>();
add<QueryOptimizerCursorTests::YieldDropIndex>();
add<QueryOptimizerCursorTests::YieldMultiplePlansNoOp>();
add<QueryOptimizerCursorTests::YieldMultiplePlansAdvanceNoOp>();
add<QueryOptimizerCursorTests::YieldMultiplePlansDelete>();
add<QueryOptimizerCursorTests::YieldMultiplePlansDeleteOr>();
add<QueryOptimizerCursorTests::YieldMultiplePlansDeleteOrAdvance>();
add<QueryOptimizerCursorTests::YieldMultiplePlansCappedOverwrite>();
add<QueryOptimizerCursorTests::YieldMultiplePlansCappedOverwriteManual>();
add<QueryOptimizerCursorTests::YieldMultiplePlansCappedOverwriteManual2>();

View File

@ -238,7 +238,14 @@ namespace QueryUtilTests {
}
};
class QueryPatternTest {
class QueryPatternBase {
protected:
static QueryPattern p( const BSONObj &query, const BSONObj &sort = BSONObj() ) {
return FieldRangeSet( "", query, true ).pattern( sort );
}
};
class QueryPatternTest : public QueryPatternBase {
public:
void run() {
ASSERT( p( BSON( "a" << 1 ) ) == p( BSON( "a" << 1 ) ) );
@ -258,12 +265,17 @@ namespace QueryUtilTests {
ASSERT( p( BSON( "a" << 1 ), BSON( "b" << 1 << "c" << 1 ) ) != p( BSON( "a" << 4 ), BSON( "b" << 1 ) ) );
ASSERT( p( BSON( "a" << 1 ), BSON( "b" << 1 ) ) != p( BSON( "a" << 4 ), BSON( "b" << 1 << "c" << 1 ) ) );
}
private:
static QueryPattern p( const BSONObj &query, const BSONObj &sort = BSONObj() ) {
return FieldRangeSet( "", query, true ).pattern( sort );
};
class QueryPatternNeConstraint : public QueryPatternBase {
public:
void run() {
ASSERT( p( BSON( "a" << NE << 5 ) ) != p( BSON( "a" << GT << 1 ) ) );
ASSERT( p( BSON( "a" << NE << 5 ) ) != p( BSONObj() ) );
ASSERT( p( BSON( "a" << NE << 5 ) ) == p( BSON( "a" << NE << "a" ) ) );
}
};
class NoWhere {
public:
void run() {
@ -902,6 +914,7 @@ namespace QueryUtilTests {
add< FieldRangeTests::Equality >();
add< FieldRangeTests::SimplifiedQuery >();
add< FieldRangeTests::QueryPatternTest >();
add< FieldRangeTests::QueryPatternNeConstraint >();
add< FieldRangeTests::NoWhere >();
add< FieldRangeTests::Numeric >();
add< FieldRangeTests::InLowerBound >();

View File

@ -28,6 +28,8 @@
#include "../db/oplog.h"
#include "../db/queryoptimizer.h"
#include "../db/repl/rs.h"
namespace mongo {
void createOplog();
}
@ -107,12 +109,6 @@ namespace ReplTests {
return count;
}
static void applyAllOperations() {
class Applier : public ReplSource {
public:
static void apply( const BSONObj &op ) {
ReplSource::applyOperation( op );
}
};
dblock lk;
vector< BSONObj > ops;
{
@ -122,8 +118,13 @@ namespace ReplTests {
}
{
Client::Context ctx( ns() );
for( vector< BSONObj >::iterator i = ops.begin(); i != ops.end(); ++i )
Applier::apply( *i );
BSONObjBuilder b;
b.append("host", "localhost");
b.appendTimestamp("syncedTo", 0);
ReplSource a(b.obj());
for( vector< BSONObj >::iterator i = ops.begin(); i != ops.end(); ++i ) {
a.applyOperation( *i );
}
}
}
static void printAll( const char *ns ) {
@ -1014,7 +1015,7 @@ namespace ReplTests {
ASSERT( !one( BSON( "_id" << 2 ) ).isEmpty() );
}
};
class DatabaseIgnorerBasic {
public:
void run() {
@ -1047,10 +1048,10 @@ namespace ReplTests {
d.doIgnoreUntilAfter( "a", OpTime( 5, 0 ) );
ASSERT( d.ignoreAt( "a", OpTime( 5, 5 ) ) );
ASSERT( d.ignoreAt( "a", OpTime( 6, 0 ) ) );
ASSERT( !d.ignoreAt( "a", OpTime( 6, 1 ) ) );
ASSERT( !d.ignoreAt( "a", OpTime( 6, 1 ) ) );
}
};
/**
* Check against oldest document in the oplog before scanning backward
* from the newest document.
@ -1075,7 +1076,7 @@ namespace ReplTests {
ASSERT_EQUALS( 0, fsc.cursor()->current()[ "o" ].Obj()[ "_id" ].Int() );
}
};
/** Check unsuccessful yield recovery with FindingStartCursor */
class FindingStartCursorYield : public Base {
public:
@ -1101,7 +1102,26 @@ namespace ReplTests {
ASSERT_EXCEPTION( fsc.recoverFromYield(), MsgAssertionException );
}
};
/** Check ReplSetConfig::MemberCfg equality */
class ReplSetMemberCfgEquality : public Base {
public:
void run() {
ReplSetConfig::MemberCfg m1, m2;
assert(m1 == m2);
m1.tags["x"] = "foo";
assert(m1 != m2);
m2.tags["y"] = "bar";
assert(m1 != m2);
m1.tags["y"] = "bar";
assert(m1 != m2);
m2.tags["x"] = "foo";
assert(m1 == m2);
m1.tags.clear();
assert(m1 != m2);
}
};
class All : public Suite {
public:
All() : Suite( "repl" ) {
@ -1158,6 +1178,7 @@ namespace ReplTests {
add< DatabaseIgnorerUpdate >();
add< FindingStartCursorStale >();
add< FindingStartCursorYield >();
add< ReplSetMemberCfgEquality >();
}
} myall;

View File

@ -20,6 +20,7 @@
#include <boost/thread/thread.hpp>
#include "dbtests.h"
#include "../util/concurrency/spin_lock.h"
#include "../util/timer.h"
namespace {
@ -73,8 +74,10 @@ namespace {
int counter = 0;
const int threads = 64;
const int incs = 10000;
const int incs = 50000;
LockTester* testers[threads];
Timer timer;
for ( int i = 0; i < threads; i++ ) {
testers[i] = new LockTester( &spin, &counter );
@ -87,7 +90,10 @@ namespace {
ASSERT_EQUALS( testers[i]->requests(), incs );
delete testers[i];
}
int ms = timer.millis();
log() << "spinlock ConcurrentIncs time: " << ms << endl;
ASSERT_EQUALS( counter, threads*incs );
#if defined(__linux__)
ASSERT( SpinLock::isfast() );

View File

@ -544,6 +544,15 @@ namespace ThreadedTests {
};
#endif
void sleepalittle() {
Timer t;
while( 1 ) {
boost::this_thread::yield();
if( t.micros() > 8 )
break;
}
}
class WriteLocksAreGreedy : public ThreadedTest<3> {
public:
WriteLocksAreGreedy() : m("gtest") {}
@ -579,6 +588,81 @@ namespace ThreadedTests {
}
};
// Tests waiting on the TicketHolder by running many more threads than can fit into the "hotel", but only
// max _nRooms threads should ever get in at once
class TicketHolderWaits : public ThreadedTest<10> {
static const int checkIns = 1000;
static const int rooms = 3;
public:
TicketHolderWaits() : _hotel( rooms ), _tickets( _hotel._nRooms ) {}
private:
class Hotel {
public:
Hotel( int nRooms ) : _frontDesk( "frontDesk" ), _nRooms( nRooms ), _checkedIn( 0 ), _maxRooms( 0 ) {}
void checkIn(){
scoped_lock lk( _frontDesk );
_checkedIn++;
assert( _checkedIn <= _nRooms );
if( _checkedIn > _maxRooms ) _maxRooms = _checkedIn;
}
void checkOut(){
scoped_lock lk( _frontDesk );
_checkedIn--;
assert( _checkedIn >= 0 );
}
mongo::mutex _frontDesk;
int _nRooms;
int _checkedIn;
int _maxRooms;
};
Hotel _hotel;
TicketHolder _tickets;
virtual void subthread(int x) {
string threadName = ( str::stream() << "ticketHolder" << x );
Client::initThread( threadName.c_str() );
for( int i = 0; i < checkIns; i++ ){
_tickets.waitForTicket();
TicketHolderReleaser whenDone( &_tickets );
_hotel.checkIn();
sleepalittle();
if( i == checkIns - 1 ) sleepsecs( 2 );
_hotel.checkOut();
if( ( i % ( checkIns / 10 ) ) == 0 )
log() << "checked in " << i << " times..." << endl;
}
cc().shutdown();
}
virtual void validate() {
// This should always be true, assuming that it takes < 1 sec for the hardware to process a check-out/check-in
// Time for test is then ~ #threads / _nRooms * 2 seconds
assert( _hotel._maxRooms == _hotel._nRooms );
}
};
class All : public Suite {
public:
All() : Suite( "threading" ) { }
@ -600,6 +684,7 @@ namespace ThreadedTests {
add< RWLockTest4 >();
add< MongoMutexTest >();
add< TicketHolderWaits >();
}
} myall;
}

View File

@ -519,6 +519,48 @@ namespace UpdateTests {
}
};
/** SERVER-4777 */
class TwoModsWithinDuplicatedField : public SetBase {
public:
void run() {
client().insert( ns(), BSON( "_id" << 0 << "a" << 1
<< "x" << BSONObj() << "x" << BSONObj()
<< "z" << 5 ) );
client().update( ns(), BSONObj(), BSON( "$set" << BSON( "x.b" << 1 << "x.c" << 1 ) ) );
ASSERT_EQUALS( BSON( "_id" << 0 << "a" << 1
<< "x" << BSON( "b" << 1 << "c" << 1 ) << "x" << BSONObj()
<< "z" << 5 ),
client().findOne( ns(), BSONObj() ) );
}
};
/** SERVER-4777 */
class ThreeModsWithinDuplicatedField : public SetBase {
public:
void run() {
client().insert( ns(),
BSON( "_id" << 0
<< "x" << BSONObj() << "x" << BSONObj() << "x" << BSONObj() ) );
client().update( ns(), BSONObj(),
BSON( "$set" << BSON( "x.b" << 1 << "x.c" << 1 << "x.d" << 1 ) ) );
ASSERT_EQUALS( BSON( "_id" << 0
<< "x" << BSON( "b" << 1 << "c" << 1 << "d" << 1 )
<< "x" << BSONObj() << "x" << BSONObj() ),
client().findOne( ns(), BSONObj() ) );
}
};
class TwoModsBeforeExistingField : public SetBase {
public:
void run() {
client().insert( ns(), BSON( "_id" << 0 << "x" << 5 ) );
client().update( ns(), BSONObj(),
BSON( "$set" << BSON( "a" << 1 << "b" << 1 << "x" << 10 ) ) );
ASSERT_EQUALS( BSON( "_id" << 0 << "a" << 1 << "b" << 1 << "x" << 10 ),
client().findOne( ns(), BSONObj() ) );
}
};
namespace ModSetTests {
class internal1 {
@ -854,6 +896,9 @@ namespace UpdateTests {
add< PreserveIdWithIndex >();
add< CheckNoMods >();
add< UpdateMissingToNull >();
add< TwoModsWithinDuplicatedField >();
add< ThreeModsWithinDuplicatedField >();
add< TwoModsBeforeExistingField >();
add< ModSetTests::internal1 >();
add< ModSetTests::inc1 >();

55
debian/changelog vendored
View File

@ -1,3 +1,58 @@
mongodb (2.0.7) unstable; urgency=low
* see http://www.mongodb.org/display/DOCS/2.0+Release+Notes
* see https://jira.mongodb.org/browse/SERVER/fixforversion/11201
-- Eric Milkie <milkie@10gen.com> Fri, 13 Jul 2012 10:52:00 -0500
mongodb (2.0.6) unstable; urgency=low
* see http://www.mongodb.org/display/DOCS/2.0+Release+Notes
* see https://jira.mongodb.org/browse/SERVER/fixforversion/11165
-- Eric Milkie <milkie@10gen.com> Tue, 22 May 2012 10:52:00 -0500
mongodb (2.0.5) unstable; urgency=low
* see http://www.mongodb.org/display/DOCS/2.0+Release+Notes
* see https://jira.mongodb.org/browse/SERVER/fixforversion/11137
-- Andy Schwerin <schwerin@10gen.com> Wed, 25 Apr 2012 10:52:00 -0500
mongodb (2.0.4) unstable; urgency=low
* see http://www.mongodb.org/display/DOCS/2.0+Release+Notes
* see http://jira.mongodb.org/browse/SERVER/fixforversion/11107
-- Richard Kreuter <richard@10gen.com> Mon, 19 Mar 2012 16:56:28 -0500
mongodb (2.0.3) unstable; urgency=low
* see http://www.mongodb.org/display/DOCS/2.0+Release+Notes
* see http://jira.mongodb.org/browse/SERVER/fixforversion/11001
-- Richard Kreuter <richard@10gen.com> Mon, 27 Feb 2012 16:56:28 -0500
mongodb (2.0.2) unstable; urgency=low
* see http://www.mongodb.org/display/DOCS/2.0+Release+Notes
* see http://jira.mongodb.org/browse/SERVER/fixforversion/10991
-- Richard Kreuter <richard@10gen.com> Wed, 14 Dec 2011 16:56:28 -0500
mongodb (2.0.1) unstable; urgency=low
* see http://www.mongodb.org/display/DOCS/2.0+Release+Notes
* see http://jira.mongodb.org/browse/SERVER/fixforversion/10890
-- Richard Kreuter <richard@10gen.com> Fri, 21 Oct 2011 16:56:28 -0500
mongodb (2.0.0) unstable; urgency=low
* see http://www.mongodb.org/display/DOCS/2.0+Release+Notes
-- Richard Kreuter <richard@10gen.com> Mon, 12 Sep 2011 16:56:28 -0500
mongodb (1.9.2) unstable; urgency=low
* see http://jira.mongodb.org/browse/SERVER/fixforversion/10261

View File

@ -188,4 +188,46 @@ freely, subject to the following restrictions:
L. Peter Deutsch
ghost@aladdin.com
5) License notice for Snappy - http://code.google.com/p/snappy/
---------------------------------
Copyright 2005 and onwards Google Inc.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the
distribution.
* Neither the name of Google Inc. nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
A light-weight compression algorithm. It is designed for speed of
compression and decompression, rather than for the utmost in space
savings.
For getting better compression ratios when you are compressing data
with long repeated sequences or compressing data that is similar to
other data, while still compressing fast, you might look at first
using BMDiff and then compressing the output of BMDiff with
Snappy.
End

View File

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

View File

@ -16,6 +16,14 @@ db.addUser( "eliot" , "eliot" );
db.addUser( "guest" , "guest", true );
db.getSisterDB( "admin" ).addUser( "super", "super" );
print("make sure we can't run certain commands w/out auth");
var errmsg = "need to login";
res = db.adminCommand({getLog : "global"});
printjson( res );
assert( ! res.log || res.log.length == 0 , "getLog should fail: " + tojson( res ) )
assert.eq( res.errmsg , "need to login" , tojson( res ) );
assert.throws( function() { t.findOne() }, [], "read without login" );
assert( db.auth( "eliot" , "eliot" ) , "auth failed" );

View File

@ -105,3 +105,5 @@ tzz = db.capped6;
for( var i = 0; i < 10; ++i ) {
doTest();
}
tzz.drop();

View File

@ -104,3 +104,5 @@ print("pass " + pass++);
t.drop();
db._dbCommand( { create:"jstests_capped8", capped: true, $nExtents: [ 10000 ] } );
testTruncate();
t.drop();

34
jstests/distinct3.js Normal file
View File

@ -0,0 +1,34 @@
// Yield and delete test case for query optimizer cursor.
t = db.jstests_distinct3;
t.drop();
t.ensureIndex({a:1});
t.ensureIndex({b:1});
for( i = 0; i < 50; ++i ) {
for( j = 0; j < 20; ++j ) {
t.save({a:i,c:i,d:j});
}
}
for( i = 0; i < 1000; ++i ) {
t.save({b:i,c:i+50});
}
db.getLastError();
// Attempt to remove the last match for the {a:1} index scan while distinct is yielding.
p = startParallelShell( 'for( i = 0; i < 2500; ++i ) { ' +
' db.jstests_distinct3.remove( { a:49 } ); ' +
' for( j = 0; j < 20; ++j ) { ' +
' db.jstests_distinct3.save( { a:49, c:49, d:j } ); ' +
' } ' +
'} ' +
'// Wait for the above writes to complete. ' +
'db.getLastError(); ' );
for( i = 0; i < 100; ++i ) {
count = t.distinct( 'c', {$or:[{a:{$gte:0},d:0},{b:{$gte:0}}]} ).length;
assert.gt( count, 1000 );
}
p();

View File

@ -1,17 +1,40 @@
// Check the return value of a db.eval function running a database query, and ensure the function's
// contents are logged in the profile log.
t = db.evalb;
t.drop();
// Use a reserved database name to avoid a conflict in the parallel test suite.
var stddb = db;
var db = db.getSisterDB( 'evalb' );
t.save( { x : 3 } );
function profileCursor() {
return db.system.profile.find( { user:username } );
}
assert.eq( 3, db.eval( function(){ return db.evalb.findOne().x; } ) , "A" );
function lastOp() {
return profileCursor().sort( { $natural:-1 } ).next();
}
db.setProfilingLevel( 2 );
try {
assert.eq( 3, db.eval( function(){ return db.evalb.findOne().x; } ) , "B" );
username = 'jstests_evalb_user';
db.addUser( username, 'password', false, 1 );
db.auth( username, 'password' );
o = db.system.profile.find().sort( { $natural : -1 } ).limit(1).next();
assert( tojson(o).indexOf( "findOne().x" ) > 0 , "C : " + tojson( o ) )
t = db.evalb;
t.drop();
db.setProfilingLevel( 0 );
t.save( { x:3 } );
assert.eq( 3, db.eval( function() { return db.evalb.findOne().x; } ), 'A' );
db.setProfilingLevel( 2 );
assert.eq( 3, db.eval( function() { return db.evalb.findOne().x; } ), 'B' );
o = lastOp();
assert( tojson( o ).indexOf( 'findOne().x' ) > 0, 'C : ' + tojson( o ) );
}
finally {
db.setProfilingLevel(0);
db = stddb;
}

View File

@ -7,5 +7,5 @@ for ( var i=0; i<50; i++ ) { // enough iterations to break 32 bit.
assert( t.count() == 1 );
t.drop();
}
t.drop();
db.dropDatabase();

31
jstests/extent2.js Normal file
View File

@ -0,0 +1,31 @@
mydb = db.getSisterDB( "test_extent2" );
mydb.dropDatabase();
t = mydb.foo;
e = mydb["$freelist"]
function insert(){
t.insert( { _id : 1 , x : 1 } )
t.insert( { _id : 2 , x : 1 } )
t.insert( { _id : 3 , x : 1 } )
t.ensureIndex( { x : 1 } );
}
insert();
t.drop();
start = e.stats();
for ( i=0; i<100; i++ ) {
insert();
t.drop();
}
end = e.stats();
printjson( start );
printjson( end )
assert.eq( 4 , start.numExtents );
assert.eq( 4 , end.numExtents );

11
jstests/filemd5.js Normal file
View File

@ -0,0 +1,11 @@
db.fs.chunks.drop();
db.fs.chunks.insert({files_id:1,n:0,data:new BinData(0,"test")})
x = db.runCommand({"filemd5":1,"root":"fs"});
assert( ! x.ok , tojson(x) )
db.fs.chunks.ensureIndex({files_id:1,n:1})
x = db.runCommand({"filemd5":1,"root":"fs"});
assert( x.ok , tojson(x) )

41
jstests/getlog2.js Normal file
View File

@ -0,0 +1,41 @@
// tests getlog as well as slow querying logging
glcol = db.getLogTest2;
glcol.drop()
contains = function(arr, func) {
var i = arr.length;
while (i--) {
if (func(arr[i])) {
return true;
}
}
return false;
}
// test doesn't work when talking to mongos
if(db.isMaster().msg != "isdbgrid") {
// run a slow query
glcol.save({ "SENTINEL": 1 });
glcol.findOne({ "SENTINEL": 1, "$where": function() { sleep(1000); return true; } });
// run a slow update
glcol.update({ "SENTINEL": 1, "$where": function() { sleep(1000); return true; } }, { "x": "x" });
var resp = db.adminCommand({getLog:"global"});
assert( resp.ok == 1, "error executing getLog command" );
assert( resp.log, "no log field" );
assert( resp.log.length > 0 , "no log lines" );
// ensure that slow query is logged in detail
assert( contains(resp.log, function(v) {
print(v);
return v.indexOf(" query ") != -1 && v.indexOf("query:") != -1 && v.indexOf("SENTINEL") != -1;
}) );
// same, but for update
assert( contains(resp.log, function(v) {
print(v);
return v.indexOf(" update ") != -1 && v.indexOf("query:") != -1 && v.indexOf("SENTINEL") != -1;
}) );
}

View File

@ -5,8 +5,7 @@
// when it doesn't move
t = db.indexb;t = db.indexb;
db.dropDatabase();
t = db.indexb;
t.drop();
t.ensureIndex({a:1},true);

View File

@ -6,9 +6,11 @@ b = new ObjectId("4c17f616a707428966a2801c");
assert.eq(a.getTimestamp(), b.getTimestamp() , "A" );
x = Math.floor( (new Date()).getTime() / 1000 );
sleep(10/*ms*/)
a = new ObjectId();
sleep(10/*ms*/)
z = Math.floor( (new Date()).getTime() / 1000 );
y = a.getTimestamp().getTime() / 1000;
assert( x <= y , "B" );
assert( y <= z , "C" );
assert.lte( x , y , "B" );
assert.lte( y , z , "C" );

View File

@ -55,12 +55,18 @@ try {
db.eval("sleep(1)") // pre-load system.js
db.setProfilingLevel(2);
before = db.system.profile.count();
function resetProfile( level , slowms ) {
db.setProfilingLevel(0);
db.system.profile.drop();
db.setProfilingLevel(level,slowms);
}
resetProfile(2);
db.eval( "sleep(25)" )
db.eval( "sleep(120)" )
after = db.system.profile.count()
assert.eq( before + 3 , after , "X1" )
assert.eq( 2 , db.system.profile.find( { "command.$eval" : /^sleep/ } ).count() );
/* sleep() could be inaccurate on certain platforms. let's check */
print("\nsleep 2 time actual:");
@ -90,24 +96,20 @@ try {
return actual >= max ? 1 : 0;
}
db.setProfilingLevel(1,100);
before = db.system.profile.count();
resetProfile(1,100);
var delta = 0;
delta += evalSleepMoreThan( 15 , 100 );
delta += evalSleepMoreThan( 120 , 100 );
after = db.system.profile.count()
assert.eq( before + delta , after , "X2 : " + getProfileAString() )
assert.eq( delta , db.system.profile.find( { "command.$eval" : /^sleep/ } ).count() , "X2 : " + getProfileAString() )
db.setProfilingLevel(1,20);
before = db.system.profile.count();
resetProfile(1,20);
delta = 0;
delta += evalSleepMoreThan( 5 , 20 );
delta += evalSleepMoreThan( 120 , 20 );
after = db.system.profile.count()
assert.eq( before + delta , after , "X3 : " + getProfileAString() )
assert.eq( delta , db.system.profile.find( { "command.$eval" : /^sleep/ } ).count() , "X3 : " + getProfileAString() )
db.profile.drop();
db.setProfilingLevel(2)
resetProfile(2);
db.profile1.drop();
var q = { _id : 5 };
var u = { $inc : { x : 1 } };
db.profile1.update( q , u );

View File

@ -17,3 +17,17 @@ t.save( { a: [ 2 ] } );
t.update( {}, { $pull: { a: 2 } } );
t.update( {}, { $pull: { a: 6 } } );
assert.eq( [], t.findOne().a );
// SERVER-6047: $pull creates empty nested docs for dotted fields
// that don't exist.
t.drop()
t.save({ m : 1 } );
t.update( { m : 1 }, { $pull : { 'a.b' : [ 1 ] } } );
assert( ('a' in t.findOne()) == false );
// Non-obvious bit: the implementation of non-in-place update
// might do different things depending on whether the "new" field
// comes before or after existing fields in the document.
// So for now it's worth testing that too. Sorry, future; blame the past.
t.update( { m : 1 }, { $pull : { 'x.y' : [ 1 ] } } );
assert( ('z' in t.findOne()) == false );
// End SERVER-6047

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