1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93
|
/* scanandorder.cpp
Order results (that aren't already indexes and in order.)
*/
/**
* Copyright (C) 2008 10gen Inc.
*
* 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,
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "pch.h"
#include "scanandorder.h"
namespace mongo {
const unsigned ScanAndOrder::MaxScanAndOrderBytes = 32 * 1024 * 1024;
void ScanAndOrder::_add(BSONObj& k, BSONObj o, DiskLoc* loc) {
if (!loc) {
_best.insert(make_pair(k.getOwned(),o.getOwned()));
}
else {
BSONObjBuilder b;
b.appendElements(o);
b.append("$diskLoc", loc->toBSONObj());
_best.insert(make_pair(k.getOwned(), b.obj().getOwned()));
}
}
void ScanAndOrder::_addIfBetter(BSONObj& k, BSONObj o, BestMap::iterator i, DiskLoc* loc) {
/* todo : we don't correct _approxSize here. */
const BSONObj& worstBestKey = i->first;
int c = worstBestKey.woCompare(k, _order._spec.keyPattern);
if ( c > 0 ) {
// k is better, 'upgrade'
_best.erase(i);
_add(k, o, loc);
}
}
void ScanAndOrder::add(BSONObj o, DiskLoc* loc) {
assert( o.isValid() );
BSONObj k = _order.getKeyFromObject(o);
if ( k.isEmpty() ) {
return;
}
if ( (int) _best.size() < _limit ) {
_approxSize += k.objsize();
_approxSize += o.objsize();
/* note : adjust when bson return limit adjusts. note this limit should be a bit higher. */
uassert( 10128 , "too much data for sort() with no index. add an index or specify a smaller limit", _approxSize < MaxScanAndOrderBytes );
_add(k, o, loc);
return;
}
BestMap::iterator i;
assert( _best.end() != _best.begin() );
i = _best.end();
i--;
_addIfBetter(k, o, i, loc);
}
void ScanAndOrder::fill(BufBuilder& b, Projection *filter, int& nout ) const {
int n = 0;
int nFilled = 0;
for ( BestMap::const_iterator i = _best.begin(); i != _best.end(); i++ ) {
n++;
if ( n <= _startFrom )
continue;
const BSONObj& o = i->second;
fillQueryResultFromObj(b, filter, o);
nFilled++;
if ( nFilled >= _limit )
break;
uassert( 10129 , "too much data for sort() with no index", b.len() < (int)MaxScanAndOrderBytes ); // appserver limit
}
nout = nFilled;
}
} // namespace mongo
|