mirror of https://gitee.com/bigwinds/arangodb
* Added analyzer cache invalidation for dropped database * Fixed jslint reported errors
This commit is contained in:
parent
ba02dc4b4d
commit
9559c8a80e
|
@ -764,6 +764,7 @@ bool dropLegacyAnalyzersCollection(
|
||||||
return lookupRes.is(TRI_ERROR_ARANGO_DATA_SOURCE_NOT_FOUND);
|
return lookupRes.is(TRI_ERROR_ARANGO_DATA_SOURCE_NOT_FOUND);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void registerUpgradeTasks() {
|
void registerUpgradeTasks() {
|
||||||
using namespace arangodb;
|
using namespace arangodb;
|
||||||
using namespace arangodb::application_features;
|
using namespace arangodb::application_features;
|
||||||
|
@ -1820,38 +1821,15 @@ arangodb::Result IResearchAnalyzerFeature::loadAnalyzers(
|
||||||
}
|
}
|
||||||
|
|
||||||
auto* vocbase = dbFeature->lookupDatabase(database);
|
auto* vocbase = dbFeature->lookupDatabase(database);
|
||||||
static auto cleanupAnalyzers = []( // remove invalid analyzers
|
|
||||||
IResearchAnalyzerFeature& feature, // analyzer feature
|
|
||||||
decltype(_lastLoad)::iterator& lastLoadItr, // iterator
|
|
||||||
irs::string_ref const& database // database
|
|
||||||
)->void {
|
|
||||||
if (lastLoadItr == feature._lastLoad.end()) {
|
|
||||||
return; // nothing to do (if not in '_lastLoad' then not in '_analyzers')
|
|
||||||
}
|
|
||||||
|
|
||||||
// remove invalid database and analyzers
|
|
||||||
feature._lastLoad.erase(lastLoadItr);
|
|
||||||
|
|
||||||
// remove no longer valid analyzers (force remove)
|
|
||||||
for (auto itr = feature._analyzers.begin(),
|
|
||||||
end = feature._analyzers.end();
|
|
||||||
itr != end;) {
|
|
||||||
auto split = splitAnalyzerName(itr->first);
|
|
||||||
|
|
||||||
if (split.first == database) {
|
|
||||||
itr = feature._analyzers.erase(itr);
|
|
||||||
} else {
|
|
||||||
++itr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
if (!vocbase) {
|
if (!vocbase) {
|
||||||
if (engine && engine->inRecovery()) {
|
if (engine && engine->inRecovery()) {
|
||||||
return arangodb::Result(); // database might not have come up yet
|
return arangodb::Result(); // database might not have come up yet
|
||||||
}
|
}
|
||||||
|
if (itr != _lastLoad.end()) {
|
||||||
cleanupAnalyzers(*this, itr, database); // cleanup any analyzers for 'database'
|
cleanupAnalyzers(database); // cleanup any analyzers for 'database'
|
||||||
|
_lastLoad.erase(itr);
|
||||||
|
}
|
||||||
|
|
||||||
return arangodb::Result( // result
|
return arangodb::Result( // result
|
||||||
TRI_ERROR_ARANGO_DATABASE_NOT_FOUND, // code
|
TRI_ERROR_ARANGO_DATABASE_NOT_FOUND, // code
|
||||||
|
@ -1860,7 +1838,9 @@ arangodb::Result IResearchAnalyzerFeature::loadAnalyzers(
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!getAnalyzerCollection(*vocbase)) {
|
if (!getAnalyzerCollection(*vocbase)) {
|
||||||
cleanupAnalyzers(*this, itr, database); // cleanup any analyzers for 'database'
|
if (itr != _lastLoad.end()) {
|
||||||
|
cleanupAnalyzers(database); // cleanup any analyzers for 'database'
|
||||||
|
}
|
||||||
_lastLoad[databaseKey] = currentTimestamp; // update timestamp
|
_lastLoad[databaseKey] = currentTimestamp; // update timestamp
|
||||||
|
|
||||||
return arangodb::Result(); // no collection means nothing to load
|
return arangodb::Result(); // no collection means nothing to load
|
||||||
|
@ -2584,6 +2564,33 @@ bool IResearchAnalyzerFeature::visit( // visit analyzers
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void IResearchAnalyzerFeature::cleanupAnalyzers(irs::string_ref const& database) {
|
||||||
|
if (ADB_UNLIKELY(database.empty())) {
|
||||||
|
TRI_ASSERT(FALSE);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (auto itr = _analyzers.begin(), end = _analyzers.end(); itr != end;) {
|
||||||
|
auto split = splitAnalyzerName(itr->first);
|
||||||
|
if (split.first == database) {
|
||||||
|
itr = _analyzers.erase(itr);
|
||||||
|
} else {
|
||||||
|
++itr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void IResearchAnalyzerFeature::invalidate(const TRI_vocbase_t& vocbase) {
|
||||||
|
WriteMutex mutex(_mutex);
|
||||||
|
SCOPED_LOCK(mutex);
|
||||||
|
auto database = irs::string_ref(vocbase.name());
|
||||||
|
auto itr = _lastLoad.find(
|
||||||
|
irs::make_hashed_ref(database, std::hash<irs::string_ref>()));
|
||||||
|
if (itr != _lastLoad.end()) {
|
||||||
|
cleanupAnalyzers(database);
|
||||||
|
_lastLoad.erase(itr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace iresearch
|
} // namespace iresearch
|
||||||
} // namespace arangodb
|
} // namespace arangodb
|
||||||
|
|
||||||
|
|
|
@ -265,6 +265,12 @@ class IResearchAnalyzerFeature final : public arangodb::application_features::Ap
|
||||||
bool visit(std::function<bool(AnalyzerPool::ptr const& analyzer)> const& visitor,
|
bool visit(std::function<bool(AnalyzerPool::ptr const& analyzer)> const& visitor,
|
||||||
TRI_vocbase_t const* vocbase) const;
|
TRI_vocbase_t const* vocbase) const;
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
// @brief removes analyzers for specified database from cache
|
||||||
|
// @param vocbase database to invalidate analyzers
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
void invalidate(const TRI_vocbase_t& vocbase);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// map of caches of irs::analysis::analyzer pools indexed by analyzer name and
|
// map of caches of irs::analysis::analyzer pools indexed by analyzer name and
|
||||||
// their associated metas
|
// their associated metas
|
||||||
|
@ -328,6 +334,12 @@ class IResearchAnalyzerFeature final : public arangodb::application_features::Ap
|
||||||
irs::string_ref const& database = irs::string_ref::NIL // database to load
|
irs::string_ref const& database = irs::string_ref::NIL // database to load
|
||||||
);
|
);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/// removes analyzers for database from feature cache
|
||||||
|
/// Write lock must be acquired by caller
|
||||||
|
/// @param database the database to cleanup analyzers for
|
||||||
|
void cleanupAnalyzers(irs::string_ref const& database);
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
/// @brief store the definition for the speicifed pool in the corresponding
|
/// @brief store the definition for the speicifed pool in the corresponding
|
||||||
/// vocbase
|
/// vocbase
|
||||||
|
|
|
@ -65,6 +65,7 @@
|
||||||
#include "VocBase/LogicalCollection.h"
|
#include "VocBase/LogicalCollection.h"
|
||||||
#include "VocBase/ticks.h"
|
#include "VocBase/ticks.h"
|
||||||
#include "VocBase/vocbase.h"
|
#include "VocBase/vocbase.h"
|
||||||
|
#include "IResearch/IResearchAnalyzerFeature.h"
|
||||||
|
|
||||||
#include <velocypack/velocypack-aliases.h>
|
#include <velocypack/velocypack-aliases.h>
|
||||||
|
|
||||||
|
@ -823,6 +824,12 @@ int DatabaseFeature::dropDatabase(std::string const& name, bool waitForDeletion,
|
||||||
#endif
|
#endif
|
||||||
arangodb::aql::QueryCache::instance()->invalidate(vocbase);
|
arangodb::aql::QueryCache::instance()->invalidate(vocbase);
|
||||||
|
|
||||||
|
auto* analyzers =
|
||||||
|
arangodb::application_features::ApplicationServer::lookupFeature<arangodb::iresearch::IResearchAnalyzerFeature>();
|
||||||
|
if (analyzers != nullptr) {
|
||||||
|
analyzers->invalidate(*vocbase);
|
||||||
|
}
|
||||||
|
|
||||||
engine->prepareDropDatabase(*vocbase, !engine->inRecovery(), res);
|
engine->prepareDropDatabase(*vocbase, !engine->inRecovery(), res);
|
||||||
}
|
}
|
||||||
// must not use the database after here, as it may now be
|
// must not use the database after here, as it may now be
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*jshint globalstrict:false, strict:false, maxlen: 500 */
|
/*jshint globalstrict:false, strict:false, maxlen: 500 */
|
||||||
/*global fail, assertUndefined, assertEqual, assertNotEqual, assertTrue, assertFalse*/
|
/*global fail, assertUndefined, assertEqual, assertNotEqual, assertTrue, assertFalse, assertNull*/
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
/// DISCLAIMER
|
/// DISCLAIMER
|
||||||
|
@ -1094,6 +1094,27 @@ function IResearchFeatureDDLTestSuite () {
|
||||||
assertTrue(String === properties.links.col2.analyzers[0].constructor);
|
assertTrue(String === properties.links.col2.analyzers[0].constructor);
|
||||||
assertEqual("identity", properties.links.col2.analyzers[0]);
|
assertEqual("identity", properties.links.col2.analyzers[0]);
|
||||||
|
|
||||||
|
db._useDatabase("_system");
|
||||||
|
db._dropDatabase(dbName);
|
||||||
|
},
|
||||||
|
testLeftAnalyzerInDroppedDatabase: function () {
|
||||||
|
const dbName = "TestNameDroppedDB";
|
||||||
|
const analyzerName = "TestAnalyzer";
|
||||||
|
db._useDatabase("_system");
|
||||||
|
try { db._dropDatabase(dbName); } catch (e) {}
|
||||||
|
db._createDatabase(dbName);
|
||||||
|
db._useDatabase(dbName);
|
||||||
|
analyzers.save(analyzerName, "identity");
|
||||||
|
// recreating database
|
||||||
|
db._useDatabase("_system");
|
||||||
|
db._dropDatabase(dbName);
|
||||||
|
db._createDatabase(dbName);
|
||||||
|
db._useDatabase(dbName);
|
||||||
|
|
||||||
|
assertNull(analyzers.analyzer(analyzerName));
|
||||||
|
// this should be no name conflict
|
||||||
|
analyzers.save(analyzerName, "text", {"stopwords" : [], "locale":"en"});
|
||||||
|
|
||||||
db._useDatabase("_system");
|
db._useDatabase("_system");
|
||||||
db._dropDatabase(dbName);
|
db._dropDatabase(dbName);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*jshint globalstrict:false, strict:false, maxlen: 500 */
|
/*jshint globalstrict:false, strict:false, maxlen: 500 */
|
||||||
/*global fail, assertUndefined, assertEqual, assertNotEqual, assertTrue, assertFalse*/
|
/*global fail, assertUndefined, assertEqual, assertNotEqual, assertTrue, assertFalse, assertNull*/
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
/// DISCLAIMER
|
/// DISCLAIMER
|
||||||
|
@ -1094,6 +1094,27 @@ function IResearchFeatureDDLTestSuite () {
|
||||||
assertTrue(String === properties.links.col2.analyzers[0].constructor);
|
assertTrue(String === properties.links.col2.analyzers[0].constructor);
|
||||||
assertEqual("identity", properties.links.col2.analyzers[0]);
|
assertEqual("identity", properties.links.col2.analyzers[0]);
|
||||||
|
|
||||||
|
db._useDatabase("_system");
|
||||||
|
db._dropDatabase(dbName);
|
||||||
|
},
|
||||||
|
testLeftAnalyzerInDroppedDatabase: function () {
|
||||||
|
const dbName = "TestNameDroppedDB";
|
||||||
|
const analyzerName = "TestAnalyzer";
|
||||||
|
db._useDatabase("_system");
|
||||||
|
try { db._dropDatabase(dbName); } catch (e) {}
|
||||||
|
db._createDatabase(dbName);
|
||||||
|
db._useDatabase(dbName);
|
||||||
|
analyzers.save(analyzerName, "identity");
|
||||||
|
// recreating database
|
||||||
|
db._useDatabase("_system");
|
||||||
|
db._dropDatabase(dbName);
|
||||||
|
db._createDatabase(dbName);
|
||||||
|
db._useDatabase(dbName);
|
||||||
|
|
||||||
|
assertNull(analyzers.analyzer(analyzerName));
|
||||||
|
// this should be no name conflict
|
||||||
|
analyzers.save(analyzerName, "text", {"stopwords" : [], "locale":"en"});
|
||||||
|
|
||||||
db._useDatabase("_system");
|
db._useDatabase("_system");
|
||||||
db._dropDatabase(dbName);
|
db._dropDatabase(dbName);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue