0
0
mirror of https://github.com/mongodb/mongo.git synced 2024-12-01 09:32:32 +01:00
mongodb/db/scanandorder.h

135 lines
3.4 KiB
C
Raw Normal View History

2008-08-19 23:57:05 +02:00
// scanandorder.h
#pragma once
/* todo:
2008-08-22 00:05:13 +02:00
_ handle compound keys with differing directions. we don't handle this yet: neither here nor in indexes i think!!!
2008-08-19 23:57:05 +02:00
_ limit amount of data
*/
2008-08-22 00:05:13 +02:00
/* see also IndexDetails::getKeysFromObject, which needs some merging with this. */
2008-08-19 23:57:05 +02:00
2008-08-22 00:05:13 +02:00
class KeyType : boost::noncopyable {
public:
JSObj pattern; // e.g., { ts : -1 }
public:
KeyType(JSObj _keyPattern) {
pattern = _keyPattern;
assert( !pattern.isEmpty() );
}
2008-08-19 23:57:05 +02:00
2008-08-22 00:05:13 +02:00
// returns the key value for o
JSObj getKeyFromObject(JSObj o) {
return o.extractFields(pattern);
}
};
2008-08-19 23:57:05 +02:00
2008-08-22 00:05:13 +02:00
/* todo:
_ respect limit
_ check for excess mem usage
_ response size limit from runquery; push it up a bit.
2008-08-19 23:57:05 +02:00
*/
2008-08-22 00:05:13 +02:00
inline bool fillQueryResultFromObj(BufBuilder& b, set<string> *filter, JSObj& js) {
if( filter ) {
JSObj x;
bool ok = x.addFields(js, *filter) > 0;
if( ok )
b.append((void*) x.objdata(), x.objsize());
return ok;
}
b.append((void*) js.objdata(), js.objsize());
return true;
}
typedef multimap<JSObj,JSObj> BestMap;
2008-08-19 23:57:05 +02:00
class ScanAndOrder {
2008-10-05 01:42:18 +02:00
BestMap best; // key -> full object
int startFrom;
int limit; // max to send back.
KeyType order;
int dir;
unsigned approxSize;
void _add(JSObj& k, JSObj o) {
best.insert(make_pair(k,o));
}
// T may be iterator or reverse_iterator
void _addIfBetter(JSObj& k, JSObj o, BestMap::iterator i) {
const JSObj& worstBestKey = i->first;
int c = worstBestKey.woCompare(k);
if( (c<0 && dir<0) || (c>0&&dir>0) ) {
// k is better, 'upgrade'
best.erase(i);
_add(k, o);
}
}
2008-08-22 00:05:13 +02:00
2008-08-19 23:57:05 +02:00
public:
2008-10-05 01:42:18 +02:00
ScanAndOrder(int _startFrom, int _limit, JSObj _order) :
startFrom(_startFrom), order(_order) {
limit = _limit > 0 ? _limit + startFrom : 0x7fffffff;
approxSize = 0;
// todo: do order right for compound keys. this is temp.
dir = 1;
Element e = order.pattern.firstElement();
if( e.type() == Number && e.number() < 0 ) {
dir = -1;
}
}
void add(JSObj o) {
JSObj k = order.getKeyFromObject(o);
if( (int) best.size() < limit ) {
approxSize += k.objsize();
uassert( "too much key data for sort() with no index", approxSize < 1 * 1024 * 1024 );
_add(k, o);
return;
}
BestMap::iterator i;
if( dir < 0 )
i = best.begin();
else {
assert( best.end() != best.begin() );
i = best.end(); i--;
}
_addIfBetter(k, o, i);
}
template<class T>
void _fill(BufBuilder& b, set<string> *filter, int& nout, T begin, T end) {
int n = 0;
int nFilled = 0;
for( T i = begin; i != end; i++ ) {
n++;
if( n <= startFrom )
continue;
JSObj& o = i->second;
if( fillQueryResultFromObj(b, filter, o) ) {
nFilled++;
if( nFilled >= limit )
goto done;
uassert( "too much data for sort() with no index", b.len() < 4000000 ); // appserver limit
}
}
done:
nout = nFilled;
}
/* scanning complete. stick the query result in b for n objects. */
void fill(BufBuilder& b, set<string> *filter, int& nout) {
// for( BestMap::iterator i = best.begin(); i != best.end(); i++ )
// cout << " fill:" << i->first.toString() << endl;
// for( BestMap::reverse_iterator i = best.rbegin(); i != best.rend(); i++ )
// cout << " fillr:" << i->first.toString() << endl;
if( dir > 0 )
_fill(b, filter, nout, best.begin(), best.end());
else
_fill(b, filter, nout, best.rbegin(), best.rend());
}
2008-08-22 00:05:13 +02:00
};