PageRenderTime 57ms CodeModel.GetById 31ms RepoModel.GetById 0ms app.codeStats 0ms

/src/mongo/db/ops/query.h

https://github.com/iandaniel/mongo
C Header | 322 lines | 195 code | 26 blank | 101 comment | 0 complexity | de80585cde9865de9020260bf840b934 MD5 | raw file
Possible License(s): BSD-3-Clause
  1. // query.h
  2. /**
  3. * Copyright (C) 2008 10gen Inc.
  4. *
  5. * This program is free software: you can redistribute it and/or modify
  6. * it under the terms of the GNU Affero General Public License, version 3,
  7. * as published by the Free Software Foundation.
  8. *
  9. * This program is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. * GNU Affero General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU Affero General Public License
  15. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  16. */
  17. #pragma once
  18. #include "mongo/pch.h"
  19. #include "../../util/net/message.h"
  20. #include "../dbmessage.h"
  21. #include "../jsobj.h"
  22. #include "../diskloc.h"
  23. #include "../explain.h"
  24. #include "../../s/d_chunk_manager.h"
  25. // struct QueryOptions, QueryResult, QueryResultFlags in:
  26. namespace mongo {
  27. class ParsedQuery;
  28. class QueryOptimizerCursor;
  29. class QueryPlanSummary;
  30. /**
  31. * Return a batch of results from a client OP_GET_MORE request.
  32. * 'cursorid' - The id of the cursor producing results.
  33. * 'isCursorAuthorized' - Set to true after a cursor with id 'cursorid' is authorized for use.
  34. */
  35. QueryResult* processGetMore(const char* ns,
  36. int ntoreturn,
  37. long long cursorid,
  38. CurOp& op,
  39. int pass,
  40. bool& exhaust,
  41. bool* isCursorAuthorized);
  42. string runQuery(Message& m, QueryMessage& q, CurOp& curop, Message &result);
  43. /** Exception indicating that a query should be retried from the beginning. */
  44. class QueryRetryException : public DBException {
  45. public:
  46. QueryRetryException() : DBException( "query retry exception" , 16083 ) {
  47. return;
  48. massert( 16083, "reserve 16083", true ); // Reserve 16083.
  49. }
  50. };
  51. /** Metadata about matching and loading a single candidate result document from a Cursor. */
  52. struct ResultDetails {
  53. ResultDetails();
  54. MatchDetails matchDetails; // Details on how the Matcher matched the query.
  55. bool match; // Matched the query, was not a dup, was not skipped etc.
  56. bool orderedMatch; // _match and belonged to an ordered query plan.
  57. bool loadedRecord; // Record was loaded (to match or return the document).
  58. bool chunkSkip; // Did not belong to an owned chunk range.
  59. };
  60. /** Interface for recording events that contribute to explain results. */
  61. class ExplainRecordingStrategy {
  62. public:
  63. ExplainRecordingStrategy( const ExplainQueryInfo::AncillaryInfo &ancillaryInfo );
  64. virtual ~ExplainRecordingStrategy() {}
  65. /** Note information about a single query plan. */
  66. virtual void notePlan( bool scanAndOrder, bool indexOnly ) {}
  67. /** Note an iteration of the query. */
  68. virtual void noteIterate( const ResultDetails& resultDetails ) {}
  69. /** Note that the query yielded. */
  70. virtual void noteYield() {}
  71. /** @return number of ordered matches noted. */
  72. virtual long long orderedMatches() const { return 0; }
  73. /** @return ExplainQueryInfo for a complete query. */
  74. shared_ptr<ExplainQueryInfo> doneQueryInfo();
  75. protected:
  76. /** @return ExplainQueryInfo for a complete query, to be implemented by subclass. */
  77. virtual shared_ptr<ExplainQueryInfo> _doneQueryInfo() = 0;
  78. private:
  79. ExplainQueryInfo::AncillaryInfo _ancillaryInfo;
  80. };
  81. /** No explain events are recorded. */
  82. class NoExplainStrategy : public ExplainRecordingStrategy {
  83. public:
  84. NoExplainStrategy();
  85. private:
  86. /** @asserts always. */
  87. virtual shared_ptr<ExplainQueryInfo> _doneQueryInfo();
  88. };
  89. class MatchCountingExplainStrategy : public ExplainRecordingStrategy {
  90. public:
  91. MatchCountingExplainStrategy( const ExplainQueryInfo::AncillaryInfo &ancillaryInfo );
  92. protected:
  93. virtual void _noteIterate( const ResultDetails& resultDetails ) = 0;
  94. private:
  95. virtual void noteIterate( const ResultDetails& resultDetails );
  96. virtual long long orderedMatches() const { return _orderedMatches; }
  97. long long _orderedMatches;
  98. };
  99. /** Record explain events for a simple cursor representing a single clause and plan. */
  100. class SimpleCursorExplainStrategy : public MatchCountingExplainStrategy {
  101. public:
  102. SimpleCursorExplainStrategy( const ExplainQueryInfo::AncillaryInfo &ancillaryInfo,
  103. const shared_ptr<Cursor> &cursor );
  104. private:
  105. virtual void notePlan( bool scanAndOrder, bool indexOnly );
  106. virtual void _noteIterate( const ResultDetails& resultDetails );
  107. virtual void noteYield();
  108. virtual shared_ptr<ExplainQueryInfo> _doneQueryInfo();
  109. shared_ptr<Cursor> _cursor;
  110. shared_ptr<ExplainSinglePlanQueryInfo> _explainInfo;
  111. };
  112. /**
  113. * Record explain events for a QueryOptimizerCursor, which may record some explain information
  114. * for multiple clauses and plans through an internal implementation.
  115. */
  116. class QueryOptimizerCursorExplainStrategy : public MatchCountingExplainStrategy {
  117. public:
  118. QueryOptimizerCursorExplainStrategy( const ExplainQueryInfo::AncillaryInfo &ancillaryInfo,
  119. const shared_ptr<QueryOptimizerCursor> &cursor );
  120. private:
  121. virtual void _noteIterate( const ResultDetails& resultDetails );
  122. virtual void noteYield();
  123. virtual shared_ptr<ExplainQueryInfo> _doneQueryInfo();
  124. shared_ptr<QueryOptimizerCursor> _cursor;
  125. };
  126. /** Interface for building a query response in a supplied BufBuilder. */
  127. class ResponseBuildStrategy {
  128. public:
  129. /**
  130. * @param queryPlan must be supplied if @param cursor is not a QueryOptimizerCursor and
  131. * results must be sorted or read with a covered index.
  132. */
  133. ResponseBuildStrategy( const ParsedQuery &parsedQuery, const shared_ptr<Cursor> &cursor,
  134. BufBuilder &buf );
  135. virtual ~ResponseBuildStrategy() {}
  136. /**
  137. * Handle the current iterate of the supplied cursor as a (possibly duplicate) match.
  138. * @return true if a match is found.
  139. * @param resultDetails details of how the result is matched and loaded.
  140. */
  141. virtual bool handleMatch( ResultDetails* resultDetails ) = 0;
  142. /**
  143. * Write all matches into the buffer, overwriting existing data.
  144. * @return number of matches written, or -1 if no op.
  145. */
  146. virtual int rewriteMatches() { return -1; }
  147. /** @return the number of matches that have been written to the buffer. */
  148. virtual int bufferedMatches() const = 0;
  149. /**
  150. * Callback when enough results have been read for the first batch, with potential handoff
  151. * to getMore.
  152. */
  153. virtual void finishedFirstBatch() {}
  154. /** Reset the buffer. */
  155. void resetBuf();
  156. protected:
  157. /**
  158. * Return the document for the current iterate. Implements the $returnKey option.
  159. * @param allowCovered enable covered index support.
  160. * @param resultDetails details of how the result is loaded.
  161. */
  162. BSONObj current( bool allowCovered, ResultDetails* resultDetails ) const;
  163. const ParsedQuery &_parsedQuery;
  164. shared_ptr<Cursor> _cursor;
  165. shared_ptr<QueryOptimizerCursor> _queryOptimizerCursor;
  166. BufBuilder &_buf;
  167. };
  168. /** Build strategy for a cursor returning in order results. */
  169. class OrderedBuildStrategy : public ResponseBuildStrategy {
  170. public:
  171. OrderedBuildStrategy( const ParsedQuery &parsedQuery, const shared_ptr<Cursor> &cursor,
  172. BufBuilder &buf );
  173. virtual bool handleMatch( ResultDetails* resultDetails );
  174. virtual int bufferedMatches() const { return _bufferedMatches; }
  175. private:
  176. int _skip;
  177. int _bufferedMatches;
  178. };
  179. class ScanAndOrder;
  180. /** Build strategy for a cursor returning out of order results. */
  181. class ReorderBuildStrategy : public ResponseBuildStrategy {
  182. public:
  183. static ReorderBuildStrategy* make( const ParsedQuery& parsedQuery,
  184. const shared_ptr<Cursor>& cursor,
  185. BufBuilder& buf,
  186. const QueryPlanSummary& queryPlan );
  187. virtual bool handleMatch( ResultDetails* resultDetails );
  188. /** Handle a match without performing deduping. */
  189. void _handleMatchNoDedup( ResultDetails* resultDetails );
  190. virtual int rewriteMatches();
  191. virtual int bufferedMatches() const { return _bufferedMatches; }
  192. private:
  193. ReorderBuildStrategy( const ParsedQuery& parsedQuery,
  194. const shared_ptr<Cursor>& cursor,
  195. BufBuilder& buf );
  196. void init( const QueryPlanSummary& queryPlan );
  197. ScanAndOrder *newScanAndOrder( const QueryPlanSummary &queryPlan ) const;
  198. shared_ptr<ScanAndOrder> _scanAndOrder;
  199. int _bufferedMatches;
  200. };
  201. /** Helper class for deduping DiskLocs */
  202. class DiskLocDupSet {
  203. public:
  204. /** @return true if dup, otherwise return false and insert. */
  205. bool getsetdup( const DiskLoc &loc ) {
  206. pair<set<DiskLoc>::iterator, bool> p = _dups.insert(loc);
  207. return !p.second;
  208. }
  209. private:
  210. set<DiskLoc> _dups;
  211. };
  212. /**
  213. * Build strategy for a QueryOptimizerCursor containing some in order and some out of order
  214. * candidate plans.
  215. */
  216. class HybridBuildStrategy : public ResponseBuildStrategy {
  217. public:
  218. static HybridBuildStrategy* make( const ParsedQuery& parsedQuery,
  219. const shared_ptr<QueryOptimizerCursor>& cursor,
  220. BufBuilder& buf );
  221. private:
  222. HybridBuildStrategy( const ParsedQuery &parsedQuery,
  223. const shared_ptr<QueryOptimizerCursor> &cursor,
  224. BufBuilder &buf );
  225. void init();
  226. virtual bool handleMatch( ResultDetails* resultDetails );
  227. virtual int rewriteMatches();
  228. virtual int bufferedMatches() const;
  229. virtual void finishedFirstBatch();
  230. bool handleReorderMatch( ResultDetails* resultDetails );
  231. DiskLocDupSet _scanAndOrderDups;
  232. OrderedBuildStrategy _orderedBuild;
  233. scoped_ptr<ReorderBuildStrategy> _reorderBuild;
  234. bool _reorderedMatches;
  235. };
  236. /**
  237. * Builds a query response with the help of an ExplainRecordingStrategy and a
  238. * ResponseBuildStrategy.
  239. */
  240. class QueryResponseBuilder {
  241. public:
  242. /**
  243. * @param queryPlan must be supplied if @param cursor is not a QueryOptimizerCursor and
  244. * results must be sorted or read with a covered index.
  245. */
  246. static QueryResponseBuilder *make( const ParsedQuery &parsedQuery,
  247. const shared_ptr<Cursor> &cursor,
  248. const QueryPlanSummary &queryPlan,
  249. const BSONObj &oldPlan );
  250. /** @return true if the current iterate matches and is added. */
  251. bool addMatch();
  252. /** Note that a yield occurred. */
  253. void noteYield();
  254. /** @return true if there are enough results to return the first batch. */
  255. bool enoughForFirstBatch() const;
  256. /** @return true if there are enough results to return the full result set. */
  257. bool enoughTotalResults() const;
  258. /**
  259. * Callback when enough results have been read for the first batch, with potential handoff
  260. * to getMore.
  261. */
  262. void finishedFirstBatch();
  263. /**
  264. * Set the data portion of the supplied Message to a buffer containing the query results.
  265. * @return the number of results in the buffer.
  266. */
  267. int handoff( Message &result );
  268. /** A chunk manager found at the beginning of the query. */
  269. ShardChunkManagerPtr chunkManager() const { return _chunkManager; }
  270. private:
  271. QueryResponseBuilder( const ParsedQuery &parsedQuery, const shared_ptr<Cursor> &cursor );
  272. void init( const QueryPlanSummary &queryPlan, const BSONObj &oldPlan );
  273. ShardChunkManagerPtr newChunkManager() const;
  274. shared_ptr<ExplainRecordingStrategy> newExplainRecordingStrategy
  275. ( const QueryPlanSummary &queryPlan, const BSONObj &oldPlan ) const;
  276. shared_ptr<ResponseBuildStrategy> newResponseBuildStrategy
  277. ( const QueryPlanSummary &queryPlan );
  278. /**
  279. * @return true if the cursor's document matches the query.
  280. * @param resultDetails describes how the document was matched and loaded.
  281. */
  282. bool currentMatches( ResultDetails* resultDetails );
  283. /**
  284. * @return true if the cursor's document is in a valid chunk range.
  285. * @param resultDetails describes how the document was matched and loaded.
  286. */
  287. bool chunkMatches( ResultDetails* resultDetails );
  288. const ParsedQuery &_parsedQuery;
  289. shared_ptr<Cursor> _cursor;
  290. shared_ptr<QueryOptimizerCursor> _queryOptimizerCursor;
  291. BufBuilder _buf;
  292. ShardChunkManagerPtr _chunkManager;
  293. shared_ptr<ExplainRecordingStrategy> _explain;
  294. shared_ptr<ResponseBuildStrategy> _builder;
  295. };
  296. } // namespace mongo