| assert_util.h | | assert_util.h | |
| | | | |
| skipping to change at line 84 | | skipping to change at line 84 | |
| | | | |
| int regular; | | int regular; | |
| int warning; | | int warning; | |
| int msg; | | int msg; | |
| int user; | | int user; | |
| int rollovers; | | int rollovers; | |
| }; | | }; | |
| | | | |
| extern AssertionCount assertionCount; | | extern AssertionCount assertionCount; | |
| | | | |
|
| | | struct ExceptionInfo { | |
| | | ExceptionInfo() : msg(""),code(-1){} | |
| | | ExceptionInfo( const char * m , int c ) | |
| | | : msg( m ) , code( c ){ | |
| | | } | |
| | | ExceptionInfo( const string& m , int c ) | |
| | | : msg( m ) , code( c ){ | |
| | | } | |
| | | | |
| | | void append( BSONObjBuilder& b , const char * m = "$err" , const ch | |
| | | ar * c = "code" ) const ; | |
| | | | |
| | | operator string() const { stringstream ss; ss << "exception: " << c | |
| | | ode << " " << msg; return ss.str(); } | |
| | | | |
| | | bool empty() const { return msg.empty(); } | |
| | | | |
| | | string msg; | |
| | | int code; | |
| | | }; | |
| | | | |
| class DBException : public std::exception { | | class DBException : public std::exception { | |
| public: | | public: | |
|
| virtual const char* what() const throw() = 0; | | DBException( const ExceptionInfo& ei ) : _ei(ei){} | |
| | | DBException( const char * msg , int code ) : _ei(msg,code){} | |
| | | DBException( const string& msg , int code ) : _ei(msg,code){} | |
| | | virtual ~DBException() throw() { } | |
| | | | |
| | | virtual const char* what() const throw(){ return _ei.msg.c_str(); } | |
| | | virtual int getCode() const { return _ei.code; } | |
| | | | |
| | | virtual void appendPrefix( stringstream& ss ) const { } | |
| | | | |
| virtual string toString() const { | | virtual string toString() const { | |
|
| return what(); | | stringstream ss; ss << getCode() << " " << what(); return ss.st | |
| | | r(); | |
| | | return ss.str(); | |
| } | | } | |
|
| virtual int getCode() const = 0; | | | |
| operator string() const { stringstream ss; ss << getCode() << " " < | | operator string() const { return toString(); } | |
| < what(); return ss.str(); } | | | |
| | | const ExceptionInfo& getInfo() const { return _ei; } | |
| | | | |
| | | protected: | |
| | | ExceptionInfo _ei; | |
| }; | | }; | |
| | | | |
| class AssertionException : public DBException { | | class AssertionException : public DBException { | |
| public: | | public: | |
|
| int code; | | | |
| string msg; | | AssertionException( const ExceptionInfo& ei ) : DBException(ei){} | |
| AssertionException() { code = 0; } | | AssertionException( const char * msg , int code ) : DBException(msg | |
| | | ,code){} | |
| | | AssertionException( const string& msg , int code ) : DBException(ms | |
| | | g,code){} | |
| | | | |
| virtual ~AssertionException() throw() { } | | virtual ~AssertionException() throw() { } | |
|
| virtual bool severe() { | | | |
| return true; | | virtual bool severe() { return true; } | |
| } | | virtual bool isUserAssertion() { return false; } | |
| virtual bool isUserAssertion() { | | | |
| return false; | | | |
| } | | | |
| virtual int getCode() const { return code; } | | | |
| virtual const char* what() const throw() { return msg.c_str(); } | | | |
| | | | |
| /* true if an interrupted exception - see KillCurrentOp */ | | /* true if an interrupted exception - see KillCurrentOp */ | |
| bool interrupted() { | | bool interrupted() { | |
|
| return code == 11600 || code == 11601; | | return _ei.code == 11600 || _ei.code == 11601; | |
| } | | } | |
| }; | | }; | |
| | | | |
| /* UserExceptions are valid errors that a user can cause, like out of d
isk space or duplicate key */ | | /* UserExceptions are valid errors that a user can cause, like out of d
isk space or duplicate key */ | |
| class UserException : public AssertionException { | | class UserException : public AssertionException { | |
| public: | | public: | |
|
| UserException(int c , const string& m) { | | UserException(int c , const string& m) : AssertionException( m , c | |
| code = c; | | ){} | |
| msg = m; | | | |
| } | | virtual bool severe() { return false; } | |
| virtual bool severe() { | | virtual bool isUserAssertion() { return true; } | |
| return false; | | virtual void appendPrefix( stringstream& ss ) const { ss << "useras | |
| } | | sert:"; } | |
| virtual bool isUserAssertion() { | | | |
| return true; | | | |
| } | | | |
| virtual string toString() const { | | | |
| return "userassert:" + msg; | | | |
| } | | | |
| }; | | }; | |
| | | | |
| class MsgAssertionException : public AssertionException { | | class MsgAssertionException : public AssertionException { | |
| public: | | public: | |
|
| MsgAssertionException(int c, const char *m) { | | MsgAssertionException( const ExceptionInfo& ei ) : AssertionExcepti | |
| code = c; | | on( ei ){} | |
| msg = m; | | MsgAssertionException(int c, const string& m) : AssertionException( | |
| } | | m , c ){} | |
| MsgAssertionException(int c, const string& m) { | | virtual bool severe() { return false; } | |
| code = c; | | virtual void appendPrefix( stringstream& ss ) const { ss << "masser | |
| msg = m; | | t:"; } | |
| } | | | |
| virtual bool severe() { | | | |
| return false; | | | |
| } | | | |
| virtual string toString() const { | | | |
| return "massert:" + msg; | | | |
| } | | | |
| }; | | }; | |
| | | | |
| void asserted(const char *msg, const char *file, unsigned line); | | void asserted(const char *msg, const char *file, unsigned line); | |
| void wasserted(const char *msg, const char *file, unsigned line); | | void wasserted(const char *msg, const char *file, unsigned line); | |
| void uasserted(int msgid, const char *msg); | | void uasserted(int msgid, const char *msg); | |
| inline void uasserted(int msgid , string msg) { uasserted(msgid, msg.c_
str()); } | | inline void uasserted(int msgid , string msg) { uasserted(msgid, msg.c_
str()); } | |
| void uassert_nothrow(const char *msg); // reported via lasterror, but d
on't throw exception | | void uassert_nothrow(const char *msg); // reported via lasterror, but d
on't throw exception | |
| void msgassertedNoTrace(int msgid, const char *msg); | | void msgassertedNoTrace(int msgid, const char *msg); | |
| void msgasserted(int msgid, const char *msg); | | void msgasserted(int msgid, const char *msg); | |
| inline void msgasserted(int msgid, string msg) { msgasserted(msgid, msg
.c_str()); } | | inline void msgasserted(int msgid, string msg) { msgasserted(msgid, msg
.c_str()); } | |
| | | | |
End of changes. 9 change blocks. |
| 44 lines changed or deleted | | 66 lines changed or added | |
|
| balancer_policy.h | | balancer_policy.h | |
| | | | |
| skipping to change at line 43 | | skipping to change at line 43 | |
| * moving, it returns NULL. | | * moving, it returns NULL. | |
| * | | * | |
| * @param ns is the collections namepace. | | * @param ns is the collections namepace. | |
| * @param shardLimitMap is a map from shardId to an object that des
cribes (for now) space | | * @param shardLimitMap is a map from shardId to an object that des
cribes (for now) space | |
| * cap and usage. E.g.: { "maxSize" : <size_in_MB> , "usedSize" : <
size_in_MB> }. | | * cap and usage. E.g.: { "maxSize" : <size_in_MB> , "usedSize" : <
size_in_MB> }. | |
| * @param shardToChunksMap is a map from shardId to chunks that liv
e there. A chunk's format | | * @param shardToChunksMap is a map from shardId to chunks that liv
e there. A chunk's format | |
| * is { }. | | * is { }. | |
| * @param balancedLastTime is the number of chunks effectively move
d in the last round. | | * @param balancedLastTime is the number of chunks effectively move
d in the last round. | |
| * @returns NULL or ChunkInfo of the best move to make towards bala
cing the collection. | | * @returns NULL or ChunkInfo of the best move to make towards bala
cing the collection. | |
| */ | | */ | |
|
| static ChunkInfo* balance( const string& ns, const map< string, BSO | | typedef map< string,BSONObj > ShardToLimitsMap; | |
| NObj>& shardLimitsMap, | | typedef map< string,vector<BSONObj> > ShardToChunksMap; | |
| const map< string,vector<BSONObj> >& sha | | static ChunkInfo* balance( const string& ns, const ShardToLimitsMap | |
| rdToChunksMap, int balancedLastTime ); | | & shardToLimitsMap, | |
| | | const ShardToChunksMap& shardToChunksMap | |
| | | , int balancedLastTime ); | |
| | | | |
| // below exposed for testing purposes only -- treat it as private -
- | | // below exposed for testing purposes only -- treat it as private -
- | |
| | | | |
| static BSONObj pickChunk( const vector<BSONObj>& from, const vector
<BSONObj>& to ); | | static BSONObj pickChunk( const vector<BSONObj>& from, const vector
<BSONObj>& to ); | |
| | | | |
| /** | | /** | |
|
| * Returns true if a shard can receive new chunks based on that sha | | * Returns true if a shard cannot receive any new chunks bacause it | |
| rd's 'shardLimits' information. | | reache 'shardLimits'. | |
| * Expects the optional fields "maxSize", can in size in MB, and "u | | * Expects the optional fields "maxSize", can in size in MB, and "u | |
| sedSize", currently used size in MB, | | sedSize", currently used size | |
| * on 'shardLimits'. | | * in MB, on 'shardLimits'. | |
| */ | | */ | |
|
| static bool isReceiver( BSONObj shardLimits ); | | static bool isSizeMaxed( BSONObj shardLimits ); | |
| | | | |
| /** | | /** | |
|
| * Returns true if 'shardLimist' contains a field "draining". | | * Returns true if 'shardLimist' contains a field "draining". Expec | |
| | | ts the optional field | |
| | | * "isDraining" on 'shrdLimits'. | |
| */ | | */ | |
| static bool isDraining( BSONObj shardLimits ); | | static bool isDraining( BSONObj shardLimits ); | |
|
| | | | |
| | | private: | |
| | | // Convenience types | |
| | | typedef ShardToChunksMap::const_iterator ShardToChunksIter; | |
| | | typedef ShardToLimitsMap::const_iterator ShardToLimitsIter; | |
| | | | |
| }; | | }; | |
| | | | |
| struct BalancerPolicy::ChunkInfo { | | struct BalancerPolicy::ChunkInfo { | |
| const string ns; | | const string ns; | |
| const string to; | | const string to; | |
| const string from; | | const string from; | |
| const BSONObj chunk; | | const BSONObj chunk; | |
| | | | |
| ChunkInfo( const string& a_ns , const string& a_to , const string&
a_from , const BSONObj& a_chunk ) | | ChunkInfo( const string& a_ns , const string& a_to , const string&
a_from , const BSONObj& a_chunk ) | |
| : ns( a_ns ) , to( a_to ) , from( a_from ), chunk( a_chunk ){} | | : ns( a_ns ) , to( a_to ) , from( a_from ), chunk( a_chunk ){} | |
| | | | |
End of changes. 5 change blocks. |
| 11 lines changed or deleted | | 21 lines changed or added | |
|
| bsonelement.h | | bsonelement.h | |
| | | | |
| skipping to change at line 21 | | skipping to change at line 21 | |
| * Unless required by applicable law or agreed to in writing, software | | * Unless required by applicable law or agreed to in writing, software | |
| * distributed under the License is distributed on an "AS IS" BASIS, | | * distributed under the License is distributed on an "AS IS" BASIS, | |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or impli
ed. | | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or impli
ed. | |
| * See the License for the specific language governing permissions and | | * See the License for the specific language governing permissions and | |
| * limitations under the License. | | * limitations under the License. | |
| */ | | */ | |
| | | | |
| #pragma once | | #pragma once | |
| | | | |
| #include <vector> | | #include <vector> | |
|
| | | #include <string.h> | |
| | | | |
| namespace bson { | | namespace bson { | |
| typedef mongo::BSONElement be; | | typedef mongo::BSONElement be; | |
| typedef mongo::BSONObj bo; | | typedef mongo::BSONObj bo; | |
| typedef mongo::BSONObjBuilder bob; | | typedef mongo::BSONObjBuilder bob; | |
| } | | } | |
| | | | |
| namespace mongo { | | namespace mongo { | |
| | | | |
| class OpTime; | | class OpTime; | |
|
| | | class BSONElement; | |
| | | | |
| | | /* l and r MUST have same type when called: check that first. */ | |
| | | int compareElementValues(const BSONElement& l, const BSONElement& r); | |
| | | | |
| /** BSONElement represents an "element" in a BSONObj. So for the object {
a : 3, b : "abc" }, | | /** BSONElement represents an "element" in a BSONObj. So for the object {
a : 3, b : "abc" }, | |
| 'a : 3' is the first element (key+value). | | 'a : 3' is the first element (key+value). | |
| | | | |
| The BSONElement object points into the BSONObj's data. Thus the BSONOb
j must stay in scope | | The BSONElement object points into the BSONObj's data. Thus the BSONOb
j must stay in scope | |
| for the life of the BSONElement. | | for the life of the BSONElement. | |
| | | | |
| internals: | | internals: | |
| <type><fieldName ><value> | | <type><fieldName ><value> | |
| -------- size() ------------ | | -------- size() ------------ | |
| | | | |
| skipping to change at line 213 | | skipping to change at line 218 | |
| */ | | */ | |
| const char * valuestr() const { | | const char * valuestr() const { | |
| return value() + 4; | | return value() + 4; | |
| } | | } | |
| | | | |
| /** Get the string value of the element. If not a string returns "". *
/ | | /** Get the string value of the element. If not a string returns "". *
/ | |
| const char *valuestrsafe() const { | | const char *valuestrsafe() const { | |
| return type() == mongo::String ? valuestr() : ""; | | return type() == mongo::String ? valuestr() : ""; | |
| } | | } | |
| /** Get the string value of the element. If not a string returns "". *
/ | | /** Get the string value of the element. If not a string returns "". *
/ | |
|
| string str() const { return valuestrsafe(); } | | string str() const { | |
| | | return type() == mongo::String ? string(valuestr(), valuestrsize()- | |
| | | 1) : string(); | |
| | | } | |
| | | | |
| /** Get javascript code of a CodeWScope data element. */ | | /** Get javascript code of a CodeWScope data element. */ | |
| const char * codeWScopeCode() const { | | const char * codeWScopeCode() const { | |
| return value() + 8; | | return value() + 8; | |
| } | | } | |
| /** Get the scope SavedContext of a CodeWScope data element. */ | | /** Get the scope SavedContext of a CodeWScope data element. */ | |
| const char * codeWScopeScopeData() const { | | const char * codeWScopeScopeData() const { | |
| // TODO fix | | // TODO fix | |
| return codeWScopeCode() + strlen( codeWScopeCode() ) + 1; | | return codeWScopeCode() + strlen( codeWScopeCode() ) + 1; | |
| } | | } | |
| | | | |
| skipping to change at line 384 | | skipping to change at line 391 | |
| int fieldNameSize() const { | | int fieldNameSize() const { | |
| if ( fieldNameSize_ == -1 ) | | if ( fieldNameSize_ == -1 ) | |
| fieldNameSize_ = (int)strlen( fieldName() ) + 1; | | fieldNameSize_ = (int)strlen( fieldName() ) + 1; | |
| return fieldNameSize_; | | return fieldNameSize_; | |
| } | | } | |
| mutable int totalSize; /* caches the computed size */ | | mutable int totalSize; /* caches the computed size */ | |
| | | | |
| friend class BSONObjIterator; | | friend class BSONObjIterator; | |
| friend class BSONObj; | | friend class BSONObj; | |
| const BSONElement& chk(int t) const { | | const BSONElement& chk(int t) const { | |
|
| uassert(13111, "unexpected or missing type value in BSON object", t | | if ( t != type() ){ | |
| == type()); | | stringstream ss; | |
| | | ss << "wrong type for BSONElement (" << fieldName() << ") " << | |
| | | type() << " != " << t; | |
| | | uasserted(13111, ss.str() ); | |
| | | } | |
| return *this; | | return *this; | |
| } | | } | |
| const BSONElement& chk(bool expr) const { | | const BSONElement& chk(bool expr) const { | |
| uassert(13118, "unexpected or missing type value in BSON object", e
xpr); | | uassert(13118, "unexpected or missing type value in BSON object", e
xpr); | |
| return *this; | | return *this; | |
| } | | } | |
| }; | | }; | |
| | | | |
| inline int BSONElement::canonicalType() const { | | inline int BSONElement::canonicalType() const { | |
| BSONType t = type(); | | BSONType t = type(); | |
| | | | |
End of changes. 4 change blocks. |
| 3 lines changed or deleted | | 15 lines changed or added | |
|
| bsoninlines.h | | bsoninlines.h | |
| | | | |
| skipping to change at line 275 | | skipping to change at line 275 | |
| msgasserted( 10321 , buf.str() ); | | msgasserted( 10321 , buf.str() ); | |
| break; | | break; | |
| } | | } | |
| case CodeWScope: { | | case CodeWScope: { | |
| int totalSize = *( int * )( value() ); | | int totalSize = *( int * )( value() ); | |
| massert( 10322 , "Invalid CodeWScope size", totalSize >= 8 ); | | massert( 10322 , "Invalid CodeWScope size", totalSize >= 8 ); | |
| int strSizeWNull = *( int * )( value() + 4 ); | | int strSizeWNull = *( int * )( value() + 4 ); | |
| massert( 10323 , "Invalid CodeWScope string size", totalSize >
= strSizeWNull + 4 + 4 ); | | massert( 10323 , "Invalid CodeWScope string size", totalSize >
= strSizeWNull + 4 + 4 ); | |
| massert( 10324 , "Invalid CodeWScope string size", | | massert( 10324 , "Invalid CodeWScope string size", | |
| strSizeWNull > 0 && | | strSizeWNull > 0 && | |
|
| strSizeWNull - 1 == strnlen( codeWScopeCode(), strSize
WNull ) ); | | (strSizeWNull - 1) == strnlen( codeWScopeCode(), strSi
zeWNull ) ); | |
| massert( 10325 , "Invalid CodeWScope size", totalSize >= strSi
zeWNull + 4 + 4 + 4 ); | | massert( 10325 , "Invalid CodeWScope size", totalSize >= strSi
zeWNull + 4 + 4 + 4 ); | |
| int objSize = *( int * )( value() + 4 + 4 + strSizeWNull ); | | int objSize = *( int * )( value() + 4 + 4 + strSizeWNull ); | |
| massert( 10326 , "Invalid CodeWScope object size", totalSize =
= 4 + 4 + strSizeWNull + objSize ); | | massert( 10326 , "Invalid CodeWScope object size", totalSize =
= 4 + 4 + strSizeWNull + objSize ); | |
| // Subobject validation handled elsewhere. | | // Subobject validation handled elsewhere. | |
| } | | } | |
| case Object: | | case Object: | |
| // We expect Object size validation to be handled elsewhere. | | // We expect Object size validation to be handled elsewhere. | |
| default: | | default: | |
| break; | | break; | |
| } | | } | |
| | | | |
| skipping to change at line 425 | | skipping to change at line 425 | |
| s << "MaxKey"; | | s << "MaxKey"; | |
| break; | | break; | |
| case MinKey: | | case MinKey: | |
| s << "MinKey"; | | s << "MinKey"; | |
| break; | | break; | |
| case CodeWScope: | | case CodeWScope: | |
| s << "CodeWScope( " | | s << "CodeWScope( " | |
| << codeWScopeCode() << ", " << codeWScopeObject().toString(
) << ")"; | | << codeWScopeCode() << ", " << codeWScopeObject().toString(
) << ")"; | |
| break; | | break; | |
| case Code: | | case Code: | |
|
| if ( valuestrsize() > 80 ) | | if ( valuestrsize() > 80 ) { | |
| s << string(valuestr()).substr(0, 70) << "..."; | | s.write(valuestr(), 70); | |
| else { | | s << "..."; | |
| s << valuestr(); | | } else { | |
| | | s.write(valuestr(), valuestrsize()-1); | |
| } | | } | |
| break; | | break; | |
| case Symbol: | | case Symbol: | |
| case mongo::String: | | case mongo::String: | |
|
| if ( valuestrsize() > 80 ) | | s << '"'; | |
| s << '"' << string(valuestr()).substr(0, 70) << "...\""; | | if ( valuestrsize() > 80 ) { | |
| else { | | s.write(valuestr(), 70); | |
| s << '"' << valuestr() << '"'; | | s << "...\""; | |
| | | } else { | |
| | | s.write(valuestr(), valuestrsize()-1); | |
| | | s << '"'; | |
| } | | } | |
| break; | | break; | |
| case DBRef: | | case DBRef: | |
| s << "DBRef('" << valuestr() << "',"; | | s << "DBRef('" << valuestr() << "',"; | |
| { | | { | |
| mongo::OID *x = (mongo::OID *) (valuestr() + valuestrsize()
); | | mongo::OID *x = (mongo::OID *) (valuestr() + valuestrsize()
); | |
| s << *x << ')'; | | s << *x << ')'; | |
| } | | } | |
| break; | | break; | |
| case jstOID: | | case jstOID: | |
| | | | |
| skipping to change at line 574 | | skipping to change at line 578 | |
| | | | |
| inline ostream& operator<<( ostream &s, const BSONObj &o ) { | | inline ostream& operator<<( ostream &s, const BSONObj &o ) { | |
| return s << o.toString(); | | return s << o.toString(); | |
| } | | } | |
| | | | |
| inline ostream& operator<<( ostream &s, const BSONElement &e ) { | | inline ostream& operator<<( ostream &s, const BSONElement &e ) { | |
| return s << e.toString(); | | return s << e.toString(); | |
| } | | } | |
| | | | |
| inline void BSONElement::Val(BSONObj& v) const { v = Obj(); } | | inline void BSONElement::Val(BSONObj& v) const { v = Obj(); } | |
|
| | | | |
| | | template<typename T> | |
| | | inline BSONFieldValue<BSONObj> BSONField<T>::query( const char * q , co | |
| | | nst T& t ) const { | |
| | | BSONObjBuilder b; | |
| | | b.append( q , t ); | |
| | | return BSONFieldValue<BSONObj>( _name , b.obj() ); | |
| | | } | |
| } | | } | |
| | | | |
End of changes. 4 change blocks. |
| 9 lines changed or deleted | | 21 lines changed or added | |
|
| bsonobj.h | | bsonobj.h | |
| | | | |
| skipping to change at line 94 | | skipping to change at line 94 | |
| b.append(reinterpret_cast<const void *>( objdata() ), objsize()
); | | b.append(reinterpret_cast<const void *>( objdata() ), objsize()
); | |
| } | | } | |
| | | | |
| /** Readable representation of a BSON object in an extended JSON-st
yle notation. | | /** Readable representation of a BSON object in an extended JSON-st
yle notation. | |
| This is an abbreviated representation which might be used for l
ogging. | | This is an abbreviated representation which might be used for l
ogging. | |
| */ | | */ | |
| string toString( bool isArray = false ) const; | | string toString( bool isArray = false ) const; | |
| operator string() const { return toString(); } | | operator string() const { return toString(); } | |
| | | | |
| /** Properly formatted JSON string. | | /** Properly formatted JSON string. | |
|
| @param pretty if tru1 we try to add some lf's and indentation | | @param pretty if true we try to add some lf's and indentation | |
| */ | | */ | |
| string jsonString( JsonStringFormat format = Strict, int pretty = 0
) const; | | string jsonString( JsonStringFormat format = Strict, int pretty = 0
) const; | |
| | | | |
| /** note: addFields always adds _id even if not specified */ | | /** note: addFields always adds _id even if not specified */ | |
| int addFields(BSONObj& from, set<string>& fields); /* returns n add
ed */ | | int addFields(BSONObj& from, set<string>& fields); /* returns n add
ed */ | |
| | | | |
| /** returns # of top level fields in the object | | /** returns # of top level fields in the object | |
| note: iterates to count the fields | | note: iterates to count the fields | |
| */ | | */ | |
| int nFields() const; | | int nFields() const; | |
| | | | |
| /** adds the field names to the fields set. does NOT clear it (app
ends). */ | | /** adds the field names to the fields set. does NOT clear it (app
ends). */ | |
| int getFieldNames(set<string>& fields) const; | | int getFieldNames(set<string>& fields) const; | |
| | | | |
| /** return has eoo() true if no match | | /** return has eoo() true if no match | |
| supports "." notation to reach into embedded objects | | supports "." notation to reach into embedded objects | |
| */ | | */ | |
| BSONElement getFieldDotted(const char *name) const; | | BSONElement getFieldDotted(const char *name) const; | |
|
| | | /** return has eoo() true if no match | |
| | | supports "." notation to reach into embedded objects | |
| | | */ | |
| | | BSONElement getFieldDotted(const string& name) const { | |
| | | return getFieldDotted( name.c_str() ); | |
| | | } | |
| | | | |
| /** Like getFieldDotted(), but expands multikey arrays and returns
all matching objects | | /** Like getFieldDotted(), but expands multikey arrays and returns
all matching objects | |
| */ | | */ | |
| void getFieldsDotted(const char *name, BSONElementSet &ret ) const; | | void getFieldsDotted(const char *name, BSONElementSet &ret ) const; | |
| /** Like getFieldDotted(), but returns first array encountered whil
e traversing the | | /** Like getFieldDotted(), but returns first array encountered whil
e traversing the | |
| dotted fields of name. The name variable is updated to represe
nt field | | dotted fields of name. The name variable is updated to represe
nt field | |
| names with respect to the returned element. */ | | names with respect to the returned element. */ | |
| BSONElement getFieldDottedOrArray(const char *&name) const; | | BSONElement getFieldDottedOrArray(const char *&name) const; | |
| | | | |
| /** Get the field of the specified name. eoo() is true on the retur
ned | | /** Get the field of the specified name. eoo() is true on the retur
ned | |
| element if not found. | | element if not found. | |
| | | | |
| skipping to change at line 240 | | skipping to change at line 247 | |
| bool considerFieldName=true) const; | | bool considerFieldName=true) const; | |
| | | | |
| /**wo='well ordered'. fields must be in same order in each object. | | /**wo='well ordered'. fields must be in same order in each object. | |
| Ordering is with respect to the signs of the elements | | Ordering is with respect to the signs of the elements | |
| and allows ascending / descending key mixing. | | and allows ascending / descending key mixing. | |
| @return <0 if l<r. 0 if l==r. >0 if l>r | | @return <0 if l<r. 0 if l==r. >0 if l>r | |
| */ | | */ | |
| int woCompare(const BSONObj& r, const BSONObj &ordering = BSONObj()
, | | int woCompare(const BSONObj& r, const BSONObj &ordering = BSONObj()
, | |
| bool considerFieldName=true) const; | | bool considerFieldName=true) const; | |
| | | | |
|
| int woSortOrder( const BSONObj& r , const BSONObj& sortKey ) const; | | /** | |
| | | * @param useDotted whether to treat sort key fields as possibly do | |
| | | tted and expand into them | |
| | | */ | |
| | | int woSortOrder( const BSONObj& r , const BSONObj& sortKey , bool u | |
| | | seDotted=false ) const; | |
| | | | |
| /** This is "shallow equality" -- ints and doubles won't match. fo
r a | | /** This is "shallow equality" -- ints and doubles won't match. fo
r a | |
| deep equality test use woCompare (which is slower). | | deep equality test use woCompare (which is slower). | |
| */ | | */ | |
| bool woEqual(const BSONObj& r) const { | | bool woEqual(const BSONObj& r) const { | |
| int os = objsize(); | | int os = objsize(); | |
| if ( os == r.objsize() ) { | | if ( os == r.objsize() ) { | |
| return (os == 0 || memcmp(objdata(),r.objdata(),os)==0); | | return (os == 0 || memcmp(objdata(),r.objdata(),os)==0); | |
| } | | } | |
| return false; | | return false; | |
| | | | |
End of changes. 3 change blocks. |
| 2 lines changed or deleted | | 14 lines changed or added | |
|
| bsonobjbuilder.h | | bsonobjbuilder.h | |
| | | | |
| skipping to change at line 36 | | skipping to change at line 36 | |
| #include <cmath> | | #include <cmath> | |
| using namespace std; | | using namespace std; | |
| | | | |
| namespace mongo { | | namespace mongo { | |
| | | | |
| #if defined(_WIN32) | | #if defined(_WIN32) | |
| // warning: 'this' : used in base member initializer list | | // warning: 'this' : used in base member initializer list | |
| #pragma warning( disable : 4355 ) | | #pragma warning( disable : 4355 ) | |
| #endif | | #endif | |
| | | | |
|
| | | template<typename T> | |
| | | class BSONFieldValue { | |
| | | public: | |
| | | BSONFieldValue( const string& name , const T& t ){ | |
| | | _name = name; | |
| | | _t = t; | |
| | | } | |
| | | | |
| | | const T& value() const { return _t; } | |
| | | const string& name() const { return _name; } | |
| | | | |
| | | private: | |
| | | string _name; | |
| | | T _t; | |
| | | }; | |
| | | | |
| | | template<typename T> | |
| | | class BSONField { | |
| | | public: | |
| | | BSONField( const string& name , const string& longName="" ) | |
| | | : _name(name), _longName(longName){} | |
| | | const string& name() const { return _name; } | |
| | | operator string() const { return _name; } | |
| | | | |
| | | BSONFieldValue<T> make( const T& t ) const { | |
| | | return BSONFieldValue<T>( _name , t ); | |
| | | } | |
| | | | |
| | | BSONFieldValue<BSONObj> gt( const T& t ) const { return query( "$gt | |
| | | " , t ); } | |
| | | BSONFieldValue<BSONObj> lt( const T& t ) const { return query( "$lt | |
| | | " , t ); } | |
| | | | |
| | | BSONFieldValue<BSONObj> query( const char * q , const T& t ) const; | |
| | | | |
| | | BSONFieldValue<T> operator()( const T& t ) const { | |
| | | return BSONFieldValue<T>( _name , t ); | |
| | | } | |
| | | | |
| | | private: | |
| | | string _name; | |
| | | string _longName; | |
| | | }; | |
| | | | |
| /** Utility for creating a BSONObj. | | /** Utility for creating a BSONObj. | |
| See also the BSON() and BSON_ARRAY() macros. | | See also the BSON() and BSON_ARRAY() macros. | |
| */ | | */ | |
| class BSONObjBuilder : boost::noncopyable { | | class BSONObjBuilder : boost::noncopyable { | |
| public: | | public: | |
| /** @param initsize this is just a hint as to the final size of the
object */ | | /** @param initsize this is just a hint as to the final size of the
object */ | |
| BSONObjBuilder(int initsize=512) : _b(_buf), _buf(initsize), _offse
t( 0 ), _s( this ) , _tracker(0) , _doneCalled(false) { | | BSONObjBuilder(int initsize=512) : _b(_buf), _buf(initsize), _offse
t( 0 ), _s( this ) , _tracker(0) , _doneCalled(false) { | |
| _b.skip(4); /*leave room for size field*/ | | _b.skip(4); /*leave room for size field*/ | |
| } | | } | |
| | | | |
| | | | |
| skipping to change at line 313 | | skipping to change at line 355 | |
| BSONObjBuilder& appendRegex(string fieldName, string regex, string
options = "") { | | BSONObjBuilder& appendRegex(string fieldName, string regex, string
options = "") { | |
| return appendRegex(fieldName.c_str(), regex.c_str(), options.c_
str()); | | return appendRegex(fieldName.c_str(), regex.c_str(), options.c_
str()); | |
| } | | } | |
| BSONObjBuilder& appendCode(const char *fieldName, const char *code)
{ | | BSONObjBuilder& appendCode(const char *fieldName, const char *code)
{ | |
| _b.append((char) Code); | | _b.append((char) Code); | |
| _b.append(fieldName); | | _b.append(fieldName); | |
| _b.append((int) strlen(code)+1); | | _b.append((int) strlen(code)+1); | |
| _b.append(code); | | _b.append(code); | |
| return *this; | | return *this; | |
| } | | } | |
|
| /** Append a string element */ | | /** Append a string element. len DOES include terminating nul */ | |
| BSONObjBuilder& append(const char *fieldName, const char *str) { | | BSONObjBuilder& append(const char *fieldName, const char *str, int | |
| | | len) { | |
| _b.append((char) String); | | _b.append((char) String); | |
| _b.append(fieldName); | | _b.append(fieldName); | |
|
| _b.append((int) strlen(str)+1); | | _b.append((int)len); | |
| _b.append(str); | | _b.append(str, len); | |
| return *this; | | return *this; | |
| } | | } | |
| /** Append a string element */ | | /** Append a string element */ | |
|
| | | BSONObjBuilder& append(const char *fieldName, const char *str) { | |
| | | return append(fieldName, str, (int) strlen(str)+1); | |
| | | } | |
| | | /** Append a string element */ | |
| BSONObjBuilder& append(const char *fieldName, string str) { | | BSONObjBuilder& append(const char *fieldName, string str) { | |
|
| return append(fieldName, str.c_str()); | | return append(fieldName, str.c_str(), (int) str.size()+1); | |
| } | | } | |
| BSONObjBuilder& appendSymbol(const char *fieldName, const char *sym
bol) { | | BSONObjBuilder& appendSymbol(const char *fieldName, const char *sym
bol) { | |
| _b.append((char) Symbol); | | _b.append((char) Symbol); | |
| _b.append(fieldName); | | _b.append(fieldName); | |
| _b.append((int) strlen(symbol)+1); | | _b.append((int) strlen(symbol)+1); | |
| _b.append(symbol); | | _b.append(symbol); | |
| return *this; } | | return *this; } | |
| | | | |
| /** Append a Null element to the object */ | | /** Append a Null element to the object */ | |
| BSONObjBuilder& appendNull( const char *fieldName ) { | | BSONObjBuilder& appendNull( const char *fieldName ) { | |
| | | | |
| skipping to change at line 530 | | skipping to change at line 576 | |
| /** Stream oriented way to add field names and values. */ | | /** Stream oriented way to add field names and values. */ | |
| BSONObjBuilderValueStream &operator<<( const ForceExplicitString& n
ame ) { | | BSONObjBuilderValueStream &operator<<( const ForceExplicitString& n
ame ) { | |
| return operator<<( name.str_.c_str() ); | | return operator<<( name.str_.c_str() ); | |
| } | | } | |
| | | | |
| Labeler operator<<( const Labeler::Label &l ) { | | Labeler operator<<( const Labeler::Label &l ) { | |
| massert( 10336 , "No subobject started", _s.subobjStarted() ); | | massert( 10336 , "No subobject started", _s.subobjStarted() ); | |
| return _s << l; | | return _s << l; | |
| } | | } | |
| | | | |
|
| | | template<typename T> | |
| | | BSONObjBuilderValueStream& operator<<( const BSONField<T>& f ) { | |
| | | _s.endField( f.name().c_str() ); | |
| | | return _s; | |
| | | } | |
| | | | |
| | | template<typename T> | |
| | | BSONObjBuilder& operator<<( const BSONFieldValue<T>& v ) { | |
| | | append( v.name().c_str() , v.value() ); | |
| | | return *this; | |
| | | } | |
| | | | |
| /** @return true if we are using our own bufbuilder, and not an alt
ernate that was given to us in our constructor */ | | /** @return true if we are using our own bufbuilder, and not an alt
ernate that was given to us in our constructor */ | |
| bool owned() const { return &_b == &_buf; } | | bool owned() const { return &_b == &_buf; } | |
| | | | |
| BSONObjIterator iterator() const ; | | BSONObjIterator iterator() const ; | |
| | | | |
| private: | | private: | |
| char* _done() { | | char* _done() { | |
| if ( _doneCalled ) | | if ( _doneCalled ) | |
| return _b.buf() + _offset; | | return _b.buf() + _offset; | |
| | | | |
| | | | |
End of changes. 6 change blocks. |
| 5 lines changed or deleted | | 66 lines changed or added | |
|
| btree.h | | btree.h | |
| | | | |
| skipping to change at line 87 | | skipping to change at line 87 | |
| class BucketBasics { | | class BucketBasics { | |
| friend class BtreeBuilder; | | friend class BtreeBuilder; | |
| friend class KeyNode; | | friend class KeyNode; | |
| public: | | public: | |
| void dumpTree(DiskLoc thisLoc, const BSONObj &order); | | void dumpTree(DiskLoc thisLoc, const BSONObj &order); | |
| bool isHead() { return parent.isNull(); } | | bool isHead() { return parent.isNull(); } | |
| void assertValid(const Ordering &order, bool force = false); | | void assertValid(const Ordering &order, bool force = false); | |
| void assertValid(const BSONObj &orderObj, bool force = false) { | | void assertValid(const BSONObj &orderObj, bool force = false) { | |
| return assertValid(Ordering::make(orderObj),force); | | return assertValid(Ordering::make(orderObj),force); | |
| } | | } | |
|
| int fullValidate(const DiskLoc& thisLoc, const BSONObj &order); /*
traverses everything */ | | int fullValidate(const DiskLoc& thisLoc, const BSONObj &order, int
*unusedCount = 0); /* traverses everything */ | |
| | | | |
| KeyNode keyNode(int i) const { | | KeyNode keyNode(int i) const { | |
| if ( i >= n ){ | | if ( i >= n ){ | |
| massert( 13000 , (string)"invalid keyNode: " + BSON( "i" <
< i << "n" << n ).jsonString() , i < n ); | | massert( 13000 , (string)"invalid keyNode: " + BSON( "i" <
< i << "n" << n ).jsonString() , i < n ); | |
| } | | } | |
| return KeyNode(*this, k(i)); | | return KeyNode(*this, k(i)); | |
| } | | } | |
| | | | |
| protected: | | protected: | |
| | | | |
| | | | |
| skipping to change at line 109 | | skipping to change at line 109 | |
| | | | |
| char * dataAt(short ofs) { | | char * dataAt(short ofs) { | |
| return data + ofs; | | return data + ofs; | |
| } | | } | |
| | | | |
| void init(); // initialize a new node | | void init(); // initialize a new node | |
| | | | |
| /* returns false if node is full and must be split | | /* returns false if node is full and must be split | |
| keypos is where to insert -- inserted after that key #. so keyp
os=0 is the leftmost one. | | keypos is where to insert -- inserted after that key #. so keyp
os=0 is the leftmost one. | |
| */ | | */ | |
|
| bool basicInsert(const DiskLoc& thisLoc, int keypos, const DiskLoc&
recordLoc, const BSONObj& key, const Ordering &order); | | bool basicInsert(const DiskLoc& thisLoc, int &keypos, const DiskLoc
& recordLoc, const BSONObj& key, const Ordering &order); | |
| | | | |
| /** | | /** | |
| * @return true if works, false if not enough space | | * @return true if works, false if not enough space | |
| */ | | */ | |
| bool _pushBack(const DiskLoc& recordLoc, BSONObj& key, const Orderi
ng &order, DiskLoc prevChild); | | bool _pushBack(const DiskLoc& recordLoc, BSONObj& key, const Orderi
ng &order, DiskLoc prevChild); | |
| void pushBack(const DiskLoc& recordLoc, BSONObj& key, const Orderin
g &order, DiskLoc prevChild){ | | void pushBack(const DiskLoc& recordLoc, BSONObj& key, const Orderin
g &order, DiskLoc prevChild){ | |
| bool ok = _pushBack( recordLoc , key , order , prevChild ); | | bool ok = _pushBack( recordLoc , key , order , prevChild ); | |
| assert(ok); | | assert(ok); | |
| } | | } | |
| void popBack(DiskLoc& recLoc, BSONObj& key); | | void popBack(DiskLoc& recLoc, BSONObj& key); | |
| | | | |
| skipping to change at line 133 | | skipping to change at line 133 | |
| We "repack" when we run out of space before considering the node | | We "repack" when we run out of space before considering the node | |
| to be full. | | to be full. | |
| */ | | */ | |
| enum Flags { Packed=1 }; | | enum Flags { Packed=1 }; | |
| | | | |
| DiskLoc& childForPos(int p) { | | DiskLoc& childForPos(int p) { | |
| return p == n ? nextChild : k(p).prevChildBucket; | | return p == n ? nextChild : k(p).prevChildBucket; | |
| } | | } | |
| | | | |
| int totalDataSize() const; | | int totalDataSize() const; | |
|
| void pack( const Ordering &order ); | | void pack( const Ordering &order, int &refPos); | |
| void setNotPacked(); | | void setNotPacked(); | |
| void setPacked(); | | void setPacked(); | |
| int _alloc(int bytes); | | int _alloc(int bytes); | |
| void _unalloc(int bytes); | | void _unalloc(int bytes); | |
|
| void truncateTo(int N, const Ordering &order); | | void truncateTo(int N, const Ordering &order, int &refPos); | |
| void markUnused(int keypos); | | void markUnused(int keypos); | |
| | | | |
| /* BtreeBuilder uses the parent var as a temp place to maintain a l
inked list chain. | | /* BtreeBuilder uses the parent var as a temp place to maintain a l
inked list chain. | |
| we use tempNext() when we do that to be less confusing. (one mig
ht have written a union in C) | | we use tempNext() when we do that to be less confusing. (one mig
ht have written a union in C) | |
| */ | | */ | |
| DiskLoc& tempNext() { return parent; } | | DiskLoc& tempNext() { return parent; } | |
| | | | |
| public: | | public: | |
| DiskLoc parent; | | DiskLoc parent; | |
| | | | |
| | | | |
| skipping to change at line 365 | | skipping to change at line 365 | |
| } | | } | |
| | | | |
| void forgetEndKey() { endKey = BSONObj(); } | | void forgetEndKey() { endKey = BSONObj(); } | |
| | | | |
| virtual CoveredIndexMatcher *matcher() const { return _matcher.get(
); } | | virtual CoveredIndexMatcher *matcher() const { return _matcher.get(
); } | |
| | | | |
| virtual void setMatcher( shared_ptr< CoveredIndexMatcher > matcher
) { | | virtual void setMatcher( shared_ptr< CoveredIndexMatcher > matcher
) { | |
| _matcher = matcher; | | _matcher = matcher; | |
| } | | } | |
| | | | |
|
| | | // for debugging only | |
| | | DiskLoc getBucket() const { return bucket; } | |
| | | | |
| private: | | private: | |
| /* Our btrees may (rarely) have "unused" keys when items are delete
d. | | /* Our btrees may (rarely) have "unused" keys when items are delete
d. | |
| Skip past them. | | Skip past them. | |
| */ | | */ | |
| void skipUnusedKeys(); | | void skipUnusedKeys(); | |
| | | | |
| /* Check if the current key is beyond endKey. */ | | /* Check if the current key is beyond endKey. */ | |
| void checkEnd(); | | void checkEnd(); | |
| | | | |
| // selective audits on construction | | // selective audits on construction | |
| | | | |
End of changes. 5 change blocks. |
| 4 lines changed or deleted | | 7 lines changed or added | |
|
| chunk.h | | chunk.h | |
| | | | |
| skipping to change at line 43 | | skipping to change at line 43 | |
| | | | |
| namespace mongo { | | namespace mongo { | |
| | | | |
| class DBConfig; | | class DBConfig; | |
| class Chunk; | | class Chunk; | |
| class ChunkRange; | | class ChunkRange; | |
| class ChunkManager; | | class ChunkManager; | |
| class ChunkRangeMangager; | | class ChunkRangeMangager; | |
| class ChunkObjUnitTest; | | class ChunkObjUnitTest; | |
| | | | |
|
| typedef unsigned long long ShardChunkVersion; | | struct ShardChunkVersion { | |
| | | union { | |
| | | struct { | |
| | | int _minor; | |
| | | int _major; | |
| | | }; | |
| | | unsigned long long _combined; | |
| | | }; | |
| | | | |
| | | ShardChunkVersion( int major=0, int minor=0 ) | |
| | | : _minor(minor),_major(major){ | |
| | | } | |
| | | | |
| | | ShardChunkVersion( unsigned long long ll ) | |
| | | : _combined( ll ){ | |
| | | } | |
| | | | |
| | | ShardChunkVersion incMajor() const { | |
| | | return ShardChunkVersion( _major + 1 , 0 ); | |
| | | } | |
| | | | |
| | | void operator++(){ | |
| | | _minor++; | |
| | | } | |
| | | | |
| | | unsigned long long toLong() const { | |
| | | return _combined; | |
| | | } | |
| | | | |
| | | bool isSet() const { | |
| | | return _combined > 0; | |
| | | } | |
| | | | |
| | | string toString() const { | |
| | | stringstream ss; | |
| | | ss << _major << "|" << _minor; | |
| | | return ss.str(); | |
| | | } | |
| | | | |
| | | operator unsigned long long() const { return _combined; } | |
| | | operator string() const { return toString(); } | |
| | | | |
| | | ShardChunkVersion& operator=( const BSONElement& elem ){ | |
| | | switch ( elem.type() ){ | |
| | | case Timestamp: | |
| | | case NumberLong: | |
| | | case Date: | |
| | | _combined = elem._numberLong(); | |
| | | break; | |
| | | case EOO: | |
| | | _combined = 0; | |
| | | break; | |
| | | default: | |
| | | assert(0); | |
| | | } | |
| | | return *this; | |
| | | } | |
| | | }; | |
| | | | |
| typedef shared_ptr<Chunk> ChunkPtr; | | typedef shared_ptr<Chunk> ChunkPtr; | |
| | | | |
| // key is max for each Chunk or ChunkRange | | // key is max for each Chunk or ChunkRange | |
| typedef map<BSONObj,ChunkPtr,BSONObjCmp> ChunkMap; | | typedef map<BSONObj,ChunkPtr,BSONObjCmp> ChunkMap; | |
| typedef map<BSONObj,shared_ptr<ChunkRange>,BSONObjCmp> ChunkRangeMap; | | typedef map<BSONObj,shared_ptr<ChunkRange>,BSONObjCmp> ChunkRangeMap; | |
| | | | |
| /** | | /** | |
| config.chunks | | config.chunks | |
| { ns : "alleyinsider.fs.chunks" , min : {} , max : {} , server : "lo
calhost:30001" } | | { ns : "alleyinsider.fs.chunks" , min : {} , max : {} , server : "lo
calhost:30001" } | |
| | | | |
| x is in a shard iff | | x is in a shard iff | |
| min <= x < max | | min <= x < max | |
| */ | | */ | |
|
| class Chunk : public Model , boost::noncopyable, public boost::enable_s
hared_from_this<Chunk> { | | class Chunk : boost::noncopyable, public boost::enable_shared_from_this
<Chunk> { | |
| public: | | public: | |
| | | | |
| Chunk( ChunkManager * info ); | | Chunk( ChunkManager * info ); | |
|
| | | Chunk( ChunkManager * info , const BSONObj& min, const BSONObj& max
, const Shard& shard); | |
| | | | |
| const BSONObj& getMin() const { return _min; } | | const BSONObj& getMin() const { return _min; } | |
| const BSONObj& getMax() const { return _max; } | | const BSONObj& getMax() const { return _max; } | |
| | | | |
| void setMin(const BSONObj& o){ | | void setMin(const BSONObj& o){ | |
| _min = o; | | _min = o; | |
| } | | } | |
| void setMax(const BSONObj& o){ | | void setMax(const BSONObj& o){ | |
| _max = o; | | _max = o; | |
| } | | } | |
| | | | |
|
| Shard getShard() const{ | | string getns() const; | |
| return _shard; | | Shard getShard() const { return _shard; } | |
| } | | | |
| void setShard( const Shard& shard ); | | void setShard( const Shard& shard ); | |
| | | | |
| bool contains( const BSONObj& obj ) const; | | bool contains( const BSONObj& obj ) const; | |
| | | | |
| string toString() const; | | string toString() const; | |
| operator string() const { return toString(); } | | operator string() const { return toString(); } | |
| friend ostream& operator << (ostream& out, const Chunk& c){ return
(out << c.toString()); } | | friend ostream& operator << (ostream& out, const Chunk& c){ return
(out << c.toString()); } | |
| | | | |
| bool operator==(const Chunk& s) const; | | bool operator==(const Chunk& s) const; | |
| | | | |
| | | | |
| skipping to change at line 122 | | skipping to change at line 181 | |
| bool splitIfShould( long dataWritten ); | | bool splitIfShould( long dataWritten ); | |
| | | | |
| /* | | /* | |
| * moves either this shard or newShard if it makes sense too | | * moves either this shard or newShard if it makes sense too | |
| * @return whether or not a shard was moved | | * @return whether or not a shard was moved | |
| */ | | */ | |
| bool moveIfShould( ChunkPtr newShard = ChunkPtr() ); | | bool moveIfShould( ChunkPtr newShard = ChunkPtr() ); | |
| | | | |
| bool moveAndCommit( const Shard& to , string& errmsg ); | | bool moveAndCommit( const Shard& to , string& errmsg ); | |
| | | | |
|
| virtual const char * getNS(){ return "config.chunks"; } | | const char * getNS(){ return "config.chunks"; } | |
| virtual void serialize(BSONObjBuilder& to); | | void serialize(BSONObjBuilder& to, ShardChunkVersion myLastMod=0); | |
| virtual void unserialize(const BSONObj& from); | | void unserialize(const BSONObj& from); | |
| virtual string modelServer(); | | string modelServer(); | |
| | | | |
| void appendShortVersion( const char * name , BSONObjBuilder& b ); | | void appendShortVersion( const char * name , BSONObjBuilder& b ); | |
| | | | |
|
| virtual void save( bool check=false ); | | | |
| | | | |
| void ensureIndex(); | | void ensureIndex(); | |
| | | | |
| void _markModified(); | | void _markModified(); | |
| | | | |
| static int MaxChunkSize; | | static int MaxChunkSize; | |
| | | | |
|
| | | string genID(); | |
| static string genID( const string& ns , const BSONObj& min ); | | static string genID( const string& ns , const BSONObj& min ); | |
| | | | |
| const ChunkManager* getManager() const { return _manager; } | | const ChunkManager* getManager() const { return _manager; } | |
| | | | |
|
| | | bool modified(); | |
| private: | | private: | |
| | | | |
| // main shard info | | // main shard info | |
| | | | |
| ChunkManager * _manager; | | ChunkManager * _manager; | |
| ShardKeyPattern skey() const; | | ShardKeyPattern skey() const; | |
| | | | |
|
| string _ns; | | | |
| BSONObj _min; | | BSONObj _min; | |
| BSONObj _max; | | BSONObj _max; | |
| Shard _shard; | | Shard _shard; | |
| ShardChunkVersion _lastmod; | | ShardChunkVersion _lastmod; | |
| | | | |
| bool _modified; | | bool _modified; | |
| | | | |
| // transient stuff | | // transient stuff | |
| | | | |
| long _dataWritten; | | long _dataWritten; | |
| | | | |
| skipping to change at line 254 | | skipping to change at line 312 | |
| key: { ts : 1 } , | | key: { ts : 1 } , | |
| shards: [ { min: 1, max: 100, server: a } , { min: 101, max: 200
, server : b } ] | | shards: [ { min: 1, max: 100, server: a } , { min: 101, max: 200
, server : b } ] | |
| } | | } | |
| */ | | */ | |
| class ChunkManager { | | class ChunkManager { | |
| public: | | public: | |
| | | | |
| ChunkManager( DBConfig * config , string ns , ShardKeyPattern patte
rn , bool unique ); | | ChunkManager( DBConfig * config , string ns , ShardKeyPattern patte
rn , bool unique ); | |
| virtual ~ChunkManager(); | | virtual ~ChunkManager(); | |
| | | | |
|
| string getns() const { | | string getns() const { return _ns; } | |
| return _ns; | | | |
| } | | | |
| | | | |
|
| int numChunks(){ rwlock lk( _lock , false ); return _chunks.size(); | | int numChunks(){ rwlock lk( _lock , false ); return _chunkMap.size( | |
| } | | ); } | |
| ChunkPtr getChunk( int i ){ rwlock lk( _lock , false ); return _chu | | | |
| nks[i]; } | | | |
| bool hasShardKey( const BSONObj& obj ); | | bool hasShardKey( const BSONObj& obj ); | |
| | | | |
| ChunkPtr findChunk( const BSONObj& obj , bool retry = false ); | | ChunkPtr findChunk( const BSONObj& obj , bool retry = false ); | |
| ChunkPtr findChunkOnServer( const Shard& shard ) const; | | ChunkPtr findChunkOnServer( const Shard& shard ) const; | |
| | | | |
| ShardKeyPattern& getShardKey(){ return _key; } | | ShardKeyPattern& getShardKey(){ return _key; } | |
| const ShardKeyPattern& getShardKey() const { return _key; } | | const ShardKeyPattern& getShardKey() const { return _key; } | |
| bool isUnique(){ return _unique; } | | bool isUnique(){ return _unique; } | |
| | | | |
| /** | | /** | |
| | | | |
| skipping to change at line 306 | | skipping to change at line 361 | |
| */ | | */ | |
| unsigned long long getSequenceNumber(){ | | unsigned long long getSequenceNumber(){ | |
| return _sequenceNumber; | | return _sequenceNumber; | |
| } | | } | |
| | | | |
| /** | | /** | |
| * @param me - so i don't get deleted before i'm done | | * @param me - so i don't get deleted before i'm done | |
| */ | | */ | |
| void drop( ChunkManagerPtr me ); | | void drop( ChunkManagerPtr me ); | |
| | | | |
|
| | | void _printChunks() const; | |
| | | | |
| private: | | private: | |
| | | | |
| void _reload(); | | void _reload(); | |
| void _reload_inlock(); | | void _reload_inlock(); | |
| void _load(); | | void _load(); | |
| | | | |
|
| | | void save_inlock(); | |
| | | ShardChunkVersion getVersion_inlock() const; | |
| | | void ensureIndex_inlock(); | |
| | | | |
| DBConfig * _config; | | DBConfig * _config; | |
| string _ns; | | string _ns; | |
| ShardKeyPattern _key; | | ShardKeyPattern _key; | |
| bool _unique; | | bool _unique; | |
| | | | |
|
| vector<ChunkPtr> _chunks; | | | |
| map<string,unsigned long long> _maxMarkers; | | map<string,unsigned long long> _maxMarkers; | |
| | | | |
| ChunkMap _chunkMap; | | ChunkMap _chunkMap; | |
| ChunkRangeManager _chunkRanges; | | ChunkRangeManager _chunkRanges; | |
| | | | |
|
| | | set<Shard> _shards; | |
| | | | |
| unsigned long long _sequenceNumber; | | unsigned long long _sequenceNumber; | |
| | | | |
| RWLock _lock; | | RWLock _lock; | |
| | | | |
| // This should only be called from Chunk after it has been migrated | | // This should only be called from Chunk after it has been migrated | |
| void _migrationNotification(Chunk* c); | | void _migrationNotification(Chunk* c); | |
| | | | |
| friend class Chunk; | | friend class Chunk; | |
| friend class ChunkRangeManager; // only needed for CRM::assertValid
() | | friend class ChunkRangeManager; // only needed for CRM::assertValid
() | |
| static AtomicUInt NextSequenceNumber; | | static AtomicUInt NextSequenceNumber; | |
| | | | |
| bool _isValid() const; | | bool _isValid() const; | |
|
| void _printChunks() const; | | | |
| | | | |
| /** | | /** | |
| * @return number of Chunk matching the query or -1 for all chunks. | | * @return number of Chunk matching the query or -1 for all chunks. | |
| */ | | */ | |
| int _getChunksForQuery( vector<shared_ptr<ChunkRange> >& chunks , c
onst BSONObj& query ); | | int _getChunksForQuery( vector<shared_ptr<ChunkRange> >& chunks , c
onst BSONObj& query ); | |
| }; | | }; | |
| | | | |
| // like BSONObjCmp. for use as an STL comparison functor | | // like BSONObjCmp. for use as an STL comparison functor | |
| // key-order in "order" argument must match key-order in shardkey | | // key-order in "order" argument must match key-order in shardkey | |
| class ChunkCmp { | | class ChunkCmp { | |
| | | | |
| skipping to change at line 366 | | skipping to change at line 427 | |
| bool operator()( const ChunkRange &l, const ChunkRange &r ) const { | | bool operator()( const ChunkRange &l, const ChunkRange &r ) const { | |
| return _cmp(l.getMin(), r.getMin()); | | return _cmp(l.getMin(), r.getMin()); | |
| } | | } | |
| bool operator()( const shared_ptr<ChunkRange> l, const shared_ptr<C
hunkRange> r ) const { | | bool operator()( const shared_ptr<ChunkRange> l, const shared_ptr<C
hunkRange> r ) const { | |
| return operator()(*l, *r); | | return operator()(*l, *r); | |
| } | | } | |
| private: | | private: | |
| BSONObjCmp _cmp; | | BSONObjCmp _cmp; | |
| }; | | }; | |
| | | | |
|
| | | /* | |
| | | struct chunk_lock { | |
| | | chunk_lock( const Chunk* c ){ | |
| | | | |
| | | } | |
| | | | |
| | | Chunk _c; | |
| | | }; | |
| | | */ | |
| | | inline string Chunk::genID(){ return genID(_manager->getns(), _min); } | |
| | | | |
| } // namespace mongo | | } // namespace mongo | |
| | | | |
End of changes. 17 change blocks. |
| 21 lines changed or deleted | | 92 lines changed or added | |
|
| client.h | | client.h | |
| | | | |
| skipping to change at line 32 | | skipping to change at line 32 | |
| todo: switch to asio...this will fit nicely with that. | | todo: switch to asio...this will fit nicely with that. | |
| */ | | */ | |
| | | | |
| #pragma once | | #pragma once | |
| | | | |
| #include "../pch.h" | | #include "../pch.h" | |
| #include "security.h" | | #include "security.h" | |
| #include "namespace.h" | | #include "namespace.h" | |
| #include "lasterror.h" | | #include "lasterror.h" | |
| #include "stats/top.h" | | #include "stats/top.h" | |
|
| #include "repl/rs.h" | | //#include "repl/rs.h" | |
| | | | |
| namespace mongo { | | namespace mongo { | |
| | | | |
|
| | | extern class ReplSet *theReplSet; | |
| | | | |
| class AuthenticationInfo; | | class AuthenticationInfo; | |
| class Database; | | class Database; | |
| class CurOp; | | class CurOp; | |
| class Command; | | class Command; | |
| class Client; | | class Client; | |
| | | | |
| extern boost::thread_specific_ptr<Client> currentClient; | | extern boost::thread_specific_ptr<Client> currentClient; | |
| | | | |
| class Client : boost::noncopyable { | | class Client : boost::noncopyable { | |
| public: | | public: | |
| static mongo::mutex clientsMutex; | | static mongo::mutex clientsMutex; | |
| static set<Client*> clients; // always be in clientsMutex when mani
pulating this | | static set<Client*> clients; // always be in clientsMutex when mani
pulating this | |
| | | | |
|
| static int recommendedYieldMicros(); | | static int recommendedYieldMicros( int * writers = 0 , int * reader
s = 0 ); | |
| | | | |
| class GodScope { | | class GodScope { | |
| bool _prev; | | bool _prev; | |
| public: | | public: | |
| GodScope(); | | GodScope(); | |
| ~GodScope(); | | ~GodScope(); | |
| }; | | }; | |
| | | | |
| /* Set database we want to use, then, restores when we finish (are
out of scope) | | /* Set database we want to use, then, restores when we finish (are
out of scope) | |
| Note this is also helpful if an exception happens as the state i
f fixed up. | | Note this is also helpful if an exception happens as the state i
f fixed up. | |
| | | | |
| skipping to change at line 85 | | skipping to change at line 87 | |
| * this will set _db and create if needed | | * this will set _db and create if needed | |
| * will also set _client->_context to this | | * will also set _client->_context to this | |
| */ | | */ | |
| void _finishInit( bool doauth=true); | | void _finishInit( bool doauth=true); | |
| | | | |
| void _auth( int lockState = dbMutex.getState() ); | | void _auth( int lockState = dbMutex.getState() ); | |
| public: | | public: | |
| Context(const string& ns, string path=dbpath, mongolock * lock
= 0 , bool doauth=true ) | | Context(const string& ns, string path=dbpath, mongolock * lock
= 0 , bool doauth=true ) | |
| : _client( currentClient.get() ) , _oldContext( _client->_c
ontext ) , | | : _client( currentClient.get() ) , _oldContext( _client->_c
ontext ) , | |
| _path( path ) , _lock( lock ) , | | _path( path ) , _lock( lock ) , | |
|
| _ns( ns ){ | | _ns( ns ), _db(0){ | |
| _finishInit( doauth ); | | _finishInit( doauth ); | |
| } | | } | |
| | | | |
| /* this version saves the context but doesn't yet set the new o
ne: */ | | /* this version saves the context but doesn't yet set the new o
ne: */ | |
| | | | |
| Context() | | Context() | |
| : _client( currentClient.get() ) , _oldContext( _client->_c
ontext ), | | : _client( currentClient.get() ) , _oldContext( _client->_c
ontext ), | |
|
| _path( dbpath ) , _lock(0) , _justCreated(false){ | | _path( dbpath ) , _lock(0) , _justCreated(false), _db(0){ | |
| _client->_context = this; | | _client->_context = this; | |
| clear(); | | clear(); | |
| } | | } | |
| | | | |
| /** | | /** | |
| * if you are doing this after allowing a write there could be
a race condition | | * if you are doing this after allowing a write there could be
a race condition | |
| * if someone closes that db. this checks that the DB is still
valid | | * if someone closes that db. this checks that the DB is still
valid | |
| */ | | */ | |
| Context( string ns , Database * db, bool doauth=true ); | | Context( string ns , Database * db, bool doauth=true ); | |
| | | | |
| | | | |
End of changes. 5 change blocks. |
| 4 lines changed or deleted | | 6 lines changed or added | |
|
| clientcursor.h | | clientcursor.h | |
| | | | |
| skipping to change at line 64 | | skipping to change at line 64 | |
| 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; | |
| | | | |
| static CCById clientCursorsById; | | static CCById clientCursorsById; | |
| static CCByLoc byLoc; | | static CCByLoc byLoc; | |
| 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: | |
| /* 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. | |
| | | | |
| skipping to change at line 114 | | skipping to change at line 115 | |
| /*const*/ CursorId cursorid; | | /*const*/ CursorId cursorid; | |
| string ns; | | string ns; | |
| shared_ptr<Cursor> c; | | 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 | | int _queryOptions; // see enum QueryOptions dbclient.h | |
| OpTime _slaveReadTill; | | OpTime _slaveReadTill; | |
| | | | |
| ClientCursor(int queryOptions, shared_ptr<Cursor>& _c, const char *
_ns) : | | ClientCursor(int queryOptions, shared_ptr<Cursor>& _c, const char *
_ns) : | |
| _idleAgeMillis(0), _pinValue(0), | | _idleAgeMillis(0), _pinValue(0), | |
|
| _doingDeletes(false), | | _doingDeletes(false), _yieldSometimesTracker(128,10), | |
| ns(_ns), c(_c), | | ns(_ns), c(_c), | |
| pos(0), _queryOptions(queryOptions) | | pos(0), _queryOptions(queryOptions) | |
| { | | { | |
| 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(); | |
| | | | |
| skipping to change at line 140 | | skipping to change at line 141 | |
| shared_ptr< ParsedQuery > pq; | | shared_ptr< ParsedQuery > pq; | |
| shared_ptr< FieldMatcher > fields; // which fields query wants retu
rned | | shared_ptr< FieldMatcher > fields; // which fields query wants retu
rned | |
| Message originalMessage; // this is effectively an auto ptr for dat
a the matcher points to | | Message originalMessage; // this is effectively an auto ptr for dat
a the matcher points to | |
| | | | |
| /* Get rid of cursors for namespaces that begin with nsprefix. | | /* Get rid of cursors for namespaces that begin with nsprefix. | |
| Used by drop, dropIndexes, dropDatabase. | | Used by drop, dropIndexes, dropDatabase. | |
| */ | | */ | |
| static void invalidate(const char *nsPrefix); | | static void invalidate(const char *nsPrefix); | |
| | | | |
| /** | | /** | |
|
| | | * @param microsToSleep -1 : ask client | |
| | | * >=0 : sleep for that amount | |
| * do a dbtemprelease | | * do a dbtemprelease | |
| * note: caller should check matcher.docMatcher().atomic() first an
d not yield if atomic - | | * note: caller should check matcher.docMatcher().atomic() first an
d not yield if atomic - | |
| * we don't do herein as this->matcher (above) is only initia
lized for true queries/getmore. | | * we don't do herein as this->matcher (above) is only initia
lized for true queries/getmore. | |
| * (ie not set for remote/update) | | * (ie not set for remote/update) | |
| * @return if the cursor is still valid. | | * @return if the cursor is still valid. | |
| * if false is returned, then this ClientCursor should be c
onsidered deleted - | | * if false is returned, then this ClientCursor should be c
onsidered deleted - | |
| * in fact, the whole database could be gone. | | * in fact, the whole database could be gone. | |
| */ | | */ | |
|
| bool yield(); | | bool yield( int microsToSleep = -1 ); | |
| | | | |
| | | /** | |
| | | * @return same as yield() | |
| | | */ | |
| | | bool yieldSometimes(); | |
| | | | |
| struct YieldLock : boost::noncopyable { | | struct YieldLock : boost::noncopyable { | |
| explicit YieldLock( ptr<ClientCursor> cc ) | | explicit YieldLock( ptr<ClientCursor> cc ) | |
| : _cc( cc ) , _id( cc->cursorid ) , _doingDeletes( cc->_doi
ngDeletes ) { | | : _cc( cc ) , _id( cc->cursorid ) , _doingDeletes( cc->_doi
ngDeletes ) { | |
| cc->updateLocation(); | | cc->updateLocation(); | |
| _unlock.reset(new dbtempreleasecond()); | | _unlock.reset(new dbtempreleasecond()); | |
| } | | } | |
| ~YieldLock(){ | | ~YieldLock(){ | |
| assert( ! _unlock ); | | assert( ! _unlock ); | |
| } | | } | |
| | | | |
End of changes. 4 change blocks. |
| 2 lines changed or deleted | | 10 lines changed or added | |
|
| concurrency.h | | concurrency.h | |
| | | | |
| skipping to change at line 32 | | skipping to change at line 32 | |
| name level | | name level | |
| Logstream::mutex 1 | | Logstream::mutex 1 | |
| ClientCursor::ccmutex 2 | | ClientCursor::ccmutex 2 | |
| dblock 3 | | dblock 3 | |
| | | | |
| End func name with _inlock to indicate "caller must lock before callin
g". | | End func name with _inlock to indicate "caller must lock before callin
g". | |
| */ | | */ | |
| | | | |
| #pragma once | | #pragma once | |
| | | | |
|
| #include "../util/concurrency/locks.h" | | #include "../util/concurrency/rwlock.h" | |
| | | #include "../util/mmap.h" | |
| | | | |
| namespace mongo { | | namespace mongo { | |
| | | | |
|
| inline bool readLockSupported(){ | | | |
| return true; | | | |
| } | | | |
| | | | |
| string sayClientState(); | | string sayClientState(); | |
| bool haveClient(); | | bool haveClient(); | |
| | | | |
| void curopWaitingForLock( int type ); | | void curopWaitingForLock( int type ); | |
| void curopGotLock(); | | void curopGotLock(); | |
| | | | |
| /* mutex time stats */ | | /* mutex time stats */ | |
| class MutexInfo { | | class MutexInfo { | |
| unsigned long long start, enter, timeLocked; // all in microseconds | | unsigned long long start, enter, timeLocked; // all in microseconds | |
| int locked; | | int locked; | |
| | | | |
| skipping to change at line 97 | | skipping to change at line 94 | |
| ThreadLocalValue<bool> _releasedEarly; | | ThreadLocalValue<bool> _releasedEarly; | |
| public: | | public: | |
| MongoMutex(const char * name) : _m(name) { } | | MongoMutex(const char * name) : _m(name) { } | |
| | | | |
| /** | | /** | |
| * @return | | * @return | |
| * > 0 write lock | | * > 0 write lock | |
| * = 0 no lock | | * = 0 no lock | |
| * < 0 read lock | | * < 0 read lock | |
| */ | | */ | |
|
| int getState(){ return _state.get(); } | | int getState() { return _state.get(); } | |
| | | bool isWriteLocked() { return getState() > 0; } | |
| void assertWriteLocked() { | | void assertWriteLocked() { | |
| assert( getState() > 0 ); | | assert( getState() > 0 ); | |
| DEV assert( !_releasedEarly.get() ); | | DEV assert( !_releasedEarly.get() ); | |
| } | | } | |
| bool atLeastReadLocked() { return _state.get() != 0; } | | bool atLeastReadLocked() { return _state.get() != 0; } | |
| void assertAtLeastReadLocked() { assert(atLeastReadLocked()); } | | void assertAtLeastReadLocked() { assert(atLeastReadLocked()); } | |
| | | | |
| bool _checkWriteLockAlready(){ | | bool _checkWriteLockAlready(){ | |
| //DEV cout << "LOCK" << endl; | | //DEV cout << "LOCK" << endl; | |
| DEV assert( haveClient() ); | | DEV assert( haveClient() ); | |
| | | | |
| skipping to change at line 131 | | skipping to change at line 129 | |
| if ( _checkWriteLockAlready() ) | | if ( _checkWriteLockAlready() ) | |
| return; | | return; | |
| | | | |
| _state.set(1); | | _state.set(1); | |
| | | | |
| curopWaitingForLock( 1 ); | | curopWaitingForLock( 1 ); | |
| _m.lock(); | | _m.lock(); | |
| curopGotLock(); | | curopGotLock(); | |
| | | | |
| _minfo.entered(); | | _minfo.entered(); | |
|
| | | | |
| | | MongoFile::lockAll(); | |
| } | | } | |
| | | | |
| bool lock_try( int millis ) { | | bool lock_try( int millis ) { | |
| if ( _checkWriteLockAlready() ) | | if ( _checkWriteLockAlready() ) | |
| return true; | | return true; | |
| | | | |
| curopWaitingForLock( 1 ); | | curopWaitingForLock( 1 ); | |
| bool got = _m.lock_try( millis ); | | bool got = _m.lock_try( millis ); | |
| curopGotLock(); | | curopGotLock(); | |
| | | | |
| if ( got ){ | | if ( got ){ | |
| _minfo.entered(); | | _minfo.entered(); | |
| _state.set(1); | | _state.set(1); | |
|
| | | MongoFile::lockAll(); | |
| } | | } | |
| | | | |
| return got; | | return got; | |
| } | | } | |
| | | | |
| void unlock() { | | void unlock() { | |
| //DEV cout << "UNLOCK" << endl; | | //DEV cout << "UNLOCK" << endl; | |
| int s = _state.get(); | | int s = _state.get(); | |
| if( s > 1 ) { | | if( s > 1 ) { | |
| _state.set(s-1); | | _state.set(s-1); | |
| return; | | return; | |
| } | | } | |
| if( s != 1 ) { | | if( s != 1 ) { | |
| if( _releasedEarly.get() ) { | | if( _releasedEarly.get() ) { | |
| _releasedEarly.set(false); | | _releasedEarly.set(false); | |
| return; | | return; | |
| } | | } | |
| massert( 12599, "internal error: attempt to unlock when was
n't in a write lock", false); | | massert( 12599, "internal error: attempt to unlock when was
n't in a write lock", false); | |
| } | | } | |
|
| | | | |
| | | MongoFile::unlockAll(); | |
| | | | |
| _state.set(0); | | _state.set(0); | |
| _minfo.leaving(); | | _minfo.leaving(); | |
| _m.unlock(); | | _m.unlock(); | |
| } | | } | |
| | | | |
| /* unlock (write lock), and when unlock() is called later, | | /* unlock (write lock), and when unlock() is called later, | |
| be smart then and don't unlock it again. | | be smart then and don't unlock it again. | |
| */ | | */ | |
| void releaseEarly() { | | void releaseEarly() { | |
| assert( getState() == 1 ); // must not be recursive | | assert( getState() == 1 ); // must not be recursive | |
| | | | |
End of changes. 6 change blocks. |
| 6 lines changed or deleted | | 10 lines changed or added | |
|
| dbclient.h | | dbclient.h | |
| | | | |
| skipping to change at line 67 | | skipping to change at line 67 | |
| QueryOption_NoCursorTimeout = 1 << 4, | | QueryOption_NoCursorTimeout = 1 << 4, | |
| | | | |
| /** Use with QueryOption_CursorTailable. If we are at the end of t
he data, block for a while rather | | /** Use with QueryOption_CursorTailable. If we are at the end of t
he data, block for a while rather | |
| than returning no data. After a timeout period, we do return as
normal. | | than returning no data. After a timeout period, we do return as
normal. | |
| */ | | */ | |
| QueryOption_AwaitData = 1 << 5, | | QueryOption_AwaitData = 1 << 5, | |
| | | | |
| /** Stream the data down full blast in multiple "more" packages, on
the assumption that the client | | /** Stream the data down full blast in multiple "more" packages, on
the assumption that the client | |
| will fully read all data queried. Faster when you are pulling
a lot of data and know you want to | | will fully read all data queried. Faster when you are pulling
a lot of data and know you want to | |
| pull it all down. Note: it is not allowed to not read all the
data unless you close the connection. | | pull it all down. Note: it is not allowed to not read all the
data unless you close the connection. | |
|
| */ | | | |
| | | Use the query( boost::function<void(const BSONObj&)> f, ... ) v | |
| | | ersion of the connection's query() | |
| | | method, and it will take care of all the details for you. | |
| | | */ | |
| QueryOption_Exhaust = 1 << 6 | | QueryOption_Exhaust = 1 << 6 | |
| | | | |
| }; | | }; | |
| | | | |
| enum UpdateOptions { | | enum UpdateOptions { | |
| /** Upsert - that is, insert the item if no matching item is found.
*/ | | /** Upsert - that is, insert the item if no matching item is found.
*/ | |
| UpdateOption_Upsert = 1 << 0, | | UpdateOption_Upsert = 1 << 0, | |
| | | | |
| /** Update multiple documents (if multiple documents match query ex
pression). | | /** Update multiple documents (if multiple documents match query ex
pression). | |
| (Default is update a single document and stop.) */ | | (Default is update a single document and stop.) */ | |
| UpdateOption_Multi = 1 << 1 | | UpdateOption_Multi = 1 << 1 | |
| }; | | }; | |
| | | | |
|
| | | class DBClientBase; | |
| | | | |
| | | class ConnectionString { | |
| | | public: | |
| | | enum ConnectionType { MASTER , SET , SYNC }; | |
| | | | |
| | | ConnectionString( const HostAndPort& server ){ | |
| | | _type = MASTER; | |
| | | _servers.push_back( server ); | |
| | | _finishInit(); | |
| | | } | |
| | | | |
| | | ConnectionString( ConnectionType type , const vector<HostAndPort>& | |
| | | servers ) | |
| | | : _type( type ) , _servers( servers ){ | |
| | | _finishInit(); | |
| | | } | |
| | | | |
| | | ConnectionString( ConnectionType type , const string& s ){ | |
| | | _type = type; | |
| | | _fillServers( s ); | |
| | | | |
| | | switch ( _type ){ | |
| | | case MASTER: | |
| | | assert( _servers.size() == 1 ); | |
| | | break; | |
| | | default: | |
| | | assert( _servers.size() > 0 ); | |
| | | } | |
| | | | |
| | | _finishInit(); | |
| | | } | |
| | | | |
| | | ConnectionString( const string& s , ConnectionType favoredMultipleT | |
| | | ype ){ | |
| | | _fillServers( s ); | |
| | | if ( _servers.size() == 1 ){ | |
| | | _type = MASTER; | |
| | | } | |
| | | else { | |
| | | _type = favoredMultipleType; | |
| | | assert( _type != MASTER ); | |
| | | } | |
| | | _finishInit(); | |
| | | } | |
| | | | |
| | | string toString() const { | |
| | | return _string; | |
| | | } | |
| | | | |
| | | operator string() const { | |
| | | return toString(); | |
| | | } | |
| | | | |
| | | DBClientBase* connect( string& errmsg ) const; | |
| | | | |
| | | private: | |
| | | | |
| | | void _fillServers( string s ){ | |
| | | string::size_type idx; | |
| | | while ( ( idx = s.find( ',' ) ) != string::npos ){ | |
| | | _servers.push_back( s.substr( 0 , idx ) ); | |
| | | s = s.substr( idx + 1 ); | |
| | | } | |
| | | _servers.push_back( s ); | |
| | | } | |
| | | | |
| | | void _finishInit(){ | |
| | | stringstream ss; | |
| | | for ( unsigned i=0; i<_servers.size(); i++ ){ | |
| | | if ( i > 0 ) | |
| | | ss << ","; | |
| | | ss << _servers[i].toString(); | |
| | | } | |
| | | _string = ss.str(); | |
| | | } | |
| | | | |
| | | ConnectionType _type; | |
| | | vector<HostAndPort> _servers; | |
| | | string _string; | |
| | | }; | |
| | | | |
| /** | | /** | |
| * controls how much a clients cares about writes | | * controls how much a clients cares about writes | |
| * default is NORMAL | | * default is NORMAL | |
| */ | | */ | |
| enum WriteConcern { | | enum WriteConcern { | |
| W_NONE = 0 , // TODO: not every connection type fully supports this | | W_NONE = 0 , // TODO: not every connection type fully supports this | |
| W_NORMAL = 1 | | W_NORMAL = 1 | |
| // TODO SAFE = 2 | | // TODO SAFE = 2 | |
| }; | | }; | |
| | | | |
| | | | |
| skipping to change at line 216 | | skipping to change at line 299 | |
| | | | |
| /** | | /** | |
| 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; | |
|
| virtual void checkResponse( const string &data, int nReturned ) {} | | virtual void checkResponse( const char* data, int nReturned ) {} | |
| | | | |
| /* used by QueryOption_Exhaust. To use that your subclass must imp
lement this. */ | | /* used by QueryOption_Exhaust. To use that your subclass must imp
lement this. */ | |
| virtual void recv( Message& m ) { assert(false); } | | virtual void recv( Message& m ) { assert(false); } | |
| }; | | }; | |
| | | | |
| /** | | /** | |
| The interface that any db connection should implement | | The interface that any db connection should implement | |
| */ | | */ | |
| class DBClientInterface : boost::noncopyable { | | class DBClientInterface : boost::noncopyable { | |
| public: | | public: | |
| | | | |
| skipping to change at line 336 | | skipping to change at line 419 | |
| */ | | */ | |
| bool createCollection(const string &ns, long long size = 0, bool ca
pped = false, int max = 0, BSONObj *info = 0); | | bool createCollection(const string &ns, long long size = 0, bool ca
pped = false, int max = 0, BSONObj *info = 0); | |
| | | | |
| /** Get error result from the last operation on this connection. | | /** Get error result from the last operation on this connection. | |
| @return error message text, or empty string if no error. | | @return error message text, or empty string if no error. | |
| */ | | */ | |
| string getLastError(); | | string getLastError(); | |
| /** Get error result from the last operation on this connect
ion. | | /** Get error result from the last operation on this connect
ion. | |
| @return full error object. | | @return full error object. | |
| */ | | */ | |
|
| BSONObj getLastErrorDetailed(); | | virtual BSONObj getLastErrorDetailed(); | |
| | | | |
| static string getLastErrorString( const BSONObj& res ); | | static string getLastErrorString( const BSONObj& res ); | |
| | | | |
| /** Return the last error which has occurred, even if not the very
last operation. | | /** Return the last error which has occurred, even if not the very
last operation. | |
| | | | |
| @return { err : <error message>, nPrev : <how_many_ops_back_occu
rred>, ok : 1 } | | @return { err : <error message>, nPrev : <how_many_ops_back_occu
rred>, ok : 1 } | |
| | | | |
| result.err will be null if no error has occurred. | | result.err will be null if no error has occurred. | |
| */ | | */ | |
| BSONObj getPrevError(); | | BSONObj getPrevError(); | |
| | | | |
| skipping to change at line 831 | | skipping to change at line 914 | |
| /* this is the callback from our underlying connections to notify u
s that we got a "not master" error. | | /* this is the callback from our underlying connections to notify u
s that we got a "not master" error. | |
| */ | | */ | |
| void isntMaster() { | | void isntMaster() { | |
| master = ( ( master == Left ) ? NotSetR : NotSetL ); | | master = ( ( master == Left ) ? NotSetR : NotSetL ); | |
| } | | } | |
| | | | |
| string getServerAddress() const { | | string getServerAddress() const { | |
| return left.getServerAddress() + "," + right.getServerAddress()
; | | return left.getServerAddress() + "," + right.getServerAddress()
; | |
| } | | } | |
| | | | |
|
| | | DBClientConnection& masterConn(); | |
| DBClientConnection& slaveConn(); | | DBClientConnection& slaveConn(); | |
| | | | |
| /* TODO - not yet implemented. mongos may need these. */ | | /* TODO - not yet implemented. mongos may need these. */ | |
| virtual bool call( Message &toSend, Message &response, bool assertO
k=true ) { assert(false); return false; } | | virtual bool call( Message &toSend, Message &response, bool assertO
k=true ) { assert(false); return false; } | |
| virtual void say( Message &toSend ) { assert(false); } | | virtual void say( Message &toSend ) { assert(false); } | |
| virtual void sayPiggyBack( Message &toSend ) { assert(false); } | | virtual void sayPiggyBack( Message &toSend ) { assert(false); } | |
| virtual void checkResponse( const char *data, int nReturned ) { ass
ert(false); } | | virtual void checkResponse( const char *data, int nReturned ) { ass
ert(false); } | |
| | | | |
| bool isFailed() const { | | bool isFailed() const { | |
| // TODO: this really should check isFailed on current master as
well | | // TODO: this really should check isFailed on current master as
well | |
| | | | |
End of changes. 5 change blocks. |
| 3 lines changed or deleted | | 90 lines changed or added | |
|
| lasterror.h | | lasterror.h | |
| | | | |
| skipping to change at line 20 | | skipping to change at line 20 | |
| * | | * | |
| * Unless required by applicable law or agreed to in writing, software | | * Unless required by applicable law or agreed to in writing, software | |
| * distributed under the License is distributed on an "AS IS" BASIS, | | * distributed under the License is distributed on an "AS IS" BASIS, | |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or impli
ed. | | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or impli
ed. | |
| * See the License for the specific language governing permissions and | | * See the License for the specific language governing permissions and | |
| * limitations under the License. | | * limitations under the License. | |
| */ | | */ | |
| | | | |
| #pragma once | | #pragma once | |
| | | | |
|
| | | #include "../bson/oid.h" | |
| | | | |
| namespace mongo { | | namespace mongo { | |
| class BSONObjBuilder; | | class BSONObjBuilder; | |
| class Message; | | class Message; | |
| | | | |
| struct LastError { | | struct LastError { | |
| int code; | | int code; | |
| string msg; | | string msg; | |
| enum UpdatedExistingType { NotUpdate, True, False } updatedExisting
; | | enum UpdatedExistingType { NotUpdate, True, False } updatedExisting
; | |
|
| /* todo: nObjects should be 64 bit */ | | OID upsertedId; | |
| long long nObjects; | | long long nObjects; | |
| int nPrev; | | int nPrev; | |
| bool valid; | | bool valid; | |
| bool overridenById; | | bool overridenById; | |
| bool disabled; | | bool disabled; | |
| 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; | |
| } | | } | |
|
| void recordUpdate( bool _updatedExisting, long long nChanged ) { | | void recordUpdate( bool _updateObjects , long long _nObjects , OID
_upsertedId ){ | |
| reset( true ); | | reset( true ); | |
|
| nObjects = nChanged; | | nObjects = _nObjects; | |
| updatedExisting = _updatedExisting ? True : False; | | updatedExisting = _updateObjects ? True : False; | |
| | | if ( _upsertedId.isSet() ) | |
| | | upsertedId = _upsertedId; | |
| | | | |
| } | | } | |
| void recordDelete( long long nDeleted ) { | | void recordDelete( long long nDeleted ) { | |
| reset( true ); | | reset( true ); | |
| nObjects = nDeleted; | | nObjects = nDeleted; | |
| } | | } | |
| LastError() { | | LastError() { | |
| overridenById = false; | | 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; | |
|
| | | upsertedId.clear(); | |
| } | | } | |
| void appendSelf( BSONObjBuilder &b ); | | void appendSelf( BSONObjBuilder &b ); | |
| static LastError noError; | | static LastError noError; | |
| }; | | }; | |
| | | | |
| extern class LastErrorHolder { | | extern class LastErrorHolder { | |
| public: | | public: | |
| LastErrorHolder() : _id( 0 ) {} | | LastErrorHolder() : _id( 0 ) {} | |
| | | | |
| LastError * get( bool create = false ); | | LastError * get( bool create = false ); | |
|
| | | LastError * getSafe(){ | |
| | | LastError * le = get(false); | |
| | | assert( le ); | |
| | | return le; | |
| | | } | |
| | | | |
| LastError * _get( bool create = false ); // may return a disabled L
astError | | LastError * _get( bool create = false ); // may return a disabled L
astError | |
| | | | |
| void reset( LastError * le ); | | void reset( LastError * le ); | |
| | | | |
| /** ok to call more than once. */ | | /** ok to call more than once. */ | |
| void initThread(); | | void initThread(); | |
| | | | |
| /** | | /** | |
| * id of 0 means should use thread local management | | * id of 0 means should use thread local management | |
| | | | |
| skipping to change at line 110 | | skipping to change at line 121 | |
| struct Status { | | struct Status { | |
| time_t time; | | time_t time; | |
| LastError *lerr; | | LastError *lerr; | |
| }; | | }; | |
| static mongo::mutex _idsmutex; | | static mongo::mutex _idsmutex; | |
| map<int,Status> _ids; | | map<int,Status> _ids; | |
| } lastError; | | } lastError; | |
| | | | |
| void raiseError(int code , const char *msg); | | void raiseError(int code , const char *msg); | |
| | | | |
|
| inline void recordUpdate( bool updatedExisting, int nChanged ) { | | | |
| LastError *le = lastError.get(); | | | |
| if ( le ) | | | |
| le->recordUpdate( updatedExisting, nChanged ); | | | |
| } | | | |
| | | | |
| inline void recordDelete( int nDeleted ) { | | | |
| LastError *le = lastError.get(); | | | |
| if ( le ) | | | |
| le->recordDelete( nDeleted ); | | | |
| } | | | |
| | | | |
| } // namespace mongo | | } // namespace mongo | |
| | | | |
End of changes. 7 change blocks. |
| 16 lines changed or deleted | | 15 lines changed or added | |
|
| log.h | | log.h | |
| | | | |
| skipping to change at line 30 | | skipping to change at line 30 | |
| #include <string.h> | | #include <string.h> | |
| #include <errno.h> | | #include <errno.h> | |
| #include "../bson/util/builder.h" | | #include "../bson/util/builder.h" | |
| | | | |
| #ifndef _WIN32 | | #ifndef _WIN32 | |
| //#include <syslog.h> | | //#include <syslog.h> | |
| #endif | | #endif | |
| | | | |
| namespace mongo { | | namespace mongo { | |
| | | | |
|
| using boost::shared_ptr; | | enum LogLevel { LL_DEBUG , LL_INFO , LL_NOTICE , LL_WARNING , LL_ERROR | |
| | | , LL_SEVERE }; | |
| | | | |
| | | inline const char * logLevelToString( LogLevel l ){ | |
| | | switch ( l ){ | |
| | | case LL_DEBUG: | |
| | | case LL_INFO: | |
| | | case LL_NOTICE: | |
| | | return ""; | |
| | | case LL_WARNING: | |
| | | return "warning" ; | |
| | | case LL_ERROR: | |
| | | return "ERROR"; | |
| | | case LL_SEVERE: | |
| | | return "SEVERE"; | |
| | | default: | |
| | | return "UNKNOWN"; | |
| | | } | |
| | | } | |
| | | | |
|
| // Utility interface for stringifying object only when val() called. | | | |
| class LazyString { | | class LazyString { | |
| public: | | public: | |
| virtual ~LazyString() {} | | virtual ~LazyString() {} | |
| virtual string val() const = 0; | | virtual string val() const = 0; | |
| }; | | }; | |
| | | | |
| // Utility class for stringifying object only when val() called. | | // Utility class for stringifying object only when val() called. | |
| template< class T > | | template< class T > | |
| class LazyStringImpl : public LazyString { | | class LazyStringImpl : public LazyString { | |
| public: | | public: | |
| LazyStringImpl( const T &t ) : t_( t ) {} | | LazyStringImpl( const T &t ) : t_( t ) {} | |
| virtual string val() const { return (string)t_; } | | virtual string val() const { return (string)t_; } | |
| private: | | private: | |
| const T& t_; | | const T& t_; | |
| }; | | }; | |
| | | | |
| class Tee { | | class Tee { | |
| public: | | public: | |
| virtual ~Tee(){} | | virtual ~Tee(){} | |
|
| virtual void write(const string& str) = 0; | | virtual void write(LogLevel level , const string& str) = 0; | |
| }; | | }; | |
| | | | |
| class Nullstream { | | class Nullstream { | |
| public: | | public: | |
| virtual Nullstream& operator<< (Tee* tee) { | | virtual Nullstream& operator<< (Tee* tee) { | |
| return *this; | | return *this; | |
| } | | } | |
| virtual ~Nullstream() {} | | virtual ~Nullstream() {} | |
| virtual Nullstream& operator<<(const char *) { | | virtual Nullstream& operator<<(const char *) { | |
| return *this; | | return *this; | |
| | | | |
| skipping to change at line 136 | | skipping to change at line 152 | |
| return *this; | | return *this; | |
| } | | } | |
| virtual void flush(Tee *t = 0) {} | | virtual void flush(Tee *t = 0) {} | |
| }; | | }; | |
| extern Nullstream nullstream; | | extern Nullstream nullstream; | |
| | | | |
| class Logstream : public Nullstream { | | class Logstream : public Nullstream { | |
| static mongo::mutex mutex; | | static mongo::mutex mutex; | |
| static int doneSetup; | | static int doneSetup; | |
| stringstream ss; | | stringstream ss; | |
|
| | | LogLevel logLevel; | |
| public: | | public: | |
| static int magicNumber(){ | | static int magicNumber(){ | |
| return 1717; | | return 1717; | |
| } | | } | |
| void flush(Tee *t = 0) { | | void flush(Tee *t = 0) { | |
| // this ensures things are sane | | // this ensures things are sane | |
| if ( doneSetup == 1717 ) { | | if ( doneSetup == 1717 ) { | |
| BufBuilder b(512); | | BufBuilder b(512); | |
| time_t_to_String( time(0) , b.grow(20) ); | | time_t_to_String( time(0) , b.grow(20) ); | |
| b.append( ss.str() ); | | b.append( ss.str() ); | |
| const char *s = b.buf(); | | const char *s = b.buf(); | |
| | | | |
|
| | | string threadName = getThreadName(); | |
| | | const char * type = logLevelToString(logLevel); | |
| | | | |
| scoped_lock lk(mutex); | | scoped_lock lk(mutex); | |
| | | | |
|
| if( t ) t->write(s); | | if( t ) t->write(logLevel,s); | |
| | | | |
| #ifndef _WIN32 | | #ifndef _WIN32 | |
| //syslog( LOG_INFO , "%s" , cc ); | | //syslog( LOG_INFO , "%s" , cc ); | |
| #endif | | #endif | |
|
| | | | |
| | | if ( ! threadName.empty() ){ | |
| | | cout << "[" << threadName << "] "; | |
| | | } | |
| | | cout << type << ( type[0] ? ": " : "" ); | |
| cout << s; | | cout << s; | |
| cout.flush(); | | cout.flush(); | |
| } | | } | |
| _init(); | | _init(); | |
| } | | } | |
| | | | |
|
| | | Nullstream& setLogLevel(LogLevel l){ | |
| | | logLevel = l; | |
| | | return *this; | |
| | | } | |
| | | | |
| /** note these are virtual */ | | /** note these are virtual */ | |
| Logstream& operator<<(const char *x) { ss << x; return *this; } | | Logstream& operator<<(const char *x) { ss << x; return *this; } | |
| Logstream& operator<<(char *x) { ss << x; return *this; } | | Logstream& operator<<(char *x) { ss << x; return *this; } | |
| Logstream& operator<<(char x) { ss << x; return *this; } | | Logstream& operator<<(char x) { ss << x; return *this; } | |
| Logstream& operator<<(int x) { ss << x; return *this; } | | Logstream& operator<<(int x) { ss << x; return *this; } | |
| Logstream& operator<<(ExitCode x) { ss << x; return *this; } | | Logstream& operator<<(ExitCode x) { ss << x; return *this; } | |
| Logstream& operator<<(long x) { ss << x; return *this; } | | Logstream& operator<<(long x) { ss << x; return *this; } | |
| Logstream& operator<<(unsigned long x) { ss << x; return *this; } | | Logstream& operator<<(unsigned long x) { ss << x; return *this; } | |
| Logstream& operator<<(unsigned x) { ss << x; return *this; } | | Logstream& operator<<(unsigned x) { ss << x; return *this; } | |
| Logstream& operator<<(double x) { ss << x; return *this; } | | Logstream& operator<<(double x) { ss << x; return *this; } | |
| | | | |
| skipping to change at line 216 | | skipping to change at line 247 | |
| return *this; | | return *this; | |
| } | | } | |
| | | | |
| private: | | private: | |
| static thread_specific_ptr<Logstream> tsp; | | static thread_specific_ptr<Logstream> tsp; | |
| Logstream(){ | | Logstream(){ | |
| _init(); | | _init(); | |
| } | | } | |
| void _init(){ | | void _init(){ | |
| ss.str(""); | | ss.str(""); | |
|
| | | logLevel = LL_INFO; | |
| } | | } | |
| public: | | public: | |
| static Logstream& get() { | | static Logstream& get() { | |
| Logstream *p = tsp.get(); | | Logstream *p = tsp.get(); | |
| if( p == 0 ) | | if( p == 0 ) | |
| tsp.reset( p = new Logstream() ); | | tsp.reset( p = new Logstream() ); | |
| return *p; | | return *p; | |
| } | | } | |
| }; | | }; | |
| | | | |
| | | | |
| skipping to change at line 263 | | skipping to change at line 295 | |
| return nullstream; | | return nullstream; | |
| return Logstream::get().prolog(); | | return Logstream::get().prolog(); | |
| } | | } | |
| | | | |
| inline Nullstream& log( int level ) { | | inline Nullstream& log( int level ) { | |
| if ( level > logLevel ) | | if ( level > logLevel ) | |
| return nullstream; | | return nullstream; | |
| return Logstream::get().prolog(); | | return Logstream::get().prolog(); | |
| } | | } | |
| | | | |
|
| | | inline Nullstream& log( LogLevel l ) { | |
| | | return Logstream::get().prolog().setLogLevel( l ); | |
| | | } | |
| | | | |
| inline Nullstream& log() { | | inline Nullstream& log() { | |
| return Logstream::get().prolog(); | | return Logstream::get().prolog(); | |
| } | | } | |
| | | | |
| /* TODOCONCURRENCY */ | | /* TODOCONCURRENCY */ | |
| inline ostream& stdcout() { | | inline ostream& stdcout() { | |
| return cout; | | return cout; | |
| } | | } | |
| | | | |
| /* default impl returns "" -- mongod overrides */ | | /* default impl returns "" -- mongod overrides */ | |
| | | | |
End of changes. 10 change blocks. |
| 4 lines changed or deleted | | 41 lines changed or added | |
|
| message.h | | message.h | |
| | | | |
| skipping to change at line 35 | | skipping to change at line 35 | |
| | | | |
| extern bool noUnixSocket; | | extern bool noUnixSocket; | |
| | | | |
| class Message; | | class Message; | |
| class MessagingPort; | | class MessagingPort; | |
| class PiggyBackData; | | class PiggyBackData; | |
| typedef AtomicUInt MSGID; | | typedef AtomicUInt MSGID; | |
| | | | |
| class Listener { | | class Listener { | |
| public: | | public: | |
|
| Listener(const string &ip, int p, bool logConnect=true ) : _port(p) | | Listener(const string &ip, int p, bool logConnect=true ) : _port(p) | |
| , _ip(ip), _logConnect(logConnect) { } | | , _ip(ip), _logConnect(logConnect), _elapsedTime(0){ } | |
| virtual ~Listener() {} | | virtual ~Listener() { | |
| | | if ( _timeTracker == this ) | |
| | | _timeTracker = 0; | |
| | | } | |
| void initAndListen(); // never returns unless error (start a thread
) | | void initAndListen(); // never returns unless error (start a thread
) | |
| | | | |
| /* spawn a thread, etc., then return */ | | /* spawn a thread, etc., then return */ | |
| virtual void accepted(int sock, const SockAddr& from); | | virtual void accepted(int sock, const SockAddr& from); | |
| virtual void accepted(MessagingPort *mp){ | | virtual void accepted(MessagingPort *mp){ | |
| assert(!"You must overwrite one of the accepted methods"); | | assert(!"You must overwrite one of the accepted methods"); | |
| } | | } | |
| | | | |
| const int _port; | | const int _port; | |
| | | | |
|
| | | /** | |
| | | * @return a rough estimate of elepased time since the server start | |
| | | ed | |
| | | */ | |
| | | long long getMyElapsedTimeMillis() const { return _elapsedTime; } | |
| | | | |
| | | void setAsTimeTracker(){ | |
| | | _timeTracker = this; | |
| | | } | |
| | | | |
| | | static const Listener* getTimeTracker(){ | |
| | | return _timeTracker; | |
| | | } | |
| | | | |
| | | static long long getElapsedTimeMillis() { | |
| | | if ( _timeTracker ) | |
| | | return _timeTracker->getMyElapsedTimeMillis(); | |
| | | return 0; | |
| | | } | |
| | | | |
| private: | | private: | |
| string _ip; | | string _ip; | |
| bool _logConnect; | | bool _logConnect; | |
|
| | | long long _elapsedTime; | |
| | | | |
| | | static const Listener* _timeTracker; | |
| }; | | }; | |
| | | | |
| class AbstractMessagingPort { | | class AbstractMessagingPort { | |
| public: | | public: | |
| virtual ~AbstractMessagingPort() { } | | virtual ~AbstractMessagingPort() { } | |
| virtual void reply(Message& received, Message& response, MSGID resp
onseTo) = 0; // like the reply below, but doesn't rely on received.data sti
ll being available | | virtual void reply(Message& received, Message& response, MSGID resp
onseTo) = 0; // like the reply below, but doesn't rely on received.data sti
ll being available | |
| virtual void reply(Message& received, Message& response) = 0; | | virtual void reply(Message& received, Message& response) = 0; | |
| | | | |
| virtual HostAndPort remote() const = 0; | | virtual HostAndPort remote() const = 0; | |
| virtual unsigned remotePort() const = 0; | | virtual unsigned remotePort() const = 0; | |
| | | | |
| skipping to change at line 370 | | skipping to change at line 395 | |
| // if just one buffer, keep it in _buf, otherwise keep a sequence o
f buffers in _data | | // if just one buffer, keep it in _buf, otherwise keep a sequence o
f buffers in _data | |
| MsgData * _buf; | | MsgData * _buf; | |
| // byte buffer(s) - the first must contain at least a full MsgData
unless using _buf for storage instead | | // byte buffer(s) - the first must contain at least a full MsgData
unless using _buf for storage instead | |
| typedef vector< pair< char*, int > > MsgVec; | | typedef vector< pair< char*, int > > MsgVec; | |
| MsgVec _data; | | MsgVec _data; | |
| bool _freeIt; | | bool _freeIt; | |
| }; | | }; | |
| | | | |
| class SocketException : public DBException { | | class SocketException : public DBException { | |
| public: | | public: | |
|
| virtual const char* what() const throw() { return "socket exception | | SocketException() : DBException( "socket exception" , 9001 ){} | |
| "; } | | | |
| virtual int getCode() const { return 9001; } | | | |
| }; | | }; | |
| | | | |
| MSGID nextMessageId(); | | MSGID nextMessageId(); | |
| | | | |
| void setClientId( int id ); | | void setClientId( int id ); | |
| int getClientId(); | | int getClientId(); | |
| | | | |
| extern TicketHolder connTicketHolder; | | extern TicketHolder connTicketHolder; | |
| | | | |
|
| | | class ElapsedTracker { | |
| | | public: | |
| | | ElapsedTracker( int hitsBetweenMarks , int msBetweenMarks ) | |
| | | : _h( hitsBetweenMarks ) , _ms( msBetweenMarks ) , _pings(0){ | |
| | | _last = Listener::getElapsedTimeMillis(); | |
| | | } | |
| | | | |
| | | /** | |
| | | * call this for every iteration | |
| | | * returns true if one of the triggers has gone off | |
| | | */ | |
| | | bool ping(){ | |
| | | if ( ( ++_pings % _h ) == 0 ){ | |
| | | _last = Listener::getElapsedTimeMillis(); | |
| | | return true; | |
| | | } | |
| | | | |
| | | long long now = Listener::getElapsedTimeMillis(); | |
| | | if ( now - _last > _ms ){ | |
| | | _last = now; | |
| | | return true; | |
| | | } | |
| | | | |
| | | return false; | |
| | | } | |
| | | | |
| | | private: | |
| | | int _h; | |
| | | int _ms; | |
| | | | |
| | | unsigned long long _pings; | |
| | | | |
| | | long long _last; | |
| | | | |
| | | }; | |
| | | | |
| } // namespace mongo | | } // namespace mongo | |
| | | | |
End of changes. 5 change blocks. |
| 6 lines changed or deleted | | 66 lines changed or added | |
|
| mmap.h | | mmap.h | |
| | | | |
| skipping to change at line 30 | | skipping to change at line 30 | |
| namespace mongo { | | namespace mongo { | |
| | | | |
| /* the administrative-ish stuff here */ | | /* the administrative-ish stuff here */ | |
| class MongoFile : boost::noncopyable { | | class MongoFile : boost::noncopyable { | |
| protected: | | protected: | |
| virtual void close() = 0; | | virtual void close() = 0; | |
| virtual void flush(bool sync) = 0; | | virtual void flush(bool sync) = 0; | |
| | | | |
| void created(); /* subclass must call after create */ | | void created(); /* subclass must call after create */ | |
| void destroyed(); /* subclass must call in destructor */ | | void destroyed(); /* subclass must call in destructor */ | |
|
| | | | |
| | | // only supporting on posix mmap | |
| | | virtual void _lock() {} | |
| | | virtual void _unlock() {} | |
| | | | |
| public: | | public: | |
| virtual ~MongoFile() {} | | virtual ~MongoFile() {} | |
| virtual long length() = 0; | | virtual long length() = 0; | |
| | | | |
| enum Options { | | enum Options { | |
| SEQUENTIAL = 1 // hint - e.g. FILE_FLAG_SEQUENTIAL_SCAN on wind
ows | | SEQUENTIAL = 1 // hint - e.g. FILE_FLAG_SEQUENTIAL_SCAN on wind
ows | |
| }; | | }; | |
| | | | |
| static int flushAll( bool sync ); // returns n flushed | | static int flushAll( bool sync ); // returns n flushed | |
| static long long totalMappedLength(); | | static long long totalMappedLength(); | |
| static void closeAllFiles( stringstream &message ); | | static void closeAllFiles( stringstream &message ); | |
| | | | |
|
| | | // Locking allows writes. Reads are always allowed | |
| | | static void lockAll(); | |
| | | static void unlockAll(); | |
| | | | |
| /* can be "overriden" if necessary */ | | /* can be "overriden" if necessary */ | |
| static bool exists(boost::filesystem::path p) { | | static bool exists(boost::filesystem::path p) { | |
| return boost::filesystem::exists(p); | | return boost::filesystem::exists(p); | |
| } | | } | |
| }; | | }; | |
| | | | |
|
| | | #ifndef _DEBUG | |
| | | // no-ops in production | |
| | | inline void MongoFile::lockAll() {} | |
| | | inline void MongoFile::unlockAll() {} | |
| | | | |
| | | #endif | |
| | | | |
| | | struct MongoFileAllowWrites { | |
| | | MongoFileAllowWrites(){ | |
| | | MongoFile::lockAll(); | |
| | | } | |
| | | ~MongoFileAllowWrites(){ | |
| | | MongoFile::unlockAll(); | |
| | | } | |
| | | }; | |
| | | | |
| /** template for what a new storage engine's class definition must impl
ement | | /** template for what a new storage engine's class definition must impl
ement | |
| PRELIMINARY - subject to change. | | PRELIMINARY - subject to change. | |
| */ | | */ | |
| class StorageContainerTemplate : public MongoFile { | | class StorageContainerTemplate : public MongoFile { | |
| protected: | | protected: | |
| virtual void close(); | | virtual void close(); | |
| virtual void flush(bool sync); | | virtual void flush(bool sync); | |
| public: | | public: | |
| virtual long length(); | | virtual long length(); | |
| | | | |
| | | | |
| skipping to change at line 140 | | skipping to change at line 165 | |
| } | | } | |
| | | | |
| private: | | private: | |
| static void updateLength( const char *filename, long &length ); | | static void updateLength( const char *filename, long &length ); | |
| | | | |
| HANDLE fd; | | HANDLE fd; | |
| HANDLE maphandle; | | HANDLE maphandle; | |
| void *view; | | void *view; | |
| long len; | | long len; | |
| string _filename; | | string _filename; | |
|
| | | | |
| | | protected: | |
| | | // only posix mmap implementations will support this | |
| | | virtual void _lock(); | |
| | | virtual void _unlock(); | |
| | | | |
| }; | | }; | |
| | | | |
| void printMemInfo( const char * where ); | | void printMemInfo( const char * where ); | |
| | | | |
| #include "ramstore.h" | | #include "ramstore.h" | |
| | | | |
| //#define _RAMSTORE | | //#define _RAMSTORE | |
| #if defined(_RAMSTORE) | | #if defined(_RAMSTORE) | |
| typedef RamStoreFile MMF; | | typedef RamStoreFile MMF; | |
| #else | | #else | |
| | | | |
End of changes. 4 change blocks. |
| 0 lines changed or deleted | | 31 lines changed or added | |
|
| optime.h | | optime.h | |
| | | | |
| skipping to change at line 26 | | skipping to change at line 26 | |
| */ | | */ | |
| | | | |
| #pragma once | | #pragma once | |
| | | | |
| #include "../db/concurrency.h" | | #include "../db/concurrency.h" | |
| | | | |
| namespace mongo { | | namespace mongo { | |
| void exitCleanly( ExitCode code ); | | void exitCleanly( ExitCode code ); | |
| | | | |
| struct ClockSkewException : public DBException { | | struct ClockSkewException : public DBException { | |
|
| virtual const char* what() const throw() { return "clock skew excep | | ClockSkewException() : DBException( "clock skew exception" , 20001 | |
| tion"; } | | ){} | |
| virtual int getCode() const { return 20001; } | | | |
| }; | | }; | |
| | | | |
| /* replsets use RSOpTime. | | /* replsets use RSOpTime. | |
| M/S uses OpTime. | | M/S uses OpTime. | |
| But this is useable from both. | | But this is useable from both. | |
| */ | | */ | |
| typedef unsigned long long ReplTime; | | typedef unsigned long long ReplTime; | |
| | | | |
| /* Operation sequence #. A combination of current second plus an ordin
al value. | | /* Operation sequence #. A combination of current second plus an ordin
al value. | |
| */ | | */ | |
| | | | |
| skipping to change at line 98 | | skipping to change at line 97 | |
| | | | |
| /* We store OpTime's in the database as BSON Date datatype -- we ne
eded some sort of | | /* We store OpTime's in the database as BSON Date datatype -- we ne
eded some sort of | |
| 64 bit "container" for these values. While these are not really "
Dates", that seems a | | 64 bit "container" for these values. While these are not really "
Dates", that seems a | |
| better choice for now than say, Number, which is floating point.
Note the BinData type | | better choice for now than say, Number, which is floating point.
Note the BinData type | |
| is perhaps the cleanest choice, lacking a true unsigned64 datatype
, but BinData has 5 | | is perhaps the cleanest choice, lacking a true unsigned64 datatype
, but BinData has 5 | |
| bytes of overhead. | | bytes of overhead. | |
| */ | | */ | |
| unsigned long long asDate() const { | | unsigned long long asDate() const { | |
| return *((unsigned long long *) &i); | | return *((unsigned long long *) &i); | |
| } | | } | |
|
| | | long long asLL() const { | |
| | | return *((long long *) &i); | |
| | | } | |
| // unsigned long long& asDate() { return *((unsigned long lon
g *) &i); } | | // unsigned long long& asDate() { return *((unsigned long lon
g *) &i); } | |
| | | | |
|
| bool isNull() { | | bool isNull() const { return secs == 0; } | |
| return secs == 0; | | | |
| } | | | |
| | | | |
| string toStringLong() const { | | string toStringLong() const { | |
| char buf[64]; | | char buf[64]; | |
| time_t_to_String(secs, buf); | | time_t_to_String(secs, buf); | |
| stringstream ss; | | stringstream ss; | |
| ss << buf << ' '; | | ss << buf << ' '; | |
| ss << hex << secs << ':' << i; | | ss << hex << secs << ':' << i; | |
| return ss.str(); | | return ss.str(); | |
| } | | } | |
| | | | |
| | | | |
| skipping to change at line 130 | | skipping to change at line 130 | |
| return i == r.i && secs == r.secs; | | return i == r.i && secs == r.secs; | |
| } | | } | |
| bool operator!=(const OpTime& r) const { | | bool operator!=(const OpTime& r) const { | |
| return !(*this == r); | | return !(*this == r); | |
| } | | } | |
| bool operator<(const OpTime& r) const { | | bool operator<(const OpTime& r) const { | |
| if ( secs != r.secs ) | | if ( secs != r.secs ) | |
| return secs < r.secs; | | return secs < r.secs; | |
| return i < r.i; | | return i < r.i; | |
| } | | } | |
|
| | | bool operator<=(const OpTime& r) const { | |
| | | return *this < r || *this == r; | |
| | | } | |
| }; | | }; | |
| #pragma pack() | | #pragma pack() | |
| | | | |
| } // namespace mongo | | } // namespace mongo | |
| | | | |
End of changes. 4 change blocks. |
| 6 lines changed or deleted | | 9 lines changed or added | |
|
| query.h | | query.h | |
| | | | |
| skipping to change at line 82 | | skipping to change at line 82 | |
| namespace mongo { | | namespace mongo { | |
| | | | |
| extern const int MaxBytesToReturnToClientAtOnce; | | extern const int MaxBytesToReturnToClientAtOnce; | |
| | | | |
| // for an existing query (ie a ClientCursor), send back additional info
rmation. | | // for an existing query (ie a ClientCursor), send back additional info
rmation. | |
| struct GetMoreWaitException { }; | | struct GetMoreWaitException { }; | |
| | | | |
| QueryResult* processGetMore(const char *ns, int ntoreturn, long long cu
rsorid , CurOp& op, int pass, bool& exhaust); | | QueryResult* processGetMore(const char *ns, int ntoreturn, long long cu
rsorid , CurOp& op, int pass, bool& exhaust); | |
| | | | |
| struct UpdateResult { | | struct UpdateResult { | |
|
| bool existing; | | bool existing; // if existing objects were modified | |
| bool mod; | | bool mod; // was this a $ mod | |
| long long num; | | long long num; // how many objects touched | |
| | | OID upserted; // if something was upserted, the new _id of the obj | |
| UpdateResult( bool e, bool m, unsigned long long n ) | | ect | |
| : existing(e) , mod(m), num(n ){} | | | |
| | | | |
|
| int oldCode(){ | | UpdateResult( bool e, bool m, unsigned long long n , const BSONObj& | |
| if ( ! num ) | | upsertedObject = BSONObj() ) | |
| return 0; | | : existing(e) , mod(m), num(n){ | |
| | | upserted.clear(); | |
| | | | |
|
| if ( existing ){ | | BSONElement id = upsertedObject["_id"]; | |
| if ( mod ) | | if ( ! e && n == 1 && id.type() == jstOID ){ | |
| return 2; | | upserted = id.OID(); | |
| return 1; | | | |
| } | | } | |
|
| | | | |
| if ( mod ) | | | |
| return 3; | | | |
| return 4; | | | |
| } | | } | |
|
| | | | |
| }; | | }; | |
| | | | |
| /* returns true if an existing object was updated, false if no existing
object was found. | | /* returns true if an existing object was updated, false if no existing
object was found. | |
| multi - update multiple objects - mostly useful with things like $se
t | | multi - update multiple objects - mostly useful with things like $se
t | |
| god - allow access to system namespaces | | god - allow access to system namespaces | |
| */ | | */ | |
| UpdateResult updateObjects(const char *ns, const BSONObj& updateobj, BS
ONObj pattern, bool upsert, bool multi , bool logop , OpDebug& debug ); | | UpdateResult updateObjects(const char *ns, const BSONObj& updateobj, BS
ONObj pattern, bool upsert, bool multi , bool logop , OpDebug& debug ); | |
| UpdateResult _updateObjects(bool god, const char *ns, const BSONObj& up
dateobj, BSONObj pattern, bool upsert, bool multi , bool logop , OpDebug& d
ebug ); | | UpdateResult _updateObjects(bool god, const char *ns, const BSONObj& up
dateobj, BSONObj pattern, bool upsert, bool multi , bool logop , OpDebug& d
ebug ); | |
| | | | |
| // If justOne is true, deletedId is set to the id of the deleted object
. | | // If justOne is true, deletedId is set to the id of the deleted object
. | |
| | | | |
End of changes. 5 change blocks. |
| 17 lines changed or deleted | | 13 lines changed or added | |
|
| queryoptimizer.h | | queryoptimizer.h | |
| | | | |
| skipping to change at line 128 | | skipping to change at line 128 | |
| _matcher->addOrConstraint( _orConstraint ); | | _matcher->addOrConstraint( _orConstraint ); | |
| _haveOrConstraint = false; | | _haveOrConstraint = false; | |
| } | | } | |
| QueryOp *ret = _createChild(); | | QueryOp *ret = _createChild(); | |
| ret->_oldMatcher = _matcher; | | ret->_oldMatcher = _matcher; | |
| return ret; | | return ret; | |
| } | | } | |
| bool complete() const { return _complete; } | | bool complete() const { return _complete; } | |
| bool error() const { return _error; } | | bool error() const { return _error; } | |
| bool stopRequested() const { return _stopRequested; } | | bool stopRequested() const { return _stopRequested; } | |
|
| string exceptionMessage() const { return _exceptionMessage; } | | ExceptionInfo exception() const { return _exception; } | |
| const QueryPlan &qp() const { return *_qp; } | | const QueryPlan &qp() const { return *_qp; } | |
| // To be called by QueryPlanSet::Runner only. | | // To be called by QueryPlanSet::Runner only. | |
| void setQueryPlan( const QueryPlan *qp ) { _qp = qp; } | | void setQueryPlan( const QueryPlan *qp ) { _qp = qp; } | |
|
| void setExceptionMessage( const string &exceptionMessage ) { | | void setException( const DBException &e ) { | |
| _error = true; | | _error = true; | |
|
| _exceptionMessage = exceptionMessage; | | _exception = e.getInfo(); | |
| } | | } | |
| shared_ptr< CoveredIndexMatcher > matcher() const { return _matcher
; } | | shared_ptr< CoveredIndexMatcher > matcher() const { return _matcher
; } | |
| protected: | | protected: | |
| void setComplete() { | | void setComplete() { | |
| _haveOrConstraint = true; | | _haveOrConstraint = true; | |
| _orConstraint = qp().simplifiedQuery( qp().indexKey(), true ); | | _orConstraint = qp().simplifiedQuery( qp().indexKey(), true ); | |
| _complete = true; | | _complete = true; | |
| } | | } | |
| void setStop() { setComplete(); _stopRequested = true; } | | void setStop() { setComplete(); _stopRequested = true; } | |
| | | | |
| virtual void _init() = 0; | | virtual void _init() = 0; | |
| | | | |
| virtual QueryOp *_createChild() const = 0; | | virtual QueryOp *_createChild() const = 0; | |
| | | | |
| virtual bool alwaysUseRecord() const { return false; } | | virtual bool alwaysUseRecord() const { return false; } | |
| | | | |
| private: | | private: | |
| bool _complete; | | bool _complete; | |
| bool _stopRequested; | | bool _stopRequested; | |
|
| string _exceptionMessage; | | ExceptionInfo _exception; | |
| const QueryPlan *_qp; | | const QueryPlan *_qp; | |
| bool _error; | | bool _error; | |
| shared_ptr< CoveredIndexMatcher > _matcher; | | shared_ptr< CoveredIndexMatcher > _matcher; | |
| shared_ptr< CoveredIndexMatcher > _oldMatcher; | | shared_ptr< CoveredIndexMatcher > _oldMatcher; | |
| bool _haveOrConstraint; | | bool _haveOrConstraint; | |
| BSONObj _orConstraint; | | BSONObj _orConstraint; | |
| }; | | }; | |
| | | | |
| // Set of candidate query plans for a particular query. Used for runni
ng | | // Set of candidate query plans for a particular query. Used for runni
ng | |
| // a QueryOp on these plans. | | // a QueryOp on these plans. | |
| | | | |
| skipping to change at line 178 | | skipping to change at line 178 | |
| typedef boost::shared_ptr< QueryPlan > PlanPtr; | | typedef boost::shared_ptr< QueryPlan > PlanPtr; | |
| typedef vector< PlanPtr > PlanSet; | | typedef vector< PlanPtr > PlanSet; | |
| | | | |
| QueryPlanSet( const char *ns, | | QueryPlanSet( const char *ns, | |
| auto_ptr< FieldRangeSet > frs, | | auto_ptr< FieldRangeSet > frs, | |
| const BSONObj &originalQuery, | | const BSONObj &originalQuery, | |
| const BSONObj &order, | | const BSONObj &order, | |
| const BSONElement *hint = 0, | | const BSONElement *hint = 0, | |
| bool honorRecordedPlan = true, | | bool honorRecordedPlan = true, | |
| const BSONObj &min = BSONObj(), | | const BSONObj &min = BSONObj(), | |
|
| const BSONObj &max = BSONObj() ); | | const BSONObj &max = BSONObj(), | |
| | | bool bestGuessOnly = false ); | |
| int nPlans() const { return plans_.size(); } | | int nPlans() const { return plans_.size(); } | |
| shared_ptr< QueryOp > runOp( QueryOp &op ); | | shared_ptr< QueryOp > runOp( QueryOp &op ); | |
| template< class T > | | template< class T > | |
| shared_ptr< T > runOp( T &op ) { | | shared_ptr< T > runOp( T &op ) { | |
| return dynamic_pointer_cast< T >( runOp( static_cast< QueryOp&
>( op ) ) ); | | return dynamic_pointer_cast< T >( runOp( static_cast< QueryOp&
>( op ) ) ); | |
| } | | } | |
| BSONObj explain() const; | | BSONObj explain() const; | |
| bool usingPrerecordedPlan() const { return usingPrerecordedPlan_; } | | bool usingPrerecordedPlan() const { return usingPrerecordedPlan_; } | |
| PlanPtr getBestGuess() const; | | PlanPtr getBestGuess() const; | |
|
| void setBestGuessOnly() { _bestGuessOnly = true; } | | | |
| //for testing | | //for testing | |
| const FieldRangeSet &fbs() const { return *fbs_; } | | const FieldRangeSet &fbs() const { return *fbs_; } | |
| private: | | private: | |
| void addOtherPlans( bool checkFirst ); | | void addOtherPlans( bool checkFirst ); | |
| void addPlan( PlanPtr plan, bool checkFirst ) { | | void addPlan( PlanPtr plan, bool checkFirst ) { | |
| if ( checkFirst && plan->indexKey().woCompare( plans_[ 0 ]->ind
exKey() ) == 0 ) | | if ( checkFirst && plan->indexKey().woCompare( plans_[ 0 ]->ind
exKey() ) == 0 ) | |
| return; | | return; | |
| plans_.push_back( plan ); | | plans_.push_back( plan ); | |
| } | | } | |
| void init(); | | void init(); | |
| | | | |
| skipping to change at line 255 | | skipping to change at line 255 | |
| // subsequent $or queries, even though there may be a significant aggre
gate | | // subsequent $or queries, even though there may be a significant aggre
gate | |
| // $nor component that would not be represented in QueryPattern. | | // $nor component that would not be represented in QueryPattern. | |
| class MultiPlanScanner { | | class MultiPlanScanner { | |
| public: | | public: | |
| MultiPlanScanner( const char *ns, | | MultiPlanScanner( const char *ns, | |
| const BSONObj &query, | | const BSONObj &query, | |
| const BSONObj &order, | | const BSONObj &order, | |
| const BSONElement *hint = 0, | | const BSONElement *hint = 0, | |
| bool honorRecordedPlan = true, | | bool honorRecordedPlan = true, | |
| const BSONObj &min = BSONObj(), | | const BSONObj &min = BSONObj(), | |
|
| const BSONObj &max = BSONObj() ); | | const BSONObj &max = BSONObj(), | |
| | | bool bestGuessOnly = false ); | |
| shared_ptr< QueryOp > runOp( QueryOp &op ); | | shared_ptr< QueryOp > runOp( QueryOp &op ); | |
| template< class T > | | template< class T > | |
| shared_ptr< T > runOp( T &op ) { | | shared_ptr< T > runOp( T &op ) { | |
| return dynamic_pointer_cast< T >( runOp( static_cast< QueryOp&
>( op ) ) ); | | return dynamic_pointer_cast< T >( runOp( static_cast< QueryOp&
>( op ) ) ); | |
| } | | } | |
| shared_ptr< QueryOp > runOpOnce( QueryOp &op ); | | shared_ptr< QueryOp > runOpOnce( QueryOp &op ); | |
| template< class T > | | template< class T > | |
| shared_ptr< T > runOpOnce( T &op ) { | | shared_ptr< T > runOpOnce( T &op ) { | |
| return dynamic_pointer_cast< T >( runOpOnce( static_cast< Query
Op& >( op ) ) ); | | return dynamic_pointer_cast< T >( runOpOnce( static_cast< Query
Op& >( op ) ) ); | |
| } | | } | |
| | | | |
| skipping to change at line 299 | | skipping to change at line 300 | |
| class MultiCursor : public Cursor { | | class MultiCursor : public Cursor { | |
| public: | | public: | |
| class CursorOp : public QueryOp { | | class CursorOp : public QueryOp { | |
| public: | | public: | |
| CursorOp() {} | | CursorOp() {} | |
| CursorOp( const QueryOp &other ) : QueryOp( other ) {} | | CursorOp( const QueryOp &other ) : QueryOp( other ) {} | |
| virtual shared_ptr< Cursor > newCursor() const = 0; | | virtual shared_ptr< Cursor > newCursor() const = 0; | |
| }; | | }; | |
| // takes ownership of 'op' | | // takes ownership of 'op' | |
| MultiCursor( const char *ns, const BSONObj &pattern, const BSONObj
&order, shared_ptr< CursorOp > op = shared_ptr< CursorOp >() ) | | MultiCursor( const char *ns, const BSONObj &pattern, const BSONObj
&order, shared_ptr< CursorOp > op = shared_ptr< CursorOp >() ) | |
|
| : _mps( new MultiPlanScanner( ns, pattern, order ) ) { | | : _mps( new MultiPlanScanner( ns, pattern, order, 0, true, BSONObj(
), BSONObj(), !op.get() ) ) { | |
| if ( op.get() ) { | | if ( op.get() ) { | |
| _op = op; | | _op = op; | |
| } else { | | } else { | |
| _op.reset( new NoOp() ); | | _op.reset( new NoOp() ); | |
|
| _mps->setBestGuessOnly(); | | | |
| } | | } | |
| if ( _mps->mayRunMore() ) { | | if ( _mps->mayRunMore() ) { | |
| nextClause(); | | nextClause(); | |
| if ( !ok() ) { | | if ( !ok() ) { | |
| advance(); | | advance(); | |
| } | | } | |
| } else { | | } else { | |
| _c.reset( new BasicCursor( DiskLoc() ) ); | | _c.reset( new BasicCursor( DiskLoc() ) ); | |
| } | | } | |
| } | | } | |
| | | | |
| skipping to change at line 351 | | skipping to change at line 351 | |
| _c->checkLocation(); | | _c->checkLocation(); | |
| } | | } | |
| virtual bool supportGetMore() { return true; } | | virtual bool supportGetMore() { return true; } | |
| // with update we could potentially get the same document on multip
le | | // with update we could potentially get the same document on multip
le | |
| // indexes, but update appears to already handle this with seenObje
cts | | // indexes, but update appears to already handle this with seenObje
cts | |
| // so we don't have to do anything special here. | | // so we don't have to do anything special here. | |
| virtual bool getsetdup(DiskLoc loc) { | | virtual bool getsetdup(DiskLoc loc) { | |
| return _c->getsetdup( loc ); | | return _c->getsetdup( loc ); | |
| } | | } | |
| virtual CoveredIndexMatcher *matcher() const { return _matcher.get(
); } | | virtual CoveredIndexMatcher *matcher() const { return _matcher.get(
); } | |
|
| | | // just for testing | |
| | | shared_ptr< Cursor > sub_c() const { return _c; } | |
| private: | | private: | |
| class NoOp : public CursorOp { | | class NoOp : public CursorOp { | |
| public: | | public: | |
| NoOp() {} | | NoOp() {} | |
| NoOp( const QueryOp &other ) : CursorOp( other ) {} | | NoOp( const QueryOp &other ) : CursorOp( other ) {} | |
| virtual void _init() { setComplete(); } | | virtual void _init() { setComplete(); } | |
| virtual void next() {} | | virtual void next() {} | |
| virtual bool mayRecordPlan() const { return false; } | | virtual bool mayRecordPlan() const { return false; } | |
| virtual QueryOp *_createChild() const { return new NoOp(); } | | virtual QueryOp *_createChild() const { return new NoOp(); } | |
| virtual shared_ptr< Cursor > newCursor() const { return qp().ne
wCursor(); } | | virtual shared_ptr< Cursor > newCursor() const { return qp().ne
wCursor(); } | |
|
| private: | | | |
| shared_ptr< CoveredIndexMatcher > _matcher; | | | |
| shared_ptr< CoveredIndexMatcher > _oldMatcher; | | | |
| }; | | }; | |
| void nextClause() { | | void nextClause() { | |
| shared_ptr< CursorOp > best = _mps->runOpOnce( *_op ); | | shared_ptr< CursorOp > best = _mps->runOpOnce( *_op ); | |
|
| massert( 10401 , best->exceptionMessage(), best->complete() ); | | if ( ! best->complete() ) | |
| | | throw MsgAssertionException( best->exception() ); | |
| _c = best->newCursor(); | | _c = best->newCursor(); | |
| _matcher = best->matcher(); | | _matcher = best->matcher(); | |
| _op = best; | | _op = best; | |
| } | | } | |
| shared_ptr< CursorOp > _op; | | shared_ptr< CursorOp > _op; | |
| shared_ptr< Cursor > _c; | | shared_ptr< Cursor > _c; | |
| auto_ptr< MultiPlanScanner > _mps; | | auto_ptr< MultiPlanScanner > _mps; | |
| shared_ptr< CoveredIndexMatcher > _matcher; | | shared_ptr< CoveredIndexMatcher > _matcher; | |
| }; | | }; | |
| | | | |
| // NOTE min, max, and keyPattern will be updated to be consistent with
the selected index. | | // NOTE min, max, and keyPattern will be updated to be consistent with
the selected index. | |
| IndexDetails *indexDetailsForRange( const char *ns, string &errmsg, BSO
NObj &min, BSONObj &max, BSONObj &keyPattern ); | | IndexDetails *indexDetailsForRange( const char *ns, string &errmsg, BSO
NObj &min, BSONObj &max, BSONObj &keyPattern ); | |
| | | | |
| inline bool isSimpleIdQuery( const BSONObj& query ){ | | inline bool isSimpleIdQuery( const BSONObj& query ){ | |
|
| return | | BSONObjIterator i(query); | |
| strcmp( query.firstElement().fieldName() , "_id" ) == 0 && | | if( !i.more() ) return false; | |
| query.nFields() == 1 && | | BSONElement e = i.next(); | |
| query.firstElement().isSimpleType(); | | if( i.more() ) return false; | |
| | | if( strcmp("_id", e.fieldName()) != 0 ) return false; | |
| | | return e.isSimpleType(); // e.g. not something like { _id : { $gt : | |
| | | ... | |
| } | | } | |
| | | | |
| // matcher() will always work on the returned cursor | | // matcher() will always work on the returned cursor | |
| inline shared_ptr< Cursor > bestGuessCursor( const char *ns, const BSON
Obj &query, const BSONObj &sort ) { | | inline shared_ptr< Cursor > bestGuessCursor( const char *ns, const BSON
Obj &query, const BSONObj &sort ) { | |
| if( !query.getField( "$or" ).eoo() ) { | | if( !query.getField( "$or" ).eoo() ) { | |
| return shared_ptr< Cursor >( new MultiCursor( ns, query, sort )
); | | return shared_ptr< Cursor >( new MultiCursor( ns, query, sort )
); | |
| } else { | | } else { | |
| auto_ptr< FieldRangeSet > frs( new FieldRangeSet( ns, query ) )
; | | auto_ptr< FieldRangeSet > frs( new FieldRangeSet( ns, query ) )
; | |
| shared_ptr< Cursor > ret = QueryPlanSet( ns, frs, query, sort )
.getBestGuess()->newCursor(); | | shared_ptr< Cursor > ret = QueryPlanSet( ns, frs, query, sort )
.getBestGuess()->newCursor(); | |
| if ( !query.isEmpty() ) { | | if ( !query.isEmpty() ) { | |
| | | | |
End of changes. 13 change blocks. |
| 17 lines changed or deleted | | 20 lines changed or added | |
|
| rs.h | | rs.h | |
| | | | |
| skipping to change at line 26 | | skipping to change at line 26 | |
| * 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 "../../util/concurrency/list.h" | | #include "../../util/concurrency/list.h" | |
| #include "../../util/concurrency/value.h" | | #include "../../util/concurrency/value.h" | |
| #include "../../util/concurrency/msg.h" | | #include "../../util/concurrency/msg.h" | |
| #include "../../util/hostandport.h" | | #include "../../util/hostandport.h" | |
| #include "../commands.h" | | #include "../commands.h" | |
|
| | | #include "rs_exception.h" | |
| #include "rs_optime.h" | | #include "rs_optime.h" | |
| #include "rsmember.h" | | #include "rsmember.h" | |
| #include "rs_config.h" | | #include "rs_config.h" | |
| | | | |
| namespace mongo { | | namespace mongo { | |
| | | | |
| struct Target; | | struct Target; | |
| class ReplSetImpl; | | class ReplSetImpl; | |
| extern bool replSet; // true if using repl sets | | extern bool replSet; // true if using repl sets | |
| extern class ReplSet *theReplSet; // null until initialized | | extern class ReplSet *theReplSet; // null until initialized | |
| | | | |
| skipping to change at line 60 | | skipping to change at line 61 | |
| | | | |
| void summarizeAsHtml(stringstream& s) const; | | void summarizeAsHtml(stringstream& s) const; | |
| friend class ReplSetImpl; | | friend class ReplSetImpl; | |
| private: | | private: | |
| const ReplSetConfig::MemberCfg *_config; /* todo: when this changes
??? */ | | const ReplSetConfig::MemberCfg *_config; /* todo: when this changes
??? */ | |
| HostAndPort _h; | | HostAndPort _h; | |
| HeartbeatInfo _hbinfo; | | HeartbeatInfo _hbinfo; | |
| }; | | }; | |
| | | | |
| class Manager : public task::Server { | | class Manager : public task::Server { | |
|
| bool got(const any&); | | | |
| ReplSetImpl *rs; | | ReplSetImpl *rs; | |
|
| | | bool busyWithElectSelf; | |
| int _primary; | | int _primary; | |
| const Member* findOtherPrimary(); | | const Member* findOtherPrimary(); | |
| void noteARemoteIsPrimary(const Member *); | | void noteARemoteIsPrimary(const Member *); | |
|
| | | virtual void starting(); | |
| public: | | public: | |
| Manager(ReplSetImpl *rs); | | Manager(ReplSetImpl *rs); | |
| void msgReceivedNewConfig(BSONObj) { assert(false); } | | void msgReceivedNewConfig(BSONObj) { assert(false); } | |
| void msgCheckNewState(); | | void msgCheckNewState(); | |
| }; | | }; | |
| | | | |
|
| | | struct Target; | |
| class Consensus { | | class Consensus { | |
| ReplSetImpl &rs; | | ReplSetImpl &rs; | |
| struct LastYea { | | struct LastYea { | |
| LastYea() : when(0), who(0xffffffff) { } | | LastYea() : when(0), who(0xffffffff) { } | |
| time_t when; | | time_t when; | |
| unsigned who; | | unsigned who; | |
| }; | | }; | |
| Atomic<LastYea> ly; | | Atomic<LastYea> ly; | |
| unsigned yea(unsigned memberId); // throws VoteException | | unsigned yea(unsigned memberId); // throws VoteException | |
| void _electSelf(); | | void _electSelf(); | |
|
| bool weAreFreshest(bool& allUp); | | bool weAreFreshest(bool& allUp, int& nTies); | |
| | | bool sleptLast; // slept last elect() pass | |
| public: | | public: | |
|
| Consensus(ReplSetImpl *t) : rs(*t) { } | | Consensus(ReplSetImpl *t) : rs(*t) { | |
| | | sleptLast = false; | |
| | | } | |
| int totalVotes() const; | | int totalVotes() const; | |
| bool aMajoritySeemsToBeUp() const; | | bool aMajoritySeemsToBeUp() const; | |
| void electSelf(); | | void electSelf(); | |
| void electCmdReceived(BSONObj, BSONObjBuilder*); | | void electCmdReceived(BSONObj, BSONObjBuilder*); | |
|
| | | void multiCommand(BSONObj cmd, list<Target>& L); | |
| }; | | }; | |
| | | | |
| /** most operations on a ReplSet object should be done while locked. */ | | /** most operations on a ReplSet object should be done while locked. */ | |
| class RSBase : boost::noncopyable { | | class RSBase : boost::noncopyable { | |
| private: | | private: | |
| mutex m; | | mutex m; | |
| int _locked; | | int _locked; | |
|
| | | ThreadLocalValue<bool> _lockedByMe; | |
| protected: | | protected: | |
| RSBase() : m("RSBase"), _locked(0) { } | | RSBase() : m("RSBase"), _locked(0) { } | |
| class lock : scoped_lock { | | class lock : scoped_lock { | |
| RSBase& _b; | | RSBase& _b; | |
| public: | | public: | |
| lock(RSBase* b) : scoped_lock(b->m), _b(*b) { | | lock(RSBase* b) : scoped_lock(b->m), _b(*b) { | |
|
| DEV assert(b->_locked == 0); | | DEV assert(_b._locked == 0); | |
| b->_locked++; | | _b._locked++; | |
| | | _b._lockedByMe.set(true); | |
| | | cout << "RSLOCKED" << endl; | |
| } | | } | |
| ~lock() { | | ~lock() { | |
|
| | | cout << "RSUNLOCKED" << endl; | |
| | | assert( _b._lockedByMe.get() ); | |
| DEV assert(_b._locked == 1); | | DEV assert(_b._locked == 1); | |
|
| | | _b._lockedByMe.set(false); | |
| _b._locked--; | | _b._locked--; | |
| } | | } | |
| }; | | }; | |
|
| | | public: | |
| | | /* for asserts */ | |
| bool locked() const { return _locked != 0; } | | bool locked() const { return _locked != 0; } | |
|
| | | | |
| | | /* if true, is locked, and was locked by this thread. note if false | |
| | | , it could be in the lock or not for another | |
| | | just for asserts & such so we can make the contracts clear on wh | |
| | | o locks what when. | |
| | | we don't use these locks that frequently, so the little bit of o | |
| | | verhead is fine. | |
| | | */ | |
| | | bool lockedByMe() { return _lockedByMe.get(); } | |
| }; | | }; | |
| | | | |
| /* information about the entire repl set, such as the various servers i
n the set, and their state */ | | /* information about the entire repl set, such as the various servers i
n the set, and their state */ | |
| /* note: We currently do not free mem when the set goes away - it is as
sumed the replset is a | | /* note: We currently do not free mem when the set goes away - it is as
sumed the replset is a | |
| singleton and long lived. | | singleton and long lived. | |
| */ | | */ | |
| class ReplSetImpl : RSBase { | | class ReplSetImpl : RSBase { | |
| public: | | public: | |
| /** info on our state if the replset isn't yet "up". for example,
if we are pre-initiation. */ | | /** info on our state if the replset isn't yet "up". for example,
if we are pre-initiation. */ | |
| enum StartupStatus { | | enum StartupStatus { | |
| | | | |
| skipping to change at line 133 | | skipping to change at line 154 | |
| static StartupStatus startupStatus; | | static StartupStatus startupStatus; | |
| static string startupStatusMsg; | | static string startupStatusMsg; | |
| static string stateAsStr(MemberState state); | | static string stateAsStr(MemberState state); | |
| static string stateAsHtml(MemberState state); | | static string stateAsHtml(MemberState state); | |
| | | | |
| /* todo thread */ | | /* todo thread */ | |
| void msgUpdateHBInfo(HeartbeatInfo); | | void msgUpdateHBInfo(HeartbeatInfo); | |
| bool isPrimary() const { return _myState == PRIMARY; } | | bool isPrimary() const { return _myState == PRIMARY; } | |
| bool isSecondary() const { return _myState == SECONDARY; } | | bool isSecondary() const { return _myState == SECONDARY; } | |
| | | | |
|
| | | //bool initiated() const { return curOpTime.initiated(); } | |
| | | | |
| | | OpTime lastOpTimeWritten; | |
| | | long long h; | |
| | | private: | |
| | | unsigned _selfId; // stored redundantly we hit this a lot | |
| | | | |
| private: | | private: | |
| Consensus elect; | | Consensus elect; | |
| bool ok() const { return _myState != FATAL; } | | bool ok() const { return _myState != FATAL; } | |
| | | | |
| void relinquish(); | | void relinquish(); | |
| void assumePrimary(); | | void assumePrimary(); | |
|
| | | void loadLastOpTimeWritten(); | |
| | | | |
| protected: | | protected: | |
| void _fillIsMaster(BSONObjBuilder&); | | void _fillIsMaster(BSONObjBuilder&); | |
| const ReplSetConfig& config() { return *_cfg; } | | const ReplSetConfig& config() { return *_cfg; } | |
| string name() const { return _name; } /* @return replica set's logi
cal name */ | | string name() const { return _name; } /* @return replica set's logi
cal name */ | |
| MemberState state() const { return _myState; } | | MemberState state() const { return _myState; } | |
| void _fatal(); | | void _fatal(); | |
| void _getOplogDiagsAsHtml(unsigned server_id, stringstream& ss) con
st; | | void _getOplogDiagsAsHtml(unsigned server_id, stringstream& ss) con
st; | |
| void _summarizeAsHtml(stringstream&) const; | | void _summarizeAsHtml(stringstream&) const; | |
| void _summarizeStatus(BSONObjBuilder&) const; // for replSetGetStat
us command | | void _summarizeStatus(BSONObjBuilder&) const; // for replSetGetStat
us command | |
| | | | |
| skipping to change at line 183 | | skipping to change at line 212 | |
| list<HostAndPort> memberHostnames() const; | | list<HostAndPort> memberHostnames() const; | |
| const Member* currentPrimary() const { return _currentPrimary; } | | const Member* currentPrimary() const { return _currentPrimary; } | |
| const ReplSetConfig::MemberCfg& myConfig() const { return _self->co
nfig(); } | | const ReplSetConfig::MemberCfg& myConfig() const { return _self->co
nfig(); } | |
| | | | |
| private: | | private: | |
| const Member *_currentPrimary; | | const Member *_currentPrimary; | |
| Member *_self; | | Member *_self; | |
| List1<Member> _members; /* all members of the set EXCEPT self. */ | | List1<Member> _members; /* all members of the set EXCEPT self. */ | |
| | | | |
| public: | | public: | |
|
| | | unsigned selfId() const { return _selfId; } | |
| shared_ptr<Manager> mgr; | | shared_ptr<Manager> mgr; | |
| | | | |
| private: | | private: | |
| Member* head() const { return _members.head(); } | | Member* head() const { return _members.head(); } | |
| Member* findById(unsigned id) const; | | Member* findById(unsigned id) const; | |
|
| void getTargets(list<Target>&); | | void _getTargets(list<Target>&, int &configVersion); | |
| | | void getTargets(list<Target>&, int &configVersion); | |
| void startThreads(); | | void startThreads(); | |
| friend class FeedbackThread; | | friend class FeedbackThread; | |
| friend class CmdReplSetElect; | | friend class CmdReplSetElect; | |
| friend class Member; | | friend class Member; | |
| friend class Manager; | | friend class Manager; | |
| friend class Consensus; | | friend class Consensus; | |
| }; | | }; | |
| | | | |
| class ReplSet : public ReplSetImpl { | | class ReplSet : public ReplSetImpl { | |
| public: | | public: | |
| | | | |
End of changes. 18 change blocks. |
| 6 lines changed or deleted | | 40 lines changed or added | |
|
| sock.h | | sock.h | |
| | | | |
| skipping to change at line 27 | | skipping to change at line 27 | |
| | | | |
| #pragma once | | #pragma once | |
| | | | |
| #include "../pch.h" | | #include "../pch.h" | |
| | | | |
| #include <stdio.h> | | #include <stdio.h> | |
| #include <sstream> | | #include <sstream> | |
| #include "goodies.h" | | #include "goodies.h" | |
| #include "../db/jsobj.h" | | #include "../db/jsobj.h" | |
| | | | |
|
| #define SOCK_FAMILY_UNKNOWN_ERROR 13078 | | | |
| | | | |
| namespace mongo { | | namespace mongo { | |
| | | | |
|
| | | const int SOCK_FAMILY_UNKNOWN_ERROR=13078; | |
| | | | |
| #if defined(_WIN32) | | #if defined(_WIN32) | |
| | | | |
| typedef short sa_family_t; | | typedef short sa_family_t; | |
| typedef int socklen_t; | | typedef int socklen_t; | |
| inline int getLastError() { | | inline int getLastError() { | |
| return WSAGetLastError(); | | return WSAGetLastError(); | |
| } | | } | |
| inline const char* gai_strerror(int code) { | | inline const char* gai_strerror(int code) { | |
| return ::gai_strerrorA(code); | | return ::gai_strerrorA(code); | |
| } | | } | |
| | | | |
| skipping to change at line 70 | | skipping to change at line 70 | |
| | | | |
| #include <sys/socket.h> | | #include <sys/socket.h> | |
| #include <sys/types.h> | | #include <sys/types.h> | |
| #include <sys/socket.h> | | #include <sys/socket.h> | |
| #include <sys/un.h> | | #include <sys/un.h> | |
| #include <netinet/in.h> | | #include <netinet/in.h> | |
| #include <netinet/tcp.h> | | #include <netinet/tcp.h> | |
| #include <arpa/inet.h> | | #include <arpa/inet.h> | |
| #include <errno.h> | | #include <errno.h> | |
| #include <netdb.h> | | #include <netdb.h> | |
|
| | | #ifdef __openbsd__ | |
| | | # include <sys/uio.h> | |
| | | #endif | |
| | | | |
| | | #ifndef AI_ADDRCONFIG | |
| | | # define AI_ADDRCONFIG 0 | |
| | | #endif | |
| | | | |
| namespace mongo { | | namespace mongo { | |
| | | | |
| inline void closesocket(int s) { | | inline void closesocket(int s) { | |
| close(s); | | close(s); | |
| } | | } | |
| const int INVALID_SOCKET = -1; | | const int INVALID_SOCKET = -1; | |
| typedef int SOCKET; | | typedef int SOCKET; | |
| | | | |
| inline void disableNagle(int sock) { | | inline void disableNagle(int sock) { | |
| | | | |
| skipping to change at line 114 | | skipping to change at line 121 | |
| #endif | | #endif | |
| | | | |
| inline string makeUnixSockPath(int port){ | | inline string makeUnixSockPath(int port){ | |
| return "/tmp/mongodb-" + BSONObjBuilder::numStr(port) + ".sock"; | | return "/tmp/mongodb-" + BSONObjBuilder::numStr(port) + ".sock"; | |
| } | | } | |
| | | | |
| inline void setSockTimeouts(int sock, int secs) { | | inline void setSockTimeouts(int sock, int secs) { | |
| struct timeval tv; | | struct timeval tv; | |
| tv.tv_sec = secs; | | tv.tv_sec = secs; | |
| tv.tv_usec = 0; | | tv.tv_usec = 0; | |
|
| massert( 13083, "unable to set SO_RCVTIMEO", | | bool report = logLevel > 3; // solaris doesn't provide these | |
| setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, (char *) &tv, siz | | DEV report = true; | |
| eof(tv) ) == 0 ); | | bool ok = setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, (char *) &tv, s | |
| massert( 13084, "unable to set SO_SNDTIMEO", | | izeof(tv) ) == 0; | |
| setsockopt(sock, SOL_SOCKET, SO_SNDTIMEO, (char *) &tv, siz | | if( report && !ok ) log() << "unabled to set SO_RCVTIMEO" << endl; | |
| eof(tv) ) == 0 ); | | ok = setsockopt(sock, SOL_SOCKET, SO_SNDTIMEO, (char *) &tv, sizeof | |
| | | (tv) ) == 0; | |
| | | DEV if( report && !ok ) log() << "unabled to set SO_RCVTIMEO" << en | |
| | | dl; | |
| } | | } | |
| | | | |
| // If an ip address is passed in, just return that. If a hostname is p
assed | | // If an ip address is passed in, just return that. If a hostname is p
assed | |
| // in, look up its ip and return that. Returns "" on failure. | | // in, look up its ip and return that. Returns "" on failure. | |
| string hostbyname(const char *hostname); | | string hostbyname(const char *hostname); | |
| | | | |
| void enableIPv6(bool state=true); | | void enableIPv6(bool state=true); | |
| bool IPv6Enabled(); | | bool IPv6Enabled(); | |
| | | | |
| struct SockAddr { | | struct SockAddr { | |
| | | | |
| skipping to change at line 284 | | skipping to change at line 293 | |
| } | | } | |
| | | | |
| static ListeningSockets* get(); | | static ListeningSockets* get(); | |
| | | | |
| private: | | private: | |
| mongo::mutex _mutex; | | mongo::mutex _mutex; | |
| set<int>* _sockets; | | set<int>* _sockets; | |
| static ListeningSockets* _instance; | | static ListeningSockets* _instance; | |
| }; | | }; | |
| | | | |
|
| #undef SOCK_FAMILY_UNKNOWN_ERROR | | | |
| | | | |
| } // namespace mongo | | } // namespace mongo | |
| | | | |
End of changes. 5 change blocks. |
| 10 lines changed or deleted | | 18 lines changed or added | |
|
| value.h | | value.h | |
|
| // value.h | | /* @file value.h | |
| | | concurrency helpers Atomic<T> and DiagStr | |
| | | */ | |
| | | | |
| /** | | /** | |
| * Copyright (C) 2008 10gen Inc. | | * Copyright (C) 2008 10gen Inc. | |
| * | | * | |
| * This program is free software: you can redistribute it and/or modify | | * This program is free software: you can redistribute it and/or modify | |
| * it under the terms of the GNU Affero General Public License, version 3
, | | * it under the terms of the GNU Affero General Public License, version 3
, | |
| * as published by the Free Software Foundation. | | * as published by the Free Software Foundation. | |
| * | | * | |
| * This program is distributed in the hope that it will be useful,b | | * This program is distributed in the hope that it will be useful,b | |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of | | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| | | | |
| skipping to change at line 23 | | skipping to change at line 25 | |
| * GNU Affero General Public License for more details. | | * GNU Affero General Public License for more details. | |
| * | | * | |
| * 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 | |
| | | | |
| namespace mongo { | | namespace mongo { | |
| | | | |
|
| /** this string COULD be mangled but with the double buffering, assumin | | | |
| g writes | | | |
| are infrequent, it's unlikely. thus, this is reasonable for lockless s | | | |
| etting of | | | |
| diagnostic strings, where their content isn't critical. | | | |
| */ | | | |
| class DiagStr { | | | |
| char buf1[256]; | | | |
| char buf2[256]; | | | |
| char *p; | | | |
| public: | | | |
| DiagStr() { | | | |
| memset(buf1, 0, 256); | | | |
| memset(buf2, 0, 256); | | | |
| p = buf1; | | | |
| } | | | |
| | | | |
| const char * get() const { return p; } | | | |
| | | | |
| void set(const char *s) { | | | |
| char *q = (p==buf1) ? buf2 : buf1; | | | |
| strncpy(q, s, 255); | | | |
| p = q; | | | |
| } | | | |
| }; | | | |
| | | | |
| extern mutex _atomicMutex; | | extern mutex _atomicMutex; | |
| | | | |
| /** atomic wrapper for a value. enters a mutex on each access. must | | /** atomic wrapper for a value. enters a mutex on each access. must | |
| be copyable. | | be copyable. | |
| */ | | */ | |
| template<typename T> | | template<typename T> | |
| class Atomic : boost::noncopyable { | | class Atomic : boost::noncopyable { | |
| T val; | | T val; | |
| public: | | public: | |
| Atomic<T>() { } | | Atomic<T>() { } | |
| | | | |
| skipping to change at line 74 | | skipping to change at line 52 | |
| return val; } | | return val; } | |
| | | | |
| class tran : private scoped_lock { | | class tran : private scoped_lock { | |
| Atomic<T>& _a; | | Atomic<T>& _a; | |
| public: | | public: | |
| tran(Atomic<T>& a) : scoped_lock(_atomicMutex), _a(a) { } | | tran(Atomic<T>& a) : scoped_lock(_atomicMutex), _a(a) { } | |
| T& ref() { return _a.val; } | | T& ref() { return _a.val; } | |
| }; | | }; | |
| }; | | }; | |
| | | | |
|
| | | /** this string COULD be mangled but with the double buffering, assumin | |
| | | g writes | |
| | | are infrequent, it's unlikely. thus, this is reasonable for lockless s | |
| | | etting of | |
| | | diagnostic strings, where their content isn't critical. | |
| | | */ | |
| | | class DiagStr { | |
| | | char buf1[256]; | |
| | | char buf2[256]; | |
| | | char *p; | |
| | | public: | |
| | | DiagStr() { | |
| | | memset(buf1, 0, 256); | |
| | | memset(buf2, 0, 256); | |
| | | p = buf1; | |
| | | } | |
| | | | |
| | | const char * get() const { return p; } | |
| | | | |
| | | void set(const char *s) { | |
| | | char *q = (p==buf1) ? buf2 : buf1; | |
| | | strncpy(q, s, 255); | |
| | | p = q; | |
| | | } | |
| | | }; | |
| | | | |
| } | | } | |
| | | | |
End of changes. 3 change blocks. |
| 27 lines changed or deleted | | 29 lines changed or added | |
|