diff options
author | Eliot Horowitz <eliot@10gen.com> | 2011-06-15 17:28:52 -0400 |
---|---|---|
committer | Eliot Horowitz <eliot@10gen.com> | 2011-06-15 17:28:52 -0400 |
commit | 5a5a18228173a9bb8b345f5695e8126e6d288312 (patch) | |
tree | 7ca268e15faf23b5860cf9163baa0381824168a1 /db/record.cpp | |
parent | 06ed5bd1986e8bfc7f49401ddb464f8afd8b4e3b (diff) | |
download | mongo-5a5a18228173a9bb8b345f5695e8126e6d288312.tar.gz |
yielding with disk lock backend, hooked into updates by _id SERVER-2563
Diffstat (limited to 'db/record.cpp')
-rw-r--r-- | db/record.cpp | 206 |
1 files changed, 206 insertions, 0 deletions
diff --git a/db/record.cpp b/db/record.cpp new file mode 100644 index 00000000000..ff154f15e40 --- /dev/null +++ b/db/record.cpp @@ -0,0 +1,206 @@ +// record.cpp + +#include "../pch.h" +#include "pdfile.h" +#include "../util/processinfo.h" +#include "../util/message.h" + +#define _BACKWARD_BACKWARD_WARNING_H 1 + +#include <hash_map> +using namespace __gnu_cxx; + + +namespace mongo { + + namespace ps { + + enum State { + IN , OUT , UNK + }; + + enum Constants { + SliceSize = 65536 , + MaxChain = 20 , // intentionally very low + NumSlices = 10 , + RotateTimeSecs = 90 + }; + + int hash( size_t region ) { + return + abs( ( ( 7 + (int)(region & 0xFFFF) ) * + ( 11 + (int)( ( region >> 16 ) & 0xFFFF ) ) * + ( 13 + (int)( ( region >> 32 ) & 0xFFFF ) ) * + ( 17 + (int)( ( region >> 48 ) & 0xFFFF ) ) ) % SliceSize ); + } + + + /** + * simple hash map for region -> status + * this constitures a single region of time + * it does chaining, but very short chains + */ + class Slice { + + struct Entry { + size_t region; + unsigned long long value; + }; + + public: + + Slice() { + reset(); + } + + void reset() { + memset( _data , 0 , SliceSize * sizeof(Entry) ); + } + + State get( size_t region , short offset ) { + Entry * e = _get( region , false ); + if ( ! e ) + return UNK; + + return ( e->value & ( 1 << offset ) ) ? IN : OUT; + } + + /** + * @return true if added, false if full + */ + bool in( size_t region , short offset ) { + Entry * e = _get( region , true ); + if ( ! e ) + return false; + + e->value |= ( 1 << offset ); + return true; + } + + private: + + Entry* _get( size_t region , bool add ) { + int start = hash( region ); + for ( int i=0; i<MaxChain; i++ ) { + + int bucket = ( start + i ) % SliceSize; + + if ( _data[bucket].region == 0 ) { + if ( ! add ) + return 0; + + _data[bucket].region = region; + return &_data[bucket]; + } + + if ( _data[bucket].region == region ) { + return &_data[bucket]; + } + } + return 0; + } + + Entry _data[SliceSize]; + }; + + + /** + * this contains many slices of times + * the idea you put mem status in the current time slice + * and then after a certain period of time, it rolls off so we check again + */ + class Rolling { + + public: + Rolling() { + _curSlice = 0; + _lastRotate = Listener::getElapsedTimeMillis(); + } + + + /** + * after this call, we assume the page is in ram + * @return whether we know the page is in ram + */ + bool access( size_t region , short offset ) { + + RARELY { + long long now = Listener::getElapsedTimeMillis(); + OCCASIONALLY if ( now == 0 ) { + warning() << "Listener::getElapsedTimeMillis returing 0" << endl; + } + + if ( now - _lastRotate > ( 1000 * RotateTimeSecs ) ) { + _rotate(); + } + } + + for ( int i=0; i<NumSlices; i++ ) { + int pos = (_curSlice+i)%NumSlices; + State s = _slices[pos].get( region , offset ); + + if ( s == IN ) + return true; + + if ( s == OUT ) { + _slices[pos].in( region , offset ); + return false; + } + } + + // we weren't in any slice + // so add to cur + if ( ! _slices[_curSlice].in( region , offset ) ) { + _rotate(); + _slices[_curSlice].in( region , offset ); + } + return false; + } + + private: + + void _rotate() { + _curSlice = ( _curSlice + 1 ) % NumSlices; + _slices[_curSlice].reset(); + _lastRotate = Listener::getElapsedTimeMillis(); + } + + int _curSlice; + long long _lastRotate; + Slice _slices[NumSlices]; + }; + + } + + + + int __record_touch_dummy = 1; // this is used to make sure the compiler doesn't get too smart on us + void Record::touch( bool entireRecrd ) { + + if ( lengthWithHeaders > HeaderSize ) { // this also makes sure lengthWithHeaders is in memory + char * addr = data; + char * end = data + netLength(); + for ( ; addr <= end ; addr += 2048 ) + __record_touch_dummy += addr[0]; + } + + } + + bool Record::likelyInPhysicalMemory() { + static bool blockSupported = ProcessInfo::blockCheckSupported(); + static ps::Rolling rolling; + + const size_t page = (size_t)data >> 12; + const size_t region = page >> 6; + const size_t offset = page & 0x3f; + + if ( rolling.access( region , offset ) ) + return true; + + if ( ! blockSupported ) + return false; + return ProcessInfo::blockInMemory( data ); + } + + +} |