concurrency.h | concurrency.h | |||
---|---|---|---|---|
skipping to change at line 116 | skipping to change at line 116 | |||
* < 0 read lock | * < 0 read lock | |||
*/ | */ | |||
int getState(){ return _state.get(); } | int getState(){ return _state.get(); } | |||
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()); } | |||
void lock() { | bool _checkWriteLockAlready(){ | |||
//DEV cout << "LOCK" << endl; | //DEV cout << "LOCK" << endl; | |||
DEV assert( haveClient() ); | DEV assert( haveClient() ); | |||
int s = _state.get(); | int s = _state.get(); | |||
if( s > 0 ) { | if( s > 0 ) { | |||
_state.set(s+1); | _state.set(s+1); | |||
return; | return true; | |||
} | } | |||
massert( 10293 , (string)"internal error: locks are not upgrade able: " + sayClientState() , s == 0 ); | massert( 10293 , (string)"internal error: locks are not upgrade able: " + sayClientState() , s == 0 ); | |||
return false; | ||||
} | ||||
void lock() { | ||||
if ( _checkWriteLockAlready() ) | ||||
return; | ||||
_state.set(1); | _state.set(1); | |||
curopWaitingForLock( 1 ); | curopWaitingForLock( 1 ); | |||
_m.lock(); | _m.lock(); | |||
curopGotLock(); | curopGotLock(); | |||
_minfo.entered(); | _minfo.entered(); | |||
} | } | |||
bool lock_try() { | ||||
if ( _checkWriteLockAlready() ) | ||||
return true; | ||||
curopWaitingForLock( 1 ); | ||||
boost::system_time until = get_system_time(); | ||||
until += boost::posix_time::milliseconds(0); | ||||
bool got = _m.timed_lock( until ); | ||||
curopGotLock(); | ||||
if ( got ){ | ||||
_minfo.entered(); | ||||
_state.set(1); | ||||
} | ||||
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); | |||
skipping to change at line 230 | skipping to change at line 260 | |||
/* this will be for old versions of boost */ | /* this will be for old versions of boost */ | |||
class MongoMutex { | class MongoMutex { | |||
MutexInfo _minfo; | MutexInfo _minfo; | |||
boost::recursive_mutex m; | boost::recursive_mutex m; | |||
ThreadLocalValue<bool> _releasedEarly; | ThreadLocalValue<bool> _releasedEarly; | |||
public: | public: | |||
MongoMutex() { } | MongoMutex() { } | |||
void lock() { | void lock() { | |||
#ifdef HAVE_READLOCK | #ifdef HAVE_READLOCK | |||
m.lock(); | m.lock(); | |||
#error this should be impossible? | ||||
#else | #else | |||
boost::detail::thread::lock_ops<boost::recursive_mutex>::lock(m ); | boost::detail::thread::lock_ops<boost::recursive_mutex>::lock(m ); | |||
#endif | #endif | |||
_minfo.entered(); | _minfo.entered(); | |||
} | } | |||
bool lock_try(){ | ||||
lock(); | ||||
return true; | ||||
} | ||||
void releaseEarly() { | void releaseEarly() { | |||
assertWriteLocked(); // aso must not be recursive, although we don't verify that in the old boost version | assertWriteLocked(); // aso must not be recursive, although we don't verify that in the old boost version | |||
assert( !_releasedEarly.get() ); | assert( !_releasedEarly.get() ); | |||
_releasedEarly.set(true); | _releasedEarly.set(true); | |||
_unlock(); | _unlock(); | |||
} | } | |||
void _unlock() { | void _unlock() { | |||
_minfo.leaving(); | _minfo.leaving(); | |||
#ifdef HAVE_READLOCK | #ifdef HAVE_READLOCK | |||
skipping to change at line 330 | skipping to change at line 366 | |||
dbunlocking_read(); | dbunlocking_read(); | |||
dbMutex.unlock_shared(); | dbMutex.unlock_shared(); | |||
} | } | |||
} | } | |||
bool got(){ | bool got(){ | |||
return _got; | return _got; | |||
} | } | |||
bool _got; | bool _got; | |||
}; | }; | |||
struct writelocktry { | ||||
writelocktry( const string&ns ){ | ||||
_got = dbMutex.lock_try(); | ||||
} | ||||
~writelocktry() { | ||||
if ( _got ){ | ||||
dbunlocking_write(); | ||||
dbMutex.unlock(); | ||||
} | ||||
} | ||||
bool got(){ | ||||
return _got; | ||||
} | ||||
bool _got; | ||||
}; | ||||
struct atleastreadlock { | struct atleastreadlock { | |||
atleastreadlock( const string& ns ){ | atleastreadlock( const string& ns ){ | |||
_prev = dbMutex.getState(); | _prev = dbMutex.getState(); | |||
if ( _prev == 0 ) | if ( _prev == 0 ) | |||
dbMutex.lock_shared(); | dbMutex.lock_shared(); | |||
} | } | |||
~atleastreadlock(){ | ~atleastreadlock(){ | |||
if ( _prev == 0 ) | if ( _prev == 0 ) | |||
dbMutex.unlock_shared(); | dbMutex.unlock_shared(); | |||
} | } | |||
End of changes. 8 change blocks. | ||||
2 lines changed or deleted | 54 lines changed or added | |||
database.h | database.h | |||
---|---|---|---|---|
skipping to change at line 156 | skipping to change at line 156 | |||
throw; | throw; | |||
} | } | |||
if ( preallocateOnly ) | if ( preallocateOnly ) | |||
delete p; | delete p; | |||
else | else | |||
files[n] = p; | files[n] = p; | |||
} | } | |||
return preallocateOnly ? 0 : p; | return preallocateOnly ? 0 : p; | |||
} | } | |||
MongoDataFile* addAFile( int sizeNeeded = 0, bool preallocateNextFi le = false ) { | MongoDataFile* addAFile( int sizeNeeded, bool preallocateNextFile ) { | |||
int n = (int) files.size(); | int n = (int) files.size(); | |||
MongoDataFile *ret = getFile( n, sizeNeeded ); | MongoDataFile *ret = getFile( n, sizeNeeded ); | |||
if ( preallocateNextFile ) | if ( preallocateNextFile ) | |||
preallocateAFile(); | preallocateAFile(); | |||
return ret; | return ret; | |||
} | } | |||
// safe to call this multiple times - the implementation will only preallocate one file | // safe to call this multiple times - the implementation will only preallocate one file | |||
void preallocateAFile() { | void preallocateAFile() { | |||
int n = (int) files.size(); | int n = (int) files.size(); | |||
getFile( n, 0, true ); | getFile( n, 0, true ); | |||
} | } | |||
MongoDataFile* suitableFile( int sizeNeeded ) { | MongoDataFile* suitableFile( int sizeNeeded, bool preallocate ) { | |||
MongoDataFile* f = newestFile(); | MongoDataFile* f = newestFile(); | |||
if ( !f ) { | ||||
f = addAFile( sizeNeeded, preallocate ); | ||||
} | ||||
for ( int i = 0; i < 8; i++ ) { | for ( int i = 0; i < 8; i++ ) { | |||
if ( f->getHeader()->unusedLength >= sizeNeeded ) | if ( f->getHeader()->unusedLength >= sizeNeeded ) | |||
break; | break; | |||
f = addAFile( sizeNeeded ); | f = addAFile( sizeNeeded, preallocate ); | |||
if ( f->getHeader()->fileLength >= MongoDataFile::maxSize() ) // this is as big as they get so might as well stop | if ( f->getHeader()->fileLength >= MongoDataFile::maxSize() ) // this is as big as they get so might as well stop | |||
break; | break; | |||
} | } | |||
return f; | return f; | |||
} | } | |||
Extent* allocExtent( const char *ns, int size, bool capped ) { | Extent* allocExtent( const char *ns, int size, bool capped ) { | |||
Extent *e = DataFileMgr::allocFromFreeList( ns, size, capped ); | Extent *e = DataFileMgr::allocFromFreeList( ns, size, capped ); | |||
if( e ) return e; | if( e ) return e; | |||
return suitableFile( size )->createExtent( ns, size, capped ); | return suitableFile( size, !capped )->createExtent( ns, size, c apped ); | |||
} | } | |||
MongoDataFile* newestFile() { | MongoDataFile* newestFile() { | |||
int n = (int) files.size(); | int n = (int) files.size(); | |||
if ( n > 0 ) n--; | if ( n > 0 ) { | |||
n--; | ||||
} else { | ||||
return 0; | ||||
} | ||||
return getFile(n); | return getFile(n); | |||
} | } | |||
/** | /** | |||
* @return true if success, false otherwise | * @return true if success, false otherwise | |||
*/ | */ | |||
bool setProfilingLevel( int newLevel , string& errmsg ); | bool setProfilingLevel( int newLevel , string& errmsg ); | |||
void finishInit(); | void finishInit(); | |||
End of changes. 6 change blocks. | ||||
5 lines changed or deleted | 12 lines changed or added | |||
update.h | update.h | |||
---|---|---|---|---|
skipping to change at line 415 | skipping to change at line 415 | |||
// TODO: should we convert this to $set? | // TODO: should we convert this to $set? | |||
return false; | return false; | |||
default: | default: | |||
return false; | return false; | |||
} | } | |||
} | } | |||
void appendForOpLog( BSONObjBuilder& b ) const { | void appendForOpLog( BSONObjBuilder& b ) const { | |||
if ( incType ){ | if ( incType ){ | |||
BSONObjBuilder bb( b.subobjStart( "$set" ) ); | BSONObjBuilder bb( b.subobjStart( "$set" ) ); | |||
appendIncValue( bb ); | appendIncValue( bb , true ); | |||
bb.done(); | bb.done(); | |||
return; | return; | |||
} | } | |||
const char * name = fixedOpName ? fixedOpName : Mod::modNames[o p()]; | const char * name = fixedOpName ? fixedOpName : Mod::modNames[o p()]; | |||
BSONObjBuilder bb( b.subobjStart( name ) ); | BSONObjBuilder bb( b.subobjStart( name ) ); | |||
if ( fixed ) | if ( fixed ) | |||
bb.appendAs( *fixed , m->fieldName ); | bb.appendAs( *fixed , m->fieldName ); | |||
else | else | |||
bb.appendAs( m->elt , m->fieldName ); | bb.appendAs( m->elt , m->fieldName ); | |||
bb.done(); | bb.done(); | |||
} | } | |||
template< class Builder > | template< class Builder > | |||
void apply( Builder& b , BSONElement in ){ | void apply( Builder& b , BSONElement in ){ | |||
m->apply( b , in , *this ); | m->apply( b , in , *this ); | |||
} | } | |||
template< class Builder > | template< class Builder > | |||
void appendIncValue( Builder& b ) const { | void appendIncValue( Builder& b , bool useFullName ) const { | |||
const char * n = useFullName ? m->fieldName : m->shortFieldName | ||||
; | ||||
switch ( incType ){ | switch ( incType ){ | |||
case NumberDouble: | case NumberDouble: | |||
b.append( m->shortFieldName , incdouble ); break; | b.append( n , incdouble ); break; | |||
case NumberLong: | case NumberLong: | |||
b.append( m->shortFieldName , inclong ); break; | b.append( n , inclong ); break; | |||
case NumberInt: | case NumberInt: | |||
b.append( m->shortFieldName , incint ); break; | b.append( n , incint ); break; | |||
default: | default: | |||
assert(0); | assert(0); | |||
} | } | |||
} | } | |||
}; | }; | |||
/** | /** | |||
* this is used to hold state, meta data while applying a ModSet to a B SONObj | * this is used to hold state, meta data while applying a ModSet to a B SONObj | |||
* the goal is to make ModSet const so its re-usable | * the goal is to make ModSet const so its re-usable | |||
*/ | */ | |||
End of changes. 5 change blocks. | ||||
5 lines changed or deleted | 8 lines changed or added | |||