diff options
author | Jason Rassi <rassi@10gen.com> | 2015-11-18 17:31:32 -0500 |
---|---|---|
committer | Jason Rassi <rassi@10gen.com> | 2015-11-18 17:38:27 -0500 |
commit | 23136883e394b73cbc26f873cd0276779adef3df (patch) | |
tree | b53259aeeaeb8a7e7450796dec662157d9b0a44d /src/mongo/db/matcher | |
parent | 7bac6c8f64019082f205c7606c65f173972960a3 (diff) | |
download | mongo-23136883e394b73cbc26f873cd0276779adef3df.tar.gz |
SERVER-19510 Move text query parsing to TextMatchExpression::init()
- Introduces FTSQuery, which is now the base class for FTSQueryImpl.
- Introduces a derived class FTSQueryNoop (which
TextNoOpMatchExpression now wraps). libfts_query_noop is now linked
into db/matcher/expressions.
- TextMatchExpression now parses the text query (which acquires a
collection lock as part of the parsing process), and TextNode now
stores a parsed version of the query. The FTSQuery::parse() call in
buildStages() is removed.
Behavior change: $text against a non-existent collection now returns
an error, instead of an empty result set.
Diffstat (limited to 'src/mongo/db/matcher')
-rw-r--r-- | src/mongo/db/matcher/SConscript | 18 | ||||
-rw-r--r-- | src/mongo/db/matcher/expression_text.cpp | 72 | ||||
-rw-r--r-- | src/mongo/db/matcher/expression_text.h | 14 | ||||
-rw-r--r-- | src/mongo/db/matcher/expression_text_base.cpp | 36 | ||||
-rw-r--r-- | src/mongo/db/matcher/expression_text_base.h | 31 | ||||
-rw-r--r-- | src/mongo/db/matcher/expression_text_noop.cpp | 23 | ||||
-rw-r--r-- | src/mongo/db/matcher/expression_text_noop.h | 10 | ||||
-rw-r--r-- | src/mongo/db/matcher/extensions_callback_noop.cpp | 4 | ||||
-rw-r--r-- | src/mongo/db/matcher/extensions_callback_real.cpp | 4 |
9 files changed, 121 insertions, 91 deletions
diff --git a/src/mongo/db/matcher/SConscript b/src/mongo/db/matcher/SConscript index af686b9f96b..d8c4fbd8299 100644 --- a/src/mongo/db/matcher/SConscript +++ b/src/mongo/db/matcher/SConscript @@ -47,6 +47,7 @@ env.Library( '$BUILD_DIR/mongo/base', '$BUILD_DIR/mongo/bson/util/bson_extract', '$BUILD_DIR/mongo/db/common', + '$BUILD_DIR/mongo/db/fts/fts_query_noop', '$BUILD_DIR/third_party/shim_pcrecpp', 'path', ], @@ -123,26 +124,19 @@ env.CppUnitTest( ) env.Library( - target='expressions_text', - source=[ - 'expression_text.cpp', - ], - LIBDEPS=[ - '$BUILD_DIR/mongo/db/fts/base', - 'expressions', - ], -) - -env.Library( target='expressions_mongod_only', source=[ 'extensions_callback_real.cpp', + 'expression_text.cpp', 'expression_where.cpp', ], LIBDEPS=[ '$BUILD_DIR/mongo/db/auth/authorization_manager_global', '$BUILD_DIR/mongo/scripting/scripting_server', 'expressions', - 'expressions_text', + ], + LIBDEPS_TAGS=[ + # Depends on symbols from serverOnlyFiles. + 'incomplete', ], ) diff --git a/src/mongo/db/matcher/expression_text.cpp b/src/mongo/db/matcher/expression_text.cpp index 8ee279efc1d..b97c2ce2780 100644 --- a/src/mongo/db/matcher/expression_text.cpp +++ b/src/mongo/db/matcher/expression_text.cpp @@ -32,34 +32,76 @@ #include "mongo/db/matcher/expression_text.h" +#include "mongo/db/catalog/collection.h" +#include "mongo/db/db_raii.h" #include "mongo/db/fts/fts_language.h" +#include "mongo/db/fts/fts_spec.h" +#include "mongo/db/index/fts_access_method.h" #include "mongo/stdx/memory.h" namespace mongo { -TextMatchExpression::TextMatchExpression(TextParams params) - : TextMatchExpressionBase(std::move(params)) {} +Status TextMatchExpression::init(OperationContext* txn, + const NamespaceString& nss, + TextParams params) { + _ftsQuery.setQuery(std::move(params.query)); + _ftsQuery.setLanguage(std::move(params.language)); + _ftsQuery.setCaseSensitive(params.caseSensitive); + _ftsQuery.setDiacriticSensitive(params.diacriticSensitive); -Status TextMatchExpression::init() { - // Validate language, but defer construction of FTSQueryImpl (which requires access to the - // target namespace) until stage building time. - if (!getLanguage().empty()) { - if (!fts::FTSLanguage::make(getLanguage(), fts::TEXT_INDEX_VERSION_2).isOK()) { - return {ErrorCodes::BadValue, "$language specifies unsupported language"}; + fts::TextIndexVersion version; + { + // Find text index. + ScopedTransaction transaction(txn, MODE_IS); + AutoGetDb autoDb(txn, nss.db(), MODE_IS); + Lock::CollectionLock collLock(txn->lockState(), nss.ns(), MODE_IS); + Database* db = autoDb.getDb(); + if (!db) { + return {ErrorCodes::IndexNotFound, + str::stream() << "text index required for $text query (no such collection '" + << nss.ns() << "')"}; } + Collection* collection = db->getCollection(nss); + if (!collection) { + return {ErrorCodes::IndexNotFound, + str::stream() << "text index required for $text query (no such collection '" + << nss.ns() << "')"}; + } + std::vector<IndexDescriptor*> idxMatches; + collection->getIndexCatalog()->findIndexByType(txn, IndexNames::TEXT, idxMatches); + if (idxMatches.empty()) { + return {ErrorCodes::IndexNotFound, "text index required for $text query"}; + } + if (idxMatches.size() > 1) { + return {ErrorCodes::IndexNotFound, "more than one text index found for $text query"}; + } + invariant(idxMatches.size() == 1); + IndexDescriptor* index = idxMatches[0]; + const FTSAccessMethod* fam = + static_cast<FTSAccessMethod*>(collection->getIndexCatalog()->getIndex(index)); + invariant(fam); + + // Extract version and default language from text index. + version = fam->getSpec().getTextIndexVersion(); + if (_ftsQuery.getLanguage().empty()) { + _ftsQuery.setLanguage(fam->getSpec().defaultLanguage().str()); + } + } + + Status parseStatus = _ftsQuery.parse(version); + if (!parseStatus.isOK()) { + return parseStatus; } return initPath("_fts"); } std::unique_ptr<MatchExpression> TextMatchExpression::shallowClone() const { - TextParams params; - params.query = getQuery(); - params.language = getLanguage(); - params.caseSensitive = getCaseSensitive(); - params.diacriticSensitive = getDiacriticSensitive(); - auto expr = stdx::make_unique<TextMatchExpression>(std::move(params)); - expr->init(); + auto expr = stdx::make_unique<TextMatchExpression>(); + // We initialize _ftsQuery here directly rather than calling init(), to avoid needing to examine + // the index catalog. + expr->_ftsQuery = _ftsQuery; + invariantOK(expr->initPath("_fts")); if (getTag()) { expr->setTag(getTag()->clone()); } diff --git a/src/mongo/db/matcher/expression_text.h b/src/mongo/db/matcher/expression_text.h index dfe4cbd8204..3bd44b29da3 100644 --- a/src/mongo/db/matcher/expression_text.h +++ b/src/mongo/db/matcher/expression_text.h @@ -30,17 +30,27 @@ #pragma once +#include "mongo/db/fts/fts_query_impl.h" #include "mongo/db/matcher/expression_text_base.h" +#include "mongo/db/namespace_string.h" namespace mongo { +class NamespaceString; +class OperationContext; + class TextMatchExpression : public TextMatchExpressionBase { public: - TextMatchExpression(TextParams params); + Status init(OperationContext* txn, const NamespaceString& nss, TextParams params); - Status init(); + const fts::FTSQuery& getFTSQuery() const final { + return _ftsQuery; + } std::unique_ptr<MatchExpression> shallowClone() const final; + +private: + fts::FTSQueryImpl _ftsQuery; }; } // namespace mongo diff --git a/src/mongo/db/matcher/expression_text_base.cpp b/src/mongo/db/matcher/expression_text_base.cpp index 04b62ecd6b1..82fa7f9fd3e 100644 --- a/src/mongo/db/matcher/expression_text_base.cpp +++ b/src/mongo/db/matcher/expression_text_base.cpp @@ -30,23 +30,21 @@ #include "mongo/db/matcher/expression_text_base.h" +#include "mongo/db/fts/fts_query.h" + namespace mongo { const bool TextMatchExpressionBase::kCaseSensitiveDefault = false; const bool TextMatchExpressionBase::kDiacriticSensitiveDefault = false; -TextMatchExpressionBase::TextMatchExpressionBase(TextParams params) - : LeafMatchExpression(TEXT), - _query(std::move(params.query)), - _language(std::move(params.language)), - _caseSensitive(params.caseSensitive), - _diacriticSensitive(params.diacriticSensitive) {} +TextMatchExpressionBase::TextMatchExpressionBase() : LeafMatchExpression(TEXT) {} void TextMatchExpressionBase::debugString(StringBuilder& debug, int level) const { + const fts::FTSQuery& ftsQuery = getFTSQuery(); _debugAddSpace(debug, level); - debug << "TEXT : query=" << _query << ", language=" << _language - << ", caseSensitive=" << _caseSensitive << ", diacriticSensitive=" << _diacriticSensitive - << ", tag="; + debug << "TEXT : query=" << ftsQuery.getQuery() << ", language=" << ftsQuery.getLanguage() + << ", caseSensitive=" << ftsQuery.getCaseSensitive() + << ", diacriticSensitive=" << ftsQuery.getDiacriticSensitive() << ", tag="; MatchExpression::TagData* td = getTag(); if (NULL != td) { td->debugString(&debug); @@ -57,9 +55,11 @@ void TextMatchExpressionBase::debugString(StringBuilder& debug, int level) const } void TextMatchExpressionBase::toBSON(BSONObjBuilder* out) const { + const fts::FTSQuery& ftsQuery = getFTSQuery(); out->append("$text", - BSON("$search" << _query << "$language" << _language << "$caseSensitive" - << _caseSensitive << "$diacriticSensitive" << _diacriticSensitive)); + BSON("$search" << ftsQuery.getQuery() << "$language" << ftsQuery.getLanguage() + << "$caseSensitive" << ftsQuery.getCaseSensitive() + << "$diacriticSensitive" << ftsQuery.getDiacriticSensitive())); } bool TextMatchExpressionBase::equivalent(const MatchExpression* other) const { @@ -68,19 +68,7 @@ bool TextMatchExpressionBase::equivalent(const MatchExpression* other) const { } const TextMatchExpressionBase* realOther = static_cast<const TextMatchExpressionBase*>(other); - if (realOther->getQuery() != _query) { - return false; - } - if (realOther->getLanguage() != _language) { - return false; - } - if (realOther->getCaseSensitive() != _caseSensitive) { - return false; - } - if (realOther->getDiacriticSensitive() != _diacriticSensitive) { - return false; - } - return true; + return getFTSQuery().equivalent(realOther->getFTSQuery()); } } // namespace mongo diff --git a/src/mongo/db/matcher/expression_text_base.h b/src/mongo/db/matcher/expression_text_base.h index 8ca25cf60eb..187a91bb2d4 100644 --- a/src/mongo/db/matcher/expression_text_base.h +++ b/src/mongo/db/matcher/expression_text_base.h @@ -32,6 +32,10 @@ namespace mongo { +namespace fts { +class FTSQuery; +} // namespace fts + /** * Common base class for $text match expression implementations. */ @@ -47,23 +51,12 @@ public: static const bool kCaseSensitiveDefault; static const bool kDiacriticSensitiveDefault; - TextMatchExpressionBase(TextParams params); + TextMatchExpressionBase(); - const std::string& getQuery() const { - return _query; - } - - const std::string& getLanguage() const { - return _language; - } - - bool getCaseSensitive() const { - return _caseSensitive; - } - - bool getDiacriticSensitive() const { - return _diacriticSensitive; - } + /** + * Returns a reference to the parsed text query that this TextMatchExpressionBase owns. + */ + virtual const fts::FTSQuery& getFTSQuery() const = 0; // // Methods inherited from MatchExpression. @@ -89,12 +82,6 @@ public: void toBSON(BSONObjBuilder* out) const final; bool equivalent(const MatchExpression* other) const final; - -private: - const std::string _query; - const std::string _language; - const bool _caseSensitive; - const bool _diacriticSensitive; }; } // namespace mongo diff --git a/src/mongo/db/matcher/expression_text_noop.cpp b/src/mongo/db/matcher/expression_text_noop.cpp index 7d2fb5c84b7..bfd61a54081 100644 --- a/src/mongo/db/matcher/expression_text_noop.cpp +++ b/src/mongo/db/matcher/expression_text_noop.cpp @@ -34,21 +34,24 @@ namespace mongo { -TextNoOpMatchExpression::TextNoOpMatchExpression(TextParams params) - : TextMatchExpressionBase(std::move(params)) {} - -Status TextNoOpMatchExpression::init() { +Status TextNoOpMatchExpression::init(TextParams params) { + _ftsQuery.setQuery(std::move(params.query)); + _ftsQuery.setLanguage(std::move(params.language)); + _ftsQuery.setCaseSensitive(params.caseSensitive); + _ftsQuery.setDiacriticSensitive(params.diacriticSensitive); + invariantOK(_ftsQuery.parse(fts::TEXT_INDEX_VERSION_INVALID)); return initPath("_fts"); } std::unique_ptr<MatchExpression> TextNoOpMatchExpression::shallowClone() const { TextParams params; - params.query = getQuery(); - params.language = getLanguage(); - params.caseSensitive = getCaseSensitive(); - params.diacriticSensitive = getDiacriticSensitive(); - auto expr = stdx::make_unique<TextNoOpMatchExpression>(std::move(params)); - expr->init(); + params.query = _ftsQuery.getQuery(); + params.language = _ftsQuery.getLanguage(); + params.caseSensitive = _ftsQuery.getCaseSensitive(); + params.diacriticSensitive = _ftsQuery.getDiacriticSensitive(); + + auto expr = stdx::make_unique<TextNoOpMatchExpression>(); + invariantOK(expr->init(std::move(params))); if (getTag()) { expr->setTag(getTag()->clone()); } diff --git a/src/mongo/db/matcher/expression_text_noop.h b/src/mongo/db/matcher/expression_text_noop.h index de02bcfa3cf..8e01d40e70b 100644 --- a/src/mongo/db/matcher/expression_text_noop.h +++ b/src/mongo/db/matcher/expression_text_noop.h @@ -28,17 +28,23 @@ #pragma once +#include "mongo/db/fts/fts_query_noop.h" #include "mongo/db/matcher/expression_text_base.h" namespace mongo { class TextNoOpMatchExpression : public TextMatchExpressionBase { public: - TextNoOpMatchExpression(TextParams params); + Status init(TextParams params); - Status init(); + const fts::FTSQuery& getFTSQuery() const final { + return _ftsQuery; + } std::unique_ptr<MatchExpression> shallowClone() const final; + +private: + fts::FTSQueryNoop _ftsQuery; }; } // namespace mongo diff --git a/src/mongo/db/matcher/extensions_callback_noop.cpp b/src/mongo/db/matcher/extensions_callback_noop.cpp index e5941f73562..10026370e64 100644 --- a/src/mongo/db/matcher/extensions_callback_noop.cpp +++ b/src/mongo/db/matcher/extensions_callback_noop.cpp @@ -41,8 +41,8 @@ StatusWithMatchExpression ExtensionsCallbackNoop::parseText(BSONElement text) co return textParams.getStatus(); } - auto expr = stdx::make_unique<TextNoOpMatchExpression>(std::move(textParams.getValue())); - Status initStatus = expr->init(); + auto expr = stdx::make_unique<TextNoOpMatchExpression>(); + Status initStatus = expr->init(std::move(textParams.getValue())); if (!initStatus.isOK()) { return initStatus; } diff --git a/src/mongo/db/matcher/extensions_callback_real.cpp b/src/mongo/db/matcher/extensions_callback_real.cpp index 161e0fb2e79..0b7e815ca58 100644 --- a/src/mongo/db/matcher/extensions_callback_real.cpp +++ b/src/mongo/db/matcher/extensions_callback_real.cpp @@ -45,8 +45,8 @@ StatusWithMatchExpression ExtensionsCallbackReal::parseText(BSONElement text) co return textParams.getStatus(); } - auto exp = stdx::make_unique<TextMatchExpression>(std::move(textParams.getValue())); - Status status = exp->init(); + auto exp = stdx::make_unique<TextMatchExpression>(); + Status status = exp->init(_txn, *_nss, std::move(textParams.getValue())); if (!status.isOK()) { return status; } |