mirror of https://gitee.com/bigwinds/arangodb
fix invalidation
This commit is contained in:
parent
e86ed5c685
commit
66eec2ac7e
|
@ -622,6 +622,7 @@ SHELL_SERVER_AQL = @top_srcdir@/js/server/tests/aql-arithmetic.js \
|
||||||
@top_srcdir@/js/server/tests/aql-queries-optimiser-sort-noncluster.js \
|
@top_srcdir@/js/server/tests/aql-queries-optimiser-sort-noncluster.js \
|
||||||
@top_srcdir@/js/server/tests/aql-queries-simple.js \
|
@top_srcdir@/js/server/tests/aql-queries-simple.js \
|
||||||
@top_srcdir@/js/server/tests/aql-queries-variables.js \
|
@top_srcdir@/js/server/tests/aql-queries-variables.js \
|
||||||
|
@top_srcdir@/js/server/tests/aql-query-cache.js \
|
||||||
@top_srcdir@/js/server/tests/aql-range.js \
|
@top_srcdir@/js/server/tests/aql-range.js \
|
||||||
@top_srcdir@/js/server/tests/aql-ranges.js \
|
@top_srcdir@/js/server/tests/aql-ranges.js \
|
||||||
@top_srcdir@/js/server/tests/aql-refaccess-attribute.js \
|
@top_srcdir@/js/server/tests/aql-refaccess-attribute.js \
|
||||||
|
|
|
@ -55,8 +55,8 @@ namespace triagens {
|
||||||
}
|
}
|
||||||
|
|
||||||
~Collections () {
|
~Collections () {
|
||||||
for (auto it = _collections.begin(); it != _collections.end(); ++it) {
|
for (auto& it : _collections) {
|
||||||
delete (*it).second;
|
delete it.second;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -83,15 +83,10 @@ namespace triagens {
|
||||||
THROW_ARANGO_EXCEPTION(TRI_ERROR_QUERY_TOO_MANY_COLLECTIONS);
|
THROW_ARANGO_EXCEPTION(TRI_ERROR_QUERY_TOO_MANY_COLLECTIONS);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto collection = new Collection(name, _vocbase, accessType);
|
std::unique_ptr<Collection> collection(new Collection(name, _vocbase, accessType));
|
||||||
try {
|
_collections.emplace(name, collection.get());
|
||||||
_collections.emplace(std::make_pair(name, collection));
|
|
||||||
}
|
return collection.release();
|
||||||
catch (...) {
|
|
||||||
delete collection;
|
|
||||||
throw;
|
|
||||||
}
|
|
||||||
return collection;
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// note that the collection is used in both read & write ops
|
// note that the collection is used in both read & write ops
|
||||||
|
@ -112,8 +107,8 @@ namespace triagens {
|
||||||
std::vector<std::string> result;
|
std::vector<std::string> result;
|
||||||
result.reserve(_collections.size());
|
result.reserve(_collections.size());
|
||||||
|
|
||||||
for (auto it = _collections.begin(); it != _collections.end(); ++it) {
|
for (auto const& it : _collections) {
|
||||||
result.emplace_back((*it).first);
|
result.emplace_back(it.first);
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
|
@ -648,6 +648,7 @@ QueryResult Query::execute (QueryRegistry* registry) {
|
||||||
res.warnings = warningsToJson(TRI_UNKNOWN_MEM_ZONE);
|
res.warnings = warningsToJson(TRI_UNKNOWN_MEM_ZONE);
|
||||||
res.json = TRI_CopyJson(TRI_UNKNOWN_MEM_ZONE, cacheResult.get()->_queryResult);
|
res.json = TRI_CopyJson(TRI_UNKNOWN_MEM_ZONE, cacheResult.get()->_queryResult);
|
||||||
res.stats = nullptr;
|
res.stats = nullptr;
|
||||||
|
res.cached = true;
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
@ -695,7 +696,14 @@ QueryResult Query::execute (QueryRegistry* registry) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// finally store the generated result in the query cache
|
// finally store the generated result in the query cache
|
||||||
QueryCache::instance()->store(_vocbase, queryStringHash, _queryString, _queryLength, TRI_CopyJson(TRI_UNKNOWN_MEM_ZONE, jsonResult.json()), std::vector<std::string>());
|
QueryCache::instance()->store(
|
||||||
|
_vocbase,
|
||||||
|
queryStringHash,
|
||||||
|
_queryString,
|
||||||
|
_queryLength,
|
||||||
|
TRI_CopyJson(TRI_UNKNOWN_MEM_ZONE, jsonResult.json()),
|
||||||
|
collections()->collectionNames()
|
||||||
|
);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// iterate over result and return it
|
// iterate over result and return it
|
||||||
|
@ -782,6 +790,7 @@ QueryResultV8 Query::executeV8 (v8::Isolate* isolate,
|
||||||
// got a result from the query cache
|
// got a result from the query cache
|
||||||
QueryResultV8 res(TRI_ERROR_NO_ERROR);
|
QueryResultV8 res(TRI_ERROR_NO_ERROR);
|
||||||
res.result = v8::Handle<v8::Array>::Cast(TRI_ObjectJson(isolate, cacheResult.get()->_queryResult));
|
res.result = v8::Handle<v8::Array>::Cast(TRI_ObjectJson(isolate, cacheResult.get()->_queryResult));
|
||||||
|
res.cached = true;
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -831,7 +840,14 @@ QueryResultV8 Query::executeV8 (v8::Isolate* isolate,
|
||||||
}
|
}
|
||||||
|
|
||||||
// finally store the generated result in the query cache
|
// finally store the generated result in the query cache
|
||||||
QueryCache::instance()->store(_vocbase, queryStringHash, _queryString, _queryLength, cacheResult.get(), std::vector<std::string>());
|
QueryCache::instance()->store(
|
||||||
|
_vocbase,
|
||||||
|
queryStringHash,
|
||||||
|
_queryString,
|
||||||
|
_queryLength,
|
||||||
|
cacheResult.get(),
|
||||||
|
collections()->collectionNames()
|
||||||
|
);
|
||||||
cacheResult.release();
|
cacheResult.release();
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
|
|
@ -220,8 +220,7 @@ void QueryCacheDatabaseEntry::invalidate (char const* collection) {
|
||||||
|
|
||||||
QueryCache::QueryCache ()
|
QueryCache::QueryCache ()
|
||||||
: _lock(),
|
: _lock(),
|
||||||
_entries(),
|
_entries() {
|
||||||
_active(true) {
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -236,12 +235,25 @@ QueryCache::~QueryCache () {
|
||||||
// --SECTION-- public methods
|
// --SECTION-- public methods
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/// @brief return the query cache properties
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
triagens::basics::Json QueryCache::properties () const {
|
||||||
|
triagens::basics::Json json(triagens::basics::Json::Object, 2);
|
||||||
|
json("mode", triagens::basics::Json(modeString(mode())));
|
||||||
|
|
||||||
|
return json;
|
||||||
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
/// @brief test whether the cache might be active
|
/// @brief test whether the cache might be active
|
||||||
|
/// this is a quick test that may save the caller from further bothering
|
||||||
|
/// about the query cache if case it returns `false`
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
bool QueryCache::mayBeActive () const {
|
bool QueryCache::mayBeActive () const {
|
||||||
return (_active && (mode() != CACHE_ALWAYS_OFF));
|
return (mode() != CACHE_ALWAYS_OFF);
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -249,11 +261,6 @@ bool QueryCache::mayBeActive () const {
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
QueryCacheMode QueryCache::mode () const {
|
QueryCacheMode QueryCache::mode () const {
|
||||||
if (! _active) {
|
|
||||||
// override whatever was stored in mode
|
|
||||||
return CACHE_ALWAYS_OFF;
|
|
||||||
}
|
|
||||||
|
|
||||||
return Mode.load(std::memory_order_relaxed);
|
return Mode.load(std::memory_order_relaxed);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -290,6 +297,24 @@ void QueryCache::mode (std::string const& value) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/// @brief return a string version of the mode
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
std::string QueryCache::modeString (QueryCacheMode mode) {
|
||||||
|
switch (mode) {
|
||||||
|
case CACHE_ALWAYS_OFF:
|
||||||
|
return "off";
|
||||||
|
case CACHE_ALWAYS_ON:
|
||||||
|
return "on";
|
||||||
|
case CACHE_ON_DEMAND:
|
||||||
|
return "demand";
|
||||||
|
}
|
||||||
|
|
||||||
|
TRI_ASSERT(false);
|
||||||
|
return "off";
|
||||||
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
/// @brief lookup a query result in the cache
|
/// @brief lookup a query result in the cache
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -323,6 +348,10 @@ void QueryCache::store (TRI_vocbase_t* vocbase,
|
||||||
TRI_json_t* result,
|
TRI_json_t* result,
|
||||||
std::vector<std::string> const& collections) {
|
std::vector<std::string> const& collections) {
|
||||||
|
|
||||||
|
if (result == nullptr) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
std::shared_ptr<QueryCacheResultEntry> entry(new QueryCacheResultEntry(queryString, queryStringLength, result, collections));
|
std::shared_ptr<QueryCacheResultEntry> entry(new QueryCacheResultEntry(queryString, queryStringLength, result, collections));
|
||||||
|
|
||||||
WRITE_LOCKER(_lock);
|
WRITE_LOCKER(_lock);
|
||||||
|
@ -348,20 +377,14 @@ void QueryCache::invalidate (triagens::basics::ReadWriteLock& lock,
|
||||||
std::vector<char const*> const& collections) {
|
std::vector<char const*> const& collections) {
|
||||||
TRI_ASSERT(&lock == &_lock); // this should be our lock
|
TRI_ASSERT(&lock == &_lock); // this should be our lock
|
||||||
|
|
||||||
try {
|
auto it = _entries.find(vocbase);
|
||||||
auto it = _entries.find(vocbase);
|
|
||||||
|
|
||||||
if (it == _entries.end()) {
|
if (it == _entries.end()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// invalidate while holding the lock
|
// invalidate while holding the lock
|
||||||
(*it).second->invalidate(collections);
|
(*it).second->invalidate(collections);
|
||||||
}
|
|
||||||
catch (...) {
|
|
||||||
// something is really wrong. now disable ourselves
|
|
||||||
disable();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -370,22 +393,16 @@ void QueryCache::invalidate (triagens::basics::ReadWriteLock& lock,
|
||||||
|
|
||||||
void QueryCache::invalidate (TRI_vocbase_t* vocbase,
|
void QueryCache::invalidate (TRI_vocbase_t* vocbase,
|
||||||
std::vector<char const*> const& collections) {
|
std::vector<char const*> const& collections) {
|
||||||
try {
|
WRITE_LOCKER(_lock);
|
||||||
WRITE_LOCKER(_lock);
|
|
||||||
|
|
||||||
auto it = _entries.find(vocbase);
|
auto it = _entries.find(vocbase);
|
||||||
|
|
||||||
if (it == _entries.end()) {
|
if (it == _entries.end()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// invalidate while holding the lock
|
// invalidate while holding the lock
|
||||||
(*it).second->invalidate(collections);
|
(*it).second->invalidate(collections);
|
||||||
}
|
|
||||||
catch (...) {
|
|
||||||
// something is really wrong. now disable ourselves
|
|
||||||
disable();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -394,22 +411,16 @@ void QueryCache::invalidate (TRI_vocbase_t* vocbase,
|
||||||
|
|
||||||
void QueryCache::invalidate (TRI_vocbase_t* vocbase,
|
void QueryCache::invalidate (TRI_vocbase_t* vocbase,
|
||||||
char const* collection) {
|
char const* collection) {
|
||||||
try {
|
WRITE_LOCKER(_lock);
|
||||||
WRITE_LOCKER(_lock);
|
|
||||||
|
|
||||||
auto it = _entries.find(vocbase);
|
auto it = _entries.find(vocbase);
|
||||||
|
|
||||||
if (it == _entries.end()) {
|
if (it == _entries.end()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// invalidate while holding the lock
|
// invalidate while holding the lock
|
||||||
(*it).second->invalidate(collection);
|
(*it).second->invalidate(collection);
|
||||||
}
|
|
||||||
catch (...) {
|
|
||||||
// something is really wrong. now disable ourselves
|
|
||||||
disable();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -422,20 +433,14 @@ void QueryCache::invalidate (triagens::basics::ReadWriteLock& lock,
|
||||||
char const* collection) {
|
char const* collection) {
|
||||||
TRI_ASSERT(&lock == &_lock); // this should be our lock
|
TRI_ASSERT(&lock == &_lock); // this should be our lock
|
||||||
|
|
||||||
try {
|
auto it = _entries.find(vocbase);
|
||||||
auto it = _entries.find(vocbase);
|
|
||||||
|
|
||||||
if (it == _entries.end()) {
|
if (it == _entries.end()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// invalidate while holding the lock
|
// invalidate while holding the lock
|
||||||
(*it).second->invalidate(collection);
|
(*it).second->invalidate(collection);
|
||||||
}
|
|
||||||
catch (...) {
|
|
||||||
// something is really wrong. now disable ourselves
|
|
||||||
disable();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -445,28 +450,22 @@ void QueryCache::invalidate (triagens::basics::ReadWriteLock& lock,
|
||||||
void QueryCache::invalidate (TRI_vocbase_t* vocbase) {
|
void QueryCache::invalidate (TRI_vocbase_t* vocbase) {
|
||||||
QueryCacheDatabaseEntry* databaseQueryCache = nullptr;
|
QueryCacheDatabaseEntry* databaseQueryCache = nullptr;
|
||||||
|
|
||||||
try {
|
{
|
||||||
{
|
WRITE_LOCKER(_lock);
|
||||||
WRITE_LOCKER(_lock);
|
|
||||||
|
|
||||||
auto it = _entries.find(vocbase);
|
auto it = _entries.find(vocbase);
|
||||||
|
|
||||||
if (it == _entries.end()) {
|
if (it == _entries.end()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
databaseQueryCache = (*it).second;
|
databaseQueryCache = (*it).second;
|
||||||
_entries.erase(it);
|
_entries.erase(it);
|
||||||
}
|
|
||||||
|
|
||||||
// delete without holding the lock
|
|
||||||
TRI_ASSERT(databaseQueryCache != nullptr);
|
|
||||||
delete databaseQueryCache;
|
|
||||||
}
|
|
||||||
catch (...) {
|
|
||||||
// something is really wrong. now disable ourselves
|
|
||||||
disable();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// delete without holding the lock
|
||||||
|
TRI_ASSERT(databaseQueryCache != nullptr);
|
||||||
|
delete databaseQueryCache;
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -478,35 +477,20 @@ void QueryCache::invalidate (triagens::basics::ReadWriteLock& lock,
|
||||||
TRI_vocbase_t* vocbase) {
|
TRI_vocbase_t* vocbase) {
|
||||||
TRI_ASSERT(&lock == &_lock); // this should be our lock
|
TRI_ASSERT(&lock == &_lock); // this should be our lock
|
||||||
|
|
||||||
try {
|
QueryCacheDatabaseEntry* databaseQueryCache = nullptr;
|
||||||
QueryCacheDatabaseEntry* databaseQueryCache = nullptr;
|
|
||||||
|
|
||||||
auto it = _entries.find(vocbase);
|
auto it = _entries.find(vocbase);
|
||||||
|
|
||||||
if (it == _entries.end()) {
|
if (it == _entries.end()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
databaseQueryCache = (*it).second;
|
databaseQueryCache = (*it).second;
|
||||||
_entries.erase(it);
|
_entries.erase(it);
|
||||||
|
|
||||||
// delete without holding the lock
|
// delete without holding the lock
|
||||||
TRI_ASSERT(databaseQueryCache != nullptr);
|
TRI_ASSERT(databaseQueryCache != nullptr);
|
||||||
delete databaseQueryCache;
|
delete databaseQueryCache;
|
||||||
}
|
|
||||||
catch (...) {
|
|
||||||
// something is really wrong. now disable ourselves
|
|
||||||
disable();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
/// @brief disable ourselves in case of emergency
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
void QueryCache::disable () {
|
|
||||||
_active = false;
|
|
||||||
mode(CACHE_ALWAYS_OFF);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
|
@ -31,6 +31,7 @@
|
||||||
#define ARANGODB_AQL_QUERY_CACHE_H 1
|
#define ARANGODB_AQL_QUERY_CACHE_H 1
|
||||||
|
|
||||||
#include "Basics/Common.h"
|
#include "Basics/Common.h"
|
||||||
|
#include "Basics/JsonHelper.h"
|
||||||
#include "Basics/ReadWriteLock.h"
|
#include "Basics/ReadWriteLock.h"
|
||||||
|
|
||||||
struct TRI_json_t;
|
struct TRI_json_t;
|
||||||
|
@ -177,8 +178,16 @@ namespace triagens {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/// @brief return the query cache properties
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
triagens::basics::Json properties () const;
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
/// @brief test whether the cache might be active
|
/// @brief test whether the cache might be active
|
||||||
|
/// this is a quick test that may save the caller from further bothering
|
||||||
|
/// about the query cache if case it returns `false`
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
bool mayBeActive () const;
|
bool mayBeActive () const;
|
||||||
|
@ -201,6 +210,12 @@ namespace triagens {
|
||||||
|
|
||||||
void mode (std::string const&);
|
void mode (std::string const&);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/// @brief return a string version of the mode
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
static std::string modeString (QueryCacheMode);
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
/// @brief lookup a query result in the cache
|
/// @brief lookup a query result in the cache
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -277,12 +292,6 @@ namespace triagens {
|
||||||
return _lock;
|
return _lock;
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
/// @brief disable ourselves in case of emergency
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
void disable ();
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
/// @brief get the pointer to the global query cache
|
/// @brief get the pointer to the global query cache
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -318,13 +327,6 @@ namespace triagens {
|
||||||
|
|
||||||
std::unordered_map<struct TRI_vocbase_s*, QueryCacheDatabaseEntry*> _entries;
|
std::unordered_map<struct TRI_vocbase_s*, QueryCacheDatabaseEntry*> _entries;
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
/// @brief activity flag. will be toggled to false only in case of something
|
|
||||||
/// going terribly wrong
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
bool _active;
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -45,6 +45,7 @@ namespace triagens {
|
||||||
|
|
||||||
QueryResult (QueryResult&& other) {
|
QueryResult (QueryResult&& other) {
|
||||||
code = other.code;
|
code = other.code;
|
||||||
|
cached = other.cached;
|
||||||
details = other.details;
|
details = other.details;
|
||||||
warnings = other.warnings;
|
warnings = other.warnings;
|
||||||
json = other.json;
|
json = other.json;
|
||||||
|
@ -65,6 +66,7 @@ namespace triagens {
|
||||||
QueryResult (int code,
|
QueryResult (int code,
|
||||||
std::string const& details)
|
std::string const& details)
|
||||||
: code(code),
|
: code(code),
|
||||||
|
cached(false),
|
||||||
details(details),
|
details(details),
|
||||||
zone(TRI_UNKNOWN_MEM_ZONE),
|
zone(TRI_UNKNOWN_MEM_ZONE),
|
||||||
warnings(nullptr),
|
warnings(nullptr),
|
||||||
|
@ -98,6 +100,7 @@ namespace triagens {
|
||||||
}
|
}
|
||||||
|
|
||||||
int code;
|
int code;
|
||||||
|
bool cached;
|
||||||
std::string details;
|
std::string details;
|
||||||
std::unordered_set<std::string> bindParameters;
|
std::unordered_set<std::string> bindParameters;
|
||||||
std::vector<std::string> collectionNames;
|
std::vector<std::string> collectionNames;
|
||||||
|
|
|
@ -1199,20 +1199,21 @@ static void JS_ExecuteAqlJson (const v8::FunctionCallbackInfo<v8::Value>& args)
|
||||||
// return the array value as it is. this is a performance optimisation
|
// return the array value as it is. this is a performance optimisation
|
||||||
v8::Handle<v8::Object> result = v8::Object::New(isolate);
|
v8::Handle<v8::Object> result = v8::Object::New(isolate);
|
||||||
if (queryResult.json != nullptr) {
|
if (queryResult.json != nullptr) {
|
||||||
result->Set(TRI_V8_ASCII_STRING("json"), TRI_ObjectJson(isolate, queryResult.json));
|
result->ForceSet(TRI_V8_ASCII_STRING("json"), TRI_ObjectJson(isolate, queryResult.json));
|
||||||
}
|
}
|
||||||
if (queryResult.stats != nullptr) {
|
if (queryResult.stats != nullptr) {
|
||||||
result->Set(TRI_V8_ASCII_STRING("stats"), TRI_ObjectJson(isolate, queryResult.stats));
|
result->ForceSet(TRI_V8_ASCII_STRING("stats"), TRI_ObjectJson(isolate, queryResult.stats));
|
||||||
}
|
}
|
||||||
if (queryResult.profile != nullptr) {
|
if (queryResult.profile != nullptr) {
|
||||||
result->Set(TRI_V8_ASCII_STRING("profile"), TRI_ObjectJson(isolate, queryResult.profile));
|
result->ForceSet(TRI_V8_ASCII_STRING("profile"), TRI_ObjectJson(isolate, queryResult.profile));
|
||||||
}
|
}
|
||||||
if (queryResult.warnings == nullptr) {
|
if (queryResult.warnings == nullptr) {
|
||||||
result->Set(TRI_V8_ASCII_STRING("warnings"), v8::Array::New(isolate));
|
result->ForceSet(TRI_V8_ASCII_STRING("warnings"), v8::Array::New(isolate));
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
result->Set(TRI_V8_ASCII_STRING("warnings"), TRI_ObjectJson(isolate, queryResult.warnings));
|
result->ForceSet(TRI_V8_ASCII_STRING("warnings"), TRI_ObjectJson(isolate, queryResult.warnings));
|
||||||
}
|
}
|
||||||
|
result->ForceSet(TRI_V8_ASCII_STRING("cached"), v8::Boolean::New(isolate, queryResult.cached));
|
||||||
|
|
||||||
TRI_V8_RETURN(result);
|
TRI_V8_RETURN(result);
|
||||||
TRI_V8_TRY_CATCH_END
|
TRI_V8_TRY_CATCH_END
|
||||||
|
@ -1299,20 +1300,21 @@ static void JS_ExecuteAql (const v8::FunctionCallbackInfo<v8::Value>& args) {
|
||||||
// return the array value as it is. this is a performance optimisation
|
// return the array value as it is. this is a performance optimisation
|
||||||
v8::Handle<v8::Object> result = v8::Object::New(isolate);
|
v8::Handle<v8::Object> result = v8::Object::New(isolate);
|
||||||
|
|
||||||
result->Set(TRI_V8_ASCII_STRING("json"), queryResult.result);
|
result->ForceSet(TRI_V8_ASCII_STRING("json"), queryResult.result);
|
||||||
|
|
||||||
if (queryResult.stats != nullptr) {
|
if (queryResult.stats != nullptr) {
|
||||||
result->Set(TRI_V8_ASCII_STRING("stats"), TRI_ObjectJson(isolate, queryResult.stats));
|
result->ForceSet(TRI_V8_ASCII_STRING("stats"), TRI_ObjectJson(isolate, queryResult.stats));
|
||||||
}
|
}
|
||||||
if (queryResult.profile != nullptr) {
|
if (queryResult.profile != nullptr) {
|
||||||
result->Set(TRI_V8_ASCII_STRING("profile"), TRI_ObjectJson(isolate, queryResult.profile));
|
result->ForceSet(TRI_V8_ASCII_STRING("profile"), TRI_ObjectJson(isolate, queryResult.profile));
|
||||||
}
|
}
|
||||||
if (queryResult.warnings == nullptr) {
|
if (queryResult.warnings == nullptr) {
|
||||||
result->Set(TRI_V8_ASCII_STRING("warnings"), v8::Array::New(isolate));
|
result->ForceSet(TRI_V8_ASCII_STRING("warnings"), v8::Array::New(isolate));
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
result->Set(TRI_V8_ASCII_STRING("warnings"), TRI_ObjectJson(isolate, queryResult.warnings));
|
result->ForceSet(TRI_V8_ASCII_STRING("warnings"), TRI_ObjectJson(isolate, queryResult.warnings));
|
||||||
}
|
}
|
||||||
|
result->ForceSet(TRI_V8_ASCII_STRING("cached"), v8::Boolean::New(isolate, queryResult.cached));
|
||||||
|
|
||||||
TRI_V8_RETURN(result);
|
TRI_V8_RETURN(result);
|
||||||
TRI_V8_TRY_CATCH_END
|
TRI_V8_TRY_CATCH_END
|
||||||
|
@ -1532,7 +1534,7 @@ static void JS_QueryIsKilledAql (const v8::FunctionCallbackInfo<v8::Value>& args
|
||||||
/// @brief configures the AQL query cache
|
/// @brief configures the AQL query cache
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
static void JS_QueryCacheConfigAql (const v8::FunctionCallbackInfo<v8::Value>& args) {
|
static void JS_QueryCachePropertiesAql (const v8::FunctionCallbackInfo<v8::Value>& args) {
|
||||||
TRI_V8_TRY_CATCH_BEGIN(isolate);
|
TRI_V8_TRY_CATCH_BEGIN(isolate);
|
||||||
v8::HandleScope scope(isolate);
|
v8::HandleScope scope(isolate);
|
||||||
|
|
||||||
|
@ -1542,17 +1544,26 @@ static void JS_QueryCacheConfigAql (const v8::FunctionCallbackInfo<v8::Value>& a
|
||||||
TRI_V8_THROW_EXCEPTION(TRI_ERROR_ARANGO_DATABASE_NOT_FOUND);
|
TRI_V8_THROW_EXCEPTION(TRI_ERROR_ARANGO_DATABASE_NOT_FOUND);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (args.Length() != 1 || ! args[0]->IsObject()) {
|
if (args.Length() > 1 || (args.Length() == 1 && ! args[0]->IsObject())) {
|
||||||
TRI_V8_THROW_EXCEPTION_USAGE("AQL_QUERY_CACHE_CONFIG(<options>)");
|
TRI_V8_THROW_EXCEPTION_USAGE("AQL_QUERY_CACHE_PROPERTIES(<options>)");
|
||||||
}
|
}
|
||||||
|
|
||||||
auto obj = args[0]->ToObject();
|
if (args.Length() == 1) {
|
||||||
|
// called with options
|
||||||
|
auto obj = args[0]->ToObject();
|
||||||
|
|
||||||
if (obj->Has(TRI_V8_ASCII_STRING("mode"))) {
|
if (obj->Has(TRI_V8_ASCII_STRING("mode"))) {
|
||||||
auto mode = TRI_ObjectToString(obj->Get(TRI_V8_ASCII_STRING("mode")));
|
auto mode = TRI_ObjectToString(obj->Get(TRI_V8_ASCII_STRING("mode")));
|
||||||
|
|
||||||
triagens::aql::QueryCache::instance()->mode(mode);
|
// set mode
|
||||||
|
triagens::aql::QueryCache::instance()->mode(mode);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto properties = triagens::aql::QueryCache::instance()->properties();
|
||||||
|
TRI_V8_RETURN(TRI_ObjectJson(isolate, properties.json()));
|
||||||
|
|
||||||
|
// fetch current configuration and return it
|
||||||
TRI_V8_TRY_CATCH_END
|
TRI_V8_TRY_CATCH_END
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3753,7 +3764,7 @@ void TRI_InitV8VocBridge (v8::Isolate* isolate,
|
||||||
TRI_AddGlobalFunctionVocbase(isolate, context, TRI_V8_ASCII_STRING("AQL_QUERIES_KILL"), JS_QueriesKillAql, true);
|
TRI_AddGlobalFunctionVocbase(isolate, context, TRI_V8_ASCII_STRING("AQL_QUERIES_KILL"), JS_QueriesKillAql, true);
|
||||||
TRI_AddGlobalFunctionVocbase(isolate, context, TRI_V8_ASCII_STRING("AQL_QUERY_SLEEP"), JS_QuerySleepAql, true);
|
TRI_AddGlobalFunctionVocbase(isolate, context, TRI_V8_ASCII_STRING("AQL_QUERY_SLEEP"), JS_QuerySleepAql, true);
|
||||||
TRI_AddGlobalFunctionVocbase(isolate, context, TRI_V8_ASCII_STRING("AQL_QUERY_IS_KILLED"), JS_QueryIsKilledAql, true);
|
TRI_AddGlobalFunctionVocbase(isolate, context, TRI_V8_ASCII_STRING("AQL_QUERY_IS_KILLED"), JS_QueryIsKilledAql, true);
|
||||||
TRI_AddGlobalFunctionVocbase(isolate, context, TRI_V8_ASCII_STRING("AQL_QUERY_CACHE_CONFIG"), JS_QueryCacheConfigAql, true);
|
TRI_AddGlobalFunctionVocbase(isolate, context, TRI_V8_ASCII_STRING("AQL_QUERY_CACHE_PROPERTIES"), JS_QueryCachePropertiesAql, true);
|
||||||
TRI_AddGlobalFunctionVocbase(isolate, context, TRI_V8_ASCII_STRING("AQL_QUERY_CACHE_INVALIDATE"), JS_QueryCacheInvalidateAql, true);
|
TRI_AddGlobalFunctionVocbase(isolate, context, TRI_V8_ASCII_STRING("AQL_QUERY_CACHE_INVALIDATE"), JS_QueryCacheInvalidateAql, true);
|
||||||
|
|
||||||
TRI_AddGlobalFunctionVocbase(isolate, context, TRI_V8_ASCII_STRING("CPP_SHORTEST_PATH"), JS_QueryShortestPath, true);
|
TRI_AddGlobalFunctionVocbase(isolate, context, TRI_V8_ASCII_STRING("CPP_SHORTEST_PATH"), JS_QueryShortestPath, true);
|
||||||
|
|
|
@ -149,7 +149,7 @@ void ClearQueryCache (TRI_transaction_t* trx) {
|
||||||
}
|
}
|
||||||
catch (...) {
|
catch (...) {
|
||||||
// in case something goes wrong, we have to disable the query cache
|
// in case something goes wrong, we have to disable the query cache
|
||||||
triagens::aql::QueryCache::instance()->disable();
|
triagens::aql::QueryCache::instance()->invalidate(trx->_vocbase);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1268,7 +1268,7 @@ int TRI_AddOperationTransaction (triagens::wal::DocumentOperation& operation,
|
||||||
if (isSingleOperationTransaction) {
|
if (isSingleOperationTransaction) {
|
||||||
// operation is directly executed
|
// operation is directly executed
|
||||||
operation.handle();
|
operation.handle();
|
||||||
|
|
||||||
triagens::aql::QueryCache::instance()->invalidate(trx->_vocbase, document->_info._name);
|
triagens::aql::QueryCache::instance()->invalidate(trx->_vocbase, document->_info._name);
|
||||||
|
|
||||||
++document->_uncollectedLogfileEntries;
|
++document->_uncollectedLogfileEntries;
|
||||||
|
|
|
@ -0,0 +1,135 @@
|
||||||
|
/*jshint globalstrict:false, strict:false, maxlen: 500 */
|
||||||
|
/*global assertEqual, assertTrue, assertFalse, AQL_EXECUTE,
|
||||||
|
AQL_QUERY_CACHE_PROPERTIES, AQL_QUERY_CACHE_INVALIDATE */
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/// @brief tests for query language, bind parameters
|
||||||
|
///
|
||||||
|
/// @file
|
||||||
|
///
|
||||||
|
/// DISCLAIMER
|
||||||
|
///
|
||||||
|
/// Copyright 2010-2012 triagens GmbH, Cologne, Germany
|
||||||
|
///
|
||||||
|
/// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
/// you may not use this file except in compliance with the License.
|
||||||
|
/// You may obtain a copy of the License at
|
||||||
|
///
|
||||||
|
/// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
///
|
||||||
|
/// Unless required by applicable law or agreed to in writing, software
|
||||||
|
/// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
/// See the License for the specific language governing permissions and
|
||||||
|
/// limitations under the License.
|
||||||
|
///
|
||||||
|
/// Copyright holder is triAGENS GmbH, Cologne, Germany
|
||||||
|
///
|
||||||
|
/// @author Jan Steemann
|
||||||
|
/// @author Copyright 2012, triAGENS GmbH, Cologne, Germany
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
var jsunity = require("jsunity");
|
||||||
|
var db = require("org/arangodb").db;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/// @brief test suite
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
function ahuacatlQueryCacheTestSuite () {
|
||||||
|
var cacheProperties;
|
||||||
|
var c1, c2;
|
||||||
|
|
||||||
|
return {
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/// @brief set up
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
setUp : function () {
|
||||||
|
cacheProperties = AQL_QUERY_CACHE_PROPERTIES();
|
||||||
|
AQL_QUERY_CACHE_INVALIDATE();
|
||||||
|
|
||||||
|
db._drop("UnitTestsAhuacatlQueryCache1");
|
||||||
|
db._drop("UnitTestsAhuacatlQueryCache2");
|
||||||
|
|
||||||
|
c1 = db._create("UnitTestsAhuacatlQueryCache1");
|
||||||
|
c2 = db._create("UnitTestsAhuacatlQueryCache2");
|
||||||
|
},
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/// @brief tear down
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
tearDown : function () {
|
||||||
|
db._drop("UnitTestsAhuacatlQueryCache1");
|
||||||
|
db._drop("UnitTestsAhuacatlQueryCache2");
|
||||||
|
|
||||||
|
c1 = null;
|
||||||
|
c2 = null;
|
||||||
|
|
||||||
|
AQL_QUERY_CACHE_PROPERTIES(cacheProperties);
|
||||||
|
AQL_QUERY_CACHE_INVALIDATE();
|
||||||
|
},
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/// @brief test setting modes
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
testModes : function () {
|
||||||
|
var result;
|
||||||
|
|
||||||
|
result = AQL_QUERY_CACHE_PROPERTIES({ mode: "off" });
|
||||||
|
assertEqual("off", result.mode);
|
||||||
|
result = AQL_QUERY_CACHE_PROPERTIES();
|
||||||
|
assertEqual("off", result.mode);
|
||||||
|
|
||||||
|
result = AQL_QUERY_CACHE_PROPERTIES({ mode: "on" });
|
||||||
|
assertEqual("on", result.mode);
|
||||||
|
result = AQL_QUERY_CACHE_PROPERTIES();
|
||||||
|
assertEqual("on", result.mode);
|
||||||
|
|
||||||
|
result = AQL_QUERY_CACHE_PROPERTIES({ mode: "demand" });
|
||||||
|
assertEqual("demand", result.mode);
|
||||||
|
result = AQL_QUERY_CACHE_PROPERTIES();
|
||||||
|
assertEqual("demand", result.mode);
|
||||||
|
},
|
||||||
|
|
||||||
|
testInvalidationAfterInsertSingle : function () {
|
||||||
|
var query = "FOR doc IN @@collection SORT doc.value RETURN doc.value";
|
||||||
|
var result;
|
||||||
|
|
||||||
|
c1.save({ value: 1 });
|
||||||
|
|
||||||
|
AQL_QUERY_CACHE_PROPERTIES({ mode: "on" });
|
||||||
|
result = AQL_EXECUTE(query, { "@collection": c1.name() });
|
||||||
|
assertFalse(result.cached);
|
||||||
|
assertEqual([ 1 ], result.json);
|
||||||
|
|
||||||
|
result = AQL_EXECUTE(query, { "@collection": c1.name() });
|
||||||
|
assertTrue(result.cached);
|
||||||
|
assertEqual([ 1 ], result.json);
|
||||||
|
|
||||||
|
c1.save({ value: 2 }); // this will invalidate cache
|
||||||
|
|
||||||
|
result = AQL_EXECUTE(query, { "@collection": c1.name() });
|
||||||
|
assertFalse(result.cached);
|
||||||
|
assertEqual([ 1, 2 ], result.json);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/// @brief executes the test suite
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
jsunity.run(ahuacatlQueryCacheTestSuite);
|
||||||
|
|
||||||
|
return jsunity.done();
|
||||||
|
|
||||||
|
// Local Variables:
|
||||||
|
// mode: outline-minor
|
||||||
|
// outline-regexp: "^\\(/// @brief\\|/// @addtogroup\\|// --SECTION--\\|/// @page\\|/// @}\\)"
|
||||||
|
// End:
|
Loading…
Reference in New Issue