| clientcursor.h | | clientcursor.h | |
| | | | |
| skipping to change at line 48 | | skipping to change at line 48 | |
| | | | |
| typedef long long CursorId; /* passed to the client so it can send back
on getMore */ | | typedef long long CursorId; /* passed to the client so it can send back
on getMore */ | |
| class Cursor; /* internal server cursor base class */ | | class Cursor; /* internal server cursor base class */ | |
| class ClientCursor; | | class ClientCursor; | |
| class ParsedQuery; | | class ParsedQuery; | |
| | | | |
| /* todo: make this map be per connection. this will prevent cursor hij
acking security attacks perhaps. | | /* todo: make this map be per connection. this will prevent cursor hij
acking security attacks perhaps. | |
| */ | | */ | |
| typedef map<CursorId, ClientCursor*> CCById; | | typedef map<CursorId, ClientCursor*> CCById; | |
| | | | |
|
| typedef multimap<DiskLoc, ClientCursor*> CCByLoc; | | | |
| | | | |
| extern BSONObj id_obj; | | extern BSONObj id_obj; | |
| | | | |
| class ClientCursor { | | class ClientCursor { | |
| friend class CmdCursorInfo; | | friend class CmdCursorInfo; | |
| DiskLoc _lastLoc; // use getter and setter n
ot this (important) | | DiskLoc _lastLoc; // use getter and setter n
ot this (important) | |
| unsigned _idleAgeMillis; // how long has the cursor
been around, relative to server idle time | | unsigned _idleAgeMillis; // how long has the cursor
been around, relative to server idle time | |
| | | | |
| /* 0 = normal | | /* 0 = normal | |
| 1 = no timeout allowed | | 1 = no timeout allowed | |
| 100 = in use (pinned) -- see Pointer class | | 100 = in use (pinned) -- see Pointer class | |
| */ | | */ | |
| unsigned _pinValue; | | unsigned _pinValue; | |
| | | | |
| bool _doingDeletes; | | bool _doingDeletes; | |
| ElapsedTracker _yieldSometimesTracker; | | ElapsedTracker _yieldSometimesTracker; | |
| | | | |
| static CCById clientCursorsById; | | static CCById clientCursorsById; | |
|
| static CCByLoc byLoc; | | static long long numberTimedOut; | |
| static boost::recursive_mutex ccmutex; // must use this for all s
tatics above! | | static boost::recursive_mutex ccmutex; // must use this for all s
tatics above! | |
|
| | | | |
| static CursorId allocCursorId_inlock(); | | static CursorId allocCursorId_inlock(); | |
| | | | |
| public: | | public: | |
|
| | | static void assertNoCursors(); | |
| | | | |
| /* use this to assure we don't in the background time out cursor wh
ile it is under use. | | /* use this to assure we don't in the background time out cursor wh
ile it is under use. | |
| if you are using noTimeout() already, there is no risk anyway. | | if you are using noTimeout() already, there is no risk anyway. | |
| Further, this mechanism guards against two getMore requests on t
he same cursor executing | | Further, this mechanism guards against two getMore requests on t
he same cursor executing | |
| at the same time - which might be bad. That should never happen
, but if a client driver | | at the same time - which might be bad. That should never happen
, but if a client driver | |
| had a bug, it could (or perhaps some sort of attack situation). | | had a bug, it could (or perhaps some sort of attack situation). | |
| */ | | */ | |
| class Pointer : boost::noncopyable { | | class Pointer : boost::noncopyable { | |
| public: | | public: | |
| ClientCursor *_c; | | ClientCursor *_c; | |
| void release() { | | void release() { | |
| | | | |
| skipping to change at line 140 | | skipping to change at line 139 | |
| DESTRUCTOR_GUARD ( reset(); ); | | DESTRUCTOR_GUARD ( reset(); ); | |
| } | | } | |
| operator bool() { return _c; } | | operator bool() { return _c; } | |
| ClientCursor * operator-> () { return _c; } | | ClientCursor * operator-> () { return _c; } | |
| private: | | private: | |
| ClientCursor *_c; | | ClientCursor *_c; | |
| CursorId _id; | | CursorId _id; | |
| }; | | }; | |
| | | | |
| /*const*/ CursorId cursorid; | | /*const*/ CursorId cursorid; | |
|
| string ns; | | const string ns; | |
| shared_ptr<Cursor> c; | | const shared_ptr<Cursor> c; | |
| int pos; // # objects into the cursor so far | | int pos; // # objects into the cursor so far | |
| BSONObj query; | | BSONObj query; | |
|
| int _queryOptions; // see enum QueryOptions dbclient.h | | const int _queryOptions; // see enum QueryOptions dbclient.h | |
| OpTime _slaveReadTill; | | OpTime _slaveReadTill; | |
|
| | | Database * const _db; | |
| | | | |
| ClientCursor(int queryOptions, shared_ptr<Cursor>& _c, const string
& _ns) : | | ClientCursor(int queryOptions, shared_ptr<Cursor>& _c, const string
& _ns) : | |
| _idleAgeMillis(0), _pinValue(0), | | _idleAgeMillis(0), _pinValue(0), | |
| _doingDeletes(false), _yieldSometimesTracker(128,10), | | _doingDeletes(false), _yieldSometimesTracker(128,10), | |
| ns(_ns), c(_c), | | ns(_ns), c(_c), | |
|
| pos(0), _queryOptions(queryOptions) | | pos(0), _queryOptions(queryOptions), | |
| | | _db( cc().database() ) | |
| { | | { | |
|
| | | assert( _db ); | |
| | | assert( str::startsWith(_ns, _db->name) ); | |
| if( queryOptions & QueryOption_NoCursorTimeout ) | | if( queryOptions & QueryOption_NoCursorTimeout ) | |
| noTimeout(); | | noTimeout(); | |
| recursive_scoped_lock lock(ccmutex); | | recursive_scoped_lock lock(ccmutex); | |
| cursorid = allocCursorId_inlock(); | | cursorid = allocCursorId_inlock(); | |
| clientCursorsById.insert( make_pair(cursorid, this) ); | | clientCursorsById.insert( make_pair(cursorid, this) ); | |
| } | | } | |
| ~ClientCursor(); | | ~ClientCursor(); | |
| | | | |
| DiskLoc lastLoc() const { | | DiskLoc lastLoc() const { | |
| return _lastLoc; | | return _lastLoc; | |
| | | | |
| skipping to change at line 309 | | skipping to change at line 312 | |
| /* if ( !ids_.get() ) | | /* if ( !ids_.get() ) | |
| return; | | return; | |
| stringstream ss; | | stringstream ss; | |
| ss << ns << "." << cursorid; | | ss << ns << "." << cursorid; | |
| ids_->mayUpgradeStorage( ss.str() );*/ | | ids_->mayUpgradeStorage( ss.str() );*/ | |
| } | | } | |
| | | | |
| /** | | /** | |
| * @param millis amount of idle passed time since last call | | * @param millis amount of idle passed time since last call | |
| */ | | */ | |
|
| bool shouldTimeout( unsigned millis ){ | | bool shouldTimeout( unsigned millis ); | |
| _idleAgeMillis += millis; | | | |
| return _idleAgeMillis > 600000 && _pinValue == 0; | | | |
| } | | | |
| | | | |
| void storeOpForSlave( DiskLoc last ); | | void storeOpForSlave( DiskLoc last ); | |
| void updateSlaveLocation( CurOp& curop ); | | void updateSlaveLocation( CurOp& curop ); | |
| | | | |
| unsigned idleTime(){ | | unsigned idleTime(){ | |
| return _idleAgeMillis; | | return _idleAgeMillis; | |
| } | | } | |
| | | | |
| static void idleTimeReport(unsigned millis); | | static void idleTimeReport(unsigned millis); | |
| private: | | private: | |
| // cursors normally timeout after an inactivy period to prevent exc
ess memory use | | // cursors normally timeout after an inactivy period to prevent exc
ess memory use | |
| // setting this prevents timeout of the cursor in question. | | // setting this prevents timeout of the cursor in question. | |
| void noTimeout() { | | void noTimeout() { | |
| _pinValue++; | | _pinValue++; | |
| } | | } | |
|
| | | | |
| | | multimap<DiskLoc, ClientCursor*>& byLoc() { | |
| | | return _db->ccByLoc; | |
| | | } | |
| public: | | public: | |
| void setDoingDeletes( bool doingDeletes ){ | | void setDoingDeletes( bool doingDeletes ){ | |
| _doingDeletes = doingDeletes; | | _doingDeletes = doingDeletes; | |
| } | | } | |
| | | | |
|
| static unsigned byLocSize(); // just for diagnostics | | static void appendStats( BSONObjBuilder& result ); | |
| | | | |
| | | static unsigned numCursors() { return clientCursorsById.size(); } | |
| | | | |
| static void informAboutToDeleteBucket(const DiskLoc& b); | | static void informAboutToDeleteBucket(const DiskLoc& b); | |
| static void aboutToDelete(const DiskLoc& dl); | | static void aboutToDelete(const DiskLoc& dl); | |
| | | | |
| static void find( const string& ns , set<CursorId>& all ); | | static void find( const string& ns , set<CursorId>& all ); | |
| }; | | }; | |
| | | | |
| class ClientCursorMonitor : public BackgroundJob { | | class ClientCursorMonitor : public BackgroundJob { | |
| public: | | public: | |
| void run(); | | void run(); | |
| | | | |
End of changes. 12 change blocks. |
| 13 lines changed or deleted | | 19 lines changed or added | |
|
| database.h | | database.h | |
| | | | |
| skipping to change at line 25 | | skipping to change at line 25 | |
| * You should have received a copy of the GNU Affero General Public Licen
se | | * You should have received a copy of the GNU Affero General Public Licen
se | |
| * along with this program. If not, see <http://www.gnu.org/licenses/>. | | * along with this program. If not, see <http://www.gnu.org/licenses/>. | |
| */ | | */ | |
| | | | |
| #pragma once | | #pragma once | |
| | | | |
| #include "cmdline.h" | | #include "cmdline.h" | |
| | | | |
| namespace mongo { | | namespace mongo { | |
| | | | |
|
| | | class ClientCursor; | |
| | | | |
| /** | | /** | |
| * Database represents a database database | | * Database represents a database database | |
| * Each database database has its own set of files -- dbname.ns, dbname
.0, dbname.1, ... | | * Each database database has its own set of files -- dbname.ns, dbname
.0, dbname.1, ... | |
| * NOT memory mapped | | * NOT memory mapped | |
| */ | | */ | |
| class Database { | | class Database { | |
| public: | | public: | |
| static bool _openAllFiles; | | static bool _openAllFiles; | |
| | | | |
| Database(const char *nm, bool& newDb, const string& _path = dbpath)
; | | Database(const char *nm, bool& newDb, const string& _path = dbpath)
; | |
| | | | |
| skipping to change at line 199 | | skipping to change at line 201 | |
| } | | } | |
| | | | |
| void flushFiles( bool sync ); | | void flushFiles( bool sync ); | |
| | | | |
| vector<MongoDataFile*> files; | | vector<MongoDataFile*> files; | |
| string name; // "alleyinsider" | | string name; // "alleyinsider" | |
| string path; | | string path; | |
| NamespaceIndex namespaceIndex; | | NamespaceIndex namespaceIndex; | |
| int profile; // 0=off. | | int profile; // 0=off. | |
| string profileName; // "alleyinsider.system.profile" | | string profileName; // "alleyinsider.system.profile" | |
|
| | | | |
| | | multimap<DiskLoc, ClientCursor*> ccByLoc; | |
| | | | |
| int magic; // used for making sure the object is still loaded in me
mory | | int magic; // used for making sure the object is still loaded in me
mory | |
| }; | | }; | |
| | | | |
| } // namespace mongo | | } // namespace mongo | |
| | | | |
End of changes. 2 change blocks. |
| 0 lines changed or deleted | | 5 lines changed or added | |
|
| dbclient.h | | dbclient.h | |
| | | | |
| skipping to change at line 109 | | skipping to change at line 109 | |
| class ConnectionString { | | class ConnectionString { | |
| public: | | public: | |
| enum ConnectionType { INVALID , MASTER , PAIR , SET , SYNC }; | | enum ConnectionType { INVALID , MASTER , PAIR , SET , SYNC }; | |
| | | | |
| ConnectionString( const HostAndPort& server ){ | | ConnectionString( const HostAndPort& server ){ | |
| _type = MASTER; | | _type = MASTER; | |
| _servers.push_back( server ); | | _servers.push_back( server ); | |
| _finishInit(); | | _finishInit(); | |
| } | | } | |
| | | | |
|
| ConnectionString( ConnectionType type , const vector<HostAndPort>& | | // TODO Delete if nobody is using | |
| servers ) | | //ConnectionString( ConnectionType type , const vector<HostAndPort> | |
| : _type( type ) , _servers( servers ){ | | & servers ) | |
| _finishInit(); | | // : _type( type ) , _servers( servers ){ | |
| } | | // _finishInit(); | |
| | | //} | |
| | | | |
| ConnectionString( ConnectionType type , const string& s , const str
ing& setName = "" ){ | | ConnectionString( ConnectionType type , const string& s , const str
ing& setName = "" ){ | |
| _type = type; | | _type = type; | |
| _setName = setName; | | _setName = setName; | |
| _fillServers( s ); | | _fillServers( s ); | |
| | | | |
| switch ( _type ){ | | switch ( _type ){ | |
| case MASTER: | | case MASTER: | |
| assert( _servers.size() == 1 ); | | assert( _servers.size() == 1 ); | |
| break; | | break; | |
| | | | |
| skipping to change at line 159 | | skipping to change at line 160 | |
| bool isValid() const { return _type != INVALID; } | | bool isValid() const { return _type != INVALID; } | |
| | | | |
| string toString() const { | | string toString() const { | |
| return _string; | | return _string; | |
| } | | } | |
| | | | |
| DBClientBase* connect( string& errmsg ) const; | | DBClientBase* connect( string& errmsg ) const; | |
| | | | |
| static ConnectionString parse( const string& url , string& errmsg )
; | | static ConnectionString parse( const string& url , string& errmsg )
; | |
| | | | |
|
| | | string getSetName() const{ | |
| | | return _setName; | |
| | | } | |
| | | | |
| | | vector<HostAndPort> getServers() const { | |
| | | return _servers; | |
| | | } | |
| | | | |
| private: | | private: | |
| | | | |
| ConnectionString(){ | | ConnectionString(){ | |
| _type = INVALID; | | _type = INVALID; | |
| } | | } | |
| | | | |
| void _fillServers( string s ){ | | void _fillServers( string s ){ | |
| string::size_type idx; | | string::size_type idx; | |
| while ( ( idx = s.find( ',' ) ) != string::npos ){ | | while ( ( idx = s.find( ',' ) ) != string::npos ){ | |
| _servers.push_back( s.substr( 0 , idx ) ); | | _servers.push_back( s.substr( 0 , idx ) ); | |
| | | | |
| skipping to change at line 317 | | skipping to change at line 326 | |
| BSONObjBuilder b; | | BSONObjBuilder b; | |
| b.appendElements(obj); | | b.appendElements(obj); | |
| b.append(fieldName, val); | | b.append(fieldName, val); | |
| obj = b.obj(); | | obj = b.obj(); | |
| } | | } | |
| }; | | }; | |
| | | | |
| /** Typically one uses the QUERY(...) macro to construct a Query object. | | /** Typically one uses the QUERY(...) macro to construct a Query object. | |
| Example: QUERY( "age" << 33 << "school" << "UCLA" ) | | Example: QUERY( "age" << 33 << "school" << "UCLA" ) | |
| */ | | */ | |
|
| #define QUERY(x) Query( BSON(x) ) | | #define QUERY(x) mongo::Query( BSON(x) ) | |
| | | | |
| /** | | /** | |
| interface that handles communication with the db | | interface that handles communication with the db | |
| */ | | */ | |
| class DBConnector { | | class DBConnector { | |
| public: | | public: | |
| virtual ~DBConnector() {} | | virtual ~DBConnector() {} | |
| virtual bool call( Message &toSend, Message &response, bool assertO
k=true ) = 0; | | virtual bool call( Message &toSend, Message &response, bool assertO
k=true ) = 0; | |
| virtual void say( Message &toSend ) = 0; | | virtual void say( Message &toSend ) = 0; | |
| virtual void sayPiggyBack( Message &toSend ) = 0; | | virtual void sayPiggyBack( Message &toSend ) = 0; | |
| | | | |
| skipping to change at line 1000 | | skipping to change at line 1009 | |
| virtual void say( Message &toSend ) { checkMaster()->say( toSend );
} | | virtual void say( Message &toSend ) { checkMaster()->say( toSend );
} | |
| virtual bool callRead( Message& toSend , Message& response ){ retur
n checkMaster()->callRead( toSend , response ); } | | virtual bool callRead( Message& toSend , Message& response ){ retur
n checkMaster()->callRead( toSend , response ); } | |
| | | | |
| virtual ConnectionString::ConnectionType type() const { return Conn
ectionString::SET; } | | virtual ConnectionString::ConnectionType type() const { return Conn
ectionString::SET; } | |
| | | | |
| virtual bool isMember( const DBConnector * conn ) const; | | virtual bool isMember( const DBConnector * conn ) const; | |
| | | | |
| virtual void checkResponse( const char *data, int nReturned ) { che
ckMaster()->checkResponse( data , nReturned ); } | | virtual void checkResponse( const char *data, int nReturned ) { che
ckMaster()->checkResponse( data , nReturned ); } | |
| | | | |
| protected: | | protected: | |
|
| virtual void sayPiggyBack( Message &toSend ) { assert(false); } | | virtual void sayPiggyBack( Message &toSend ) { checkMaster()->say(
toSend ); } | |
| | | | |
| bool isFailed() const { | | bool isFailed() const { | |
| return _currentMaster == 0 || _currentMaster->isFailed(); | | return _currentMaster == 0 || _currentMaster->isFailed(); | |
| } | | } | |
| }; | | }; | |
| | | | |
| /** pings server to check if it's up | | /** pings server to check if it's up | |
| */ | | */ | |
| bool serverAlive( const string &uri ); | | bool serverAlive( const string &uri ); | |
| | | | |
| | | | |
End of changes. 4 change blocks. |
| 7 lines changed or deleted | | 16 lines changed or added | |
|
| grid.h | | grid.h | |
| | | | |
| skipping to change at line 60 | | skipping to change at line 60 | |
| bool allowLocalHost() const; | | bool allowLocalHost() const; | |
| | | | |
| /** | | /** | |
| * @param whether to allow shards and config servers to use 'localh
ost' in address | | * @param whether to allow shards and config servers to use 'localh
ost' in address | |
| */ | | */ | |
| void setAllowLocalHost( bool allow ); | | void setAllowLocalHost( bool allow ); | |
| | | | |
| /** | | /** | |
| * | | * | |
| * addShard will create a new shard in the grid. It expects a mongo
d process to be runing | | * addShard will create a new shard in the grid. It expects a mongo
d process to be runing | |
|
| * on the provided address. | | * on the provided address. Adding a shard that is a replica set is | |
| * TODO - add the mongod's databases to the grid | | supported. | |
| * | | * | |
| * @param name is an optional string with the name of the shard. if
ommited, grid will | | * @param name is an optional string with the name of the shard. if
ommited, grid will | |
| * generate one and update the parameter. | | * generate one and update the parameter. | |
|
| * @param host is the complete address of the machine where the sha
rd will be | | * @param servers is the connection string of the shard being added | |
| * @param maxSize is the optional space quota in bytes. Zeros means
there's no limitation to | | * @param maxSize is the optional space quota in bytes. Zeros means
there's no limitation to | |
| * space usage | | * space usage | |
| * @param errMsg is the error description in case the operation fai
led. | | * @param errMsg is the error description in case the operation fai
led. | |
| * @return true if shard was successfully added. | | * @return true if shard was successfully added. | |
| */ | | */ | |
|
| bool addShard( string* name , const string& host , long long maxSiz
e , string& errMsg ); | | bool addShard( string* name , const ConnectionString& servers , lon
g long maxSize , string& errMsg ); | |
| | | | |
| /** | | /** | |
| * @return true if the config database knows about a host 'name' | | * @return true if the config database knows about a host 'name' | |
| */ | | */ | |
| bool knowAboutShard( const string& name ) const; | | bool knowAboutShard( const string& name ) const; | |
| | | | |
| /** | | /** | |
| * @return true if the chunk balancing functionality is enabled | | * @return true if the chunk balancing functionality is enabled | |
| */ | | */ | |
| bool shouldBalance() const; | | bool shouldBalance() const; | |
| | | | |
End of changes. 3 change blocks. |
| 4 lines changed or deleted | | 4 lines changed or added | |
|
| lasterror.h | | lasterror.h | |
| | | | |
| skipping to change at line 35 | | skipping to change at line 35 | |
| | | | |
| struct LastError { | | struct LastError { | |
| int code; | | int code; | |
| string msg; | | string msg; | |
| enum UpdatedExistingType { NotUpdate, True, False } updatedExisting
; | | enum UpdatedExistingType { NotUpdate, True, False } updatedExisting
; | |
| OID upsertedId; | | OID upsertedId; | |
| OID writebackId; | | OID writebackId; | |
| long long nObjects; | | long long nObjects; | |
| int nPrev; | | int nPrev; | |
| bool valid; | | bool valid; | |
|
| bool overridenById; | | | |
| bool disabled; | | bool disabled; | |
| void writeback( OID& oid ){ | | void writeback( OID& oid ){ | |
| reset( true ); | | reset( true ); | |
| writebackId = oid; | | writebackId = oid; | |
| } | | } | |
| void raiseError(int _code , const char *_msg) { | | void raiseError(int _code , const char *_msg) { | |
| reset( true ); | | reset( true ); | |
| code = _code; | | code = _code; | |
| msg = _msg; | | msg = _msg; | |
| } | | } | |
| | | | |
| skipping to change at line 59 | | skipping to change at line 58 | |
| updatedExisting = _updateObjects ? True : False; | | updatedExisting = _updateObjects ? True : False; | |
| if ( _upsertedId.isSet() ) | | if ( _upsertedId.isSet() ) | |
| upsertedId = _upsertedId; | | upsertedId = _upsertedId; | |
| | | | |
| } | | } | |
| void recordDelete( long long nDeleted ) { | | void recordDelete( long long nDeleted ) { | |
| reset( true ); | | reset( true ); | |
| nObjects = nDeleted; | | nObjects = nDeleted; | |
| } | | } | |
| LastError() { | | LastError() { | |
|
| overridenById = false; | | | |
| reset(); | | reset(); | |
| } | | } | |
| void reset( bool _valid = false ) { | | void reset( bool _valid = false ) { | |
| code = 0; | | code = 0; | |
| msg.clear(); | | msg.clear(); | |
| updatedExisting = NotUpdate; | | updatedExisting = NotUpdate; | |
| nObjects = 0; | | nObjects = 0; | |
| nPrev = 1; | | nPrev = 1; | |
| valid = _valid; | | valid = _valid; | |
| disabled = false; | | disabled = false; | |
| | | | |
| skipping to change at line 130 | | skipping to change at line 128 | |
| * id of 0 means should use thread local management | | * id of 0 means should use thread local management | |
| */ | | */ | |
| void setID( int id ); | | void setID( int id ); | |
| int getID(); | | int getID(); | |
| | | | |
| void remove( int id ); | | void remove( int id ); | |
| void release(); | | void release(); | |
| | | | |
| /** when db receives a message/request, call this */ | | /** when db receives a message/request, call this */ | |
| void startRequest( Message& m , LastError * connectionOwned ); | | void startRequest( Message& m , LastError * connectionOwned ); | |
|
| LastError * startRequest( Message& m , int clientId = 0 ); | | LastError * startRequest( Message& m , int clientId ); | |
| | | | |
| void disconnect( int clientId ); | | void disconnect( int clientId ); | |
| | | | |
| // used to disable lastError reporting while processing a killCurso
rs message | | // used to disable lastError reporting while processing a killCurso
rs message | |
| // disable causes get() to return 0. | | // disable causes get() to return 0. | |
| LastError *disableForCommand(); // only call once per command invoc
ation! | | LastError *disableForCommand(); // only call once per command invoc
ation! | |
| private: | | private: | |
| ThreadLocalValue<int> _id; | | ThreadLocalValue<int> _id; | |
| boost::thread_specific_ptr<LastError> _tl; | | boost::thread_specific_ptr<LastError> _tl; | |
| | | | |
| | | | |
End of changes. 3 change blocks. |
| 3 lines changed or deleted | | 1 lines changed or added | |
|
| scanandorder.h | | scanandorder.h | |
| | | | |
| skipping to change at line 91 | | skipping to change at line 91 | |
| typedef multimap<BSONObj,BSONObj,BSONObjCmp> BestMap; | | typedef multimap<BSONObj,BSONObj,BSONObjCmp> BestMap; | |
| class ScanAndOrder { | | class ScanAndOrder { | |
| BestMap best; // key -> full object | | BestMap best; // key -> full object | |
| int startFrom; | | int startFrom; | |
| int limit; // max to send back. | | int limit; // max to send back. | |
| KeyType order; | | KeyType order; | |
| unsigned approxSize; | | unsigned approxSize; | |
| | | | |
| void _add(BSONObj& k, BSONObj o, DiskLoc* loc) { | | void _add(BSONObj& k, BSONObj o, DiskLoc* loc) { | |
| if (!loc){ | | if (!loc){ | |
|
| best.insert(make_pair(k,o)); | | best.insert(make_pair(k.getOwned(),o.getOwned())); | |
| } else { | | } else { | |
| BSONObjBuilder b; | | BSONObjBuilder b; | |
| b.appendElements(o); | | b.appendElements(o); | |
| b.append("$diskLoc", loc->toBSONObj()); | | b.append("$diskLoc", loc->toBSONObj()); | |
|
| best.insert(make_pair(k, b.obj())); | | best.insert(make_pair(k.getOwned(), b.obj().getOwned())); | |
| } | | } | |
| } | | } | |
| | | | |
| void _addIfBetter(BSONObj& k, BSONObj o, BestMap::iterator i, DiskL
oc* loc) { | | void _addIfBetter(BSONObj& k, BSONObj o, BestMap::iterator i, DiskL
oc* loc) { | |
|
| | | /* todo : we don't correct approxSize here. */ | |
| const BSONObj& worstBestKey = i->first; | | const BSONObj& worstBestKey = i->first; | |
| int c = worstBestKey.woCompare(k, order.pattern); | | int c = worstBestKey.woCompare(k, order.pattern); | |
| if ( c > 0 ) { | | if ( c > 0 ) { | |
| // k is better, 'upgrade' | | // k is better, 'upgrade' | |
| best.erase(i); | | best.erase(i); | |
| _add(k, o, loc); | | _add(k, o, loc); | |
| } | | } | |
| } | | } | |
| | | | |
| public: | | public: | |
| | | | |
| skipping to change at line 127 | | skipping to change at line 128 | |
| | | | |
| int size() const { | | int size() const { | |
| return best.size(); | | return best.size(); | |
| } | | } | |
| | | | |
| void add(BSONObj o, DiskLoc* loc) { | | void add(BSONObj o, DiskLoc* loc) { | |
| assert( o.isValid() ); | | assert( o.isValid() ); | |
| BSONObj k = order.getKeyFromObject(o); | | BSONObj k = order.getKeyFromObject(o); | |
| if ( (int) best.size() < limit ) { | | if ( (int) best.size() < limit ) { | |
| approxSize += k.objsize(); | | approxSize += k.objsize(); | |
|
| uassert( 10128 , "too much key data for sort() with no ind | | approxSize += o.objsize(); | |
| ex. add an index or specify a smaller limit", approxSize < 1 * 1024 * 1024 | | | |
| ); | | /* note : adjust when bson return limit adjusts. note this | |
| | | limit should be a bit higher. */ | |
| | | uassert( 10128 , "too much data for sort() with no index. | |
| | | add an index or specify a smaller limit", approxSize < 32 * 1024 * 1024 ); | |
| | | | |
| _add(k, o, loc); | | _add(k, o, loc); | |
| return; | | return; | |
| } | | } | |
| BestMap::iterator i; | | BestMap::iterator i; | |
| assert( best.end() != best.begin() ); | | assert( best.end() != best.begin() ); | |
| i = best.end(); | | i = best.end(); | |
| i--; | | i--; | |
| _addIfBetter(k, o, i, loc); | | _addIfBetter(k, o, i, loc); | |
| } | | } | |
| | | | |
| | | | |
End of changes. 4 change blocks. |
| 5 lines changed or deleted | | 10 lines changed or added | |
|