00001
00002
00003
00004
00021 #pragma once
00022
00023 namespace mongo {
00024
00025
00026
00027
00028
00029
00030
00031
00032 class KeyType : boost::noncopyable {
00033 public:
00034 BSONObj pattern;
00035 public:
00036 KeyType(BSONObj _keyPattern) {
00037 pattern = _keyPattern;
00038 assert( !pattern.isEmpty() );
00039 }
00040
00041
00042 BSONObj getKeyFromObject(BSONObj o) {
00043 return o.extractFields(pattern,true);
00044 }
00045 };
00046
00047
00048
00049
00050
00051
00052
00053 inline void fillQueryResultFromObj(BufBuilder& bb, Projection *filter, const BSONObj& js, DiskLoc* loc=NULL) {
00054 if ( filter ) {
00055 BSONObjBuilder b( bb );
00056 filter->transform( js , b );
00057 if (loc)
00058 b.append("$diskLoc", loc->toBSONObj());
00059 b.done();
00060 }
00061 else if (loc) {
00062 BSONObjBuilder b( bb );
00063 b.appendElements(js);
00064 b.append("$diskLoc", loc->toBSONObj());
00065 b.done();
00066 }
00067 else {
00068 bb.appendBuf((void*) js.objdata(), js.objsize());
00069 }
00070 }
00071
00072 typedef multimap<BSONObj,BSONObj,BSONObjCmp> BestMap;
00073 class ScanAndOrder {
00074 BestMap best;
00075 int startFrom;
00076 int limit;
00077 KeyType order;
00078 unsigned approxSize;
00079
00080 void _add(BSONObj& k, BSONObj o, DiskLoc* loc) {
00081 if (!loc) {
00082 best.insert(make_pair(k.getOwned(),o.getOwned()));
00083 }
00084 else {
00085 BSONObjBuilder b;
00086 b.appendElements(o);
00087 b.append("$diskLoc", loc->toBSONObj());
00088 best.insert(make_pair(k.getOwned(), b.obj().getOwned()));
00089 }
00090 }
00091
00092 void _addIfBetter(BSONObj& k, BSONObj o, BestMap::iterator i, DiskLoc* loc) {
00093
00094 const BSONObj& worstBestKey = i->first;
00095 int c = worstBestKey.woCompare(k, order.pattern);
00096 if ( c > 0 ) {
00097
00098 best.erase(i);
00099 _add(k, o, loc);
00100 }
00101 }
00102
00103 public:
00104 ScanAndOrder(int _startFrom, int _limit, BSONObj _order) :
00105 best( BSONObjCmp( _order ) ),
00106 startFrom(_startFrom), order(_order) {
00107 limit = _limit > 0 ? _limit + startFrom : 0x7fffffff;
00108 approxSize = 0;
00109 }
00110
00111 int size() const {
00112 return best.size();
00113 }
00114
00115 void add(BSONObj o, DiskLoc* loc) {
00116 assert( o.isValid() );
00117 BSONObj k = order.getKeyFromObject(o);
00118 if ( (int) best.size() < limit ) {
00119 approxSize += k.objsize();
00120 approxSize += o.objsize();
00121
00122
00123 uassert( 10128 , "too much data for sort() with no index. add an index or specify a smaller limit", approxSize < 32 * 1024 * 1024 );
00124
00125 _add(k, o, loc);
00126 return;
00127 }
00128 BestMap::iterator i;
00129 assert( best.end() != best.begin() );
00130 i = best.end();
00131 i--;
00132 _addIfBetter(k, o, i, loc);
00133 }
00134
00135 void _fill(BufBuilder& b, Projection *filter, int& nout, BestMap::iterator begin, BestMap::iterator end) {
00136 int n = 0;
00137 int nFilled = 0;
00138 for ( BestMap::iterator i = begin; i != end; i++ ) {
00139 n++;
00140 if ( n <= startFrom )
00141 continue;
00142 BSONObj& o = i->second;
00143 fillQueryResultFromObj(b, filter, o);
00144 nFilled++;
00145 if ( nFilled >= limit )
00146 break;
00147 uassert( 10129 , "too much data for sort() with no index", b.len() < 4000000 );
00148 }
00149 nout = nFilled;
00150 }
00151
00152
00153 void fill(BufBuilder& b, Projection *filter, int& nout) {
00154 _fill(b, filter, nout, best.begin(), best.end());
00155 }
00156
00157 };
00158
00159 }