summaryrefslogtreecommitdiff
path: root/db/record.cpp
diff options
context:
space:
mode:
authorEliot Horowitz <eliot@10gen.com>2011-06-15 17:28:52 -0400
committerEliot Horowitz <eliot@10gen.com>2011-06-15 17:28:52 -0400
commit5a5a18228173a9bb8b345f5695e8126e6d288312 (patch)
tree7ca268e15faf23b5860cf9163baa0381824168a1 /db/record.cpp
parent06ed5bd1986e8bfc7f49401ddb464f8afd8b4e3b (diff)
downloadmongo-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.cpp206
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 );
+ }
+
+
+}