From de314cc050cd28741e6805795bd966b53442b9d8 Mon Sep 17 00:00:00 2001 From: Michael Hackstein Date: Wed, 30 Apr 2025 12:48:49 +0200 Subject: [PATCH 1/7] Added printing for violation of shutdown ordering --- arangod/Aql/ExecutionBlock.cpp | 20 ++++++++++++++++++++ arangod/Aql/ExecutionBlock.h | 10 +++++++++- arangod/Aql/ExecutionEngine.cpp | 29 ++++++++++++++++++++++++++--- 3 files changed, 55 insertions(+), 4 deletions(-) diff --git a/arangod/Aql/ExecutionBlock.cpp b/arangod/Aql/ExecutionBlock.cpp index 17dd7b70cde0..27ec29f42d25 100644 --- a/arangod/Aql/ExecutionBlock.cpp +++ b/arangod/Aql/ExecutionBlock.cpp @@ -210,3 +210,23 @@ auto ExecutionBlock::printBlockInfo() const -> std::string const { } auto ExecutionBlock::stopAsyncTasks() -> void {} + +auto ExecutionBlock::isDependencyInList(std::unordered_set const& seenBlocks) const noexcept -> ExecutionBlock* { + for (auto const& dependency : _dependencies) { + if (seenBlocks.find(dependency) != seenBlocks.end()) { + return dependency; + } + } + return nullptr; +} + +auto ExecutionBlock::printBlockAndDependenciesInfo() const noexcept -> std::string const { + std::stringstream ss; + ss << printBlockInfo(); + ss << " calls: ["; + for (auto const& dependency : _dependencies) { + ss << " " << dependency->printBlockInfo() << ","; + } + ss << " ]"; + return ss.str(); +} \ No newline at end of file diff --git a/arangod/Aql/ExecutionBlock.h b/arangod/Aql/ExecutionBlock.h index 1da9be17b8d9..d07c81e2cac3 100644 --- a/arangod/Aql/ExecutionBlock.h +++ b/arangod/Aql/ExecutionBlock.h @@ -31,10 +31,12 @@ #include #include -#include +#include #include +#include #include + namespace arangodb { namespace transaction { class Methods; @@ -131,9 +133,15 @@ class ExecutionBlock { [[nodiscard]] auto printBlockInfo() const -> std::string const; [[nodiscard]] auto printTypeInfo() const -> std::string const; + [[nodiscard]] auto printBlockAndDependenciesInfo() const noexcept + -> std::string const; virtual auto stopAsyncTasks() -> void; + [[nodiscard]] auto isDependencyInList( + std::unordered_set const& seenBlocks) const noexcept + -> ExecutionBlock*; + protected: // Trace the start of a execute call void traceExecuteBegin(AqlCallStack const& stack, diff --git a/arangod/Aql/ExecutionEngine.cpp b/arangod/Aql/ExecutionEngine.cpp index 09613b1e13c3..afc869e5aaa5 100644 --- a/arangod/Aql/ExecutionEngine.cpp +++ b/arangod/Aql/ExecutionEngine.cpp @@ -272,10 +272,33 @@ ExecutionEngine::~ExecutionEngine() { // tasks running on any dependent which could start another on the // current block. // The blocks are pushed in a reversed topological order. - for (auto it = _blocks.rbegin(); it != _blocks.rend(); ++it) { - (*it)->stopAsyncTasks(); + { + // Note: We can use raw pointers here because we are not taking + // any responsibilty of the pointer. It is still managed by the _blocks + // vector. Also we are in the destructor here, so we have guaranteed, + // that no one else is cleaning up the blocks. + std::unordered_set seenBlocks; + for (auto it = _blocks.rbegin(); it != _blocks.rend(); ++it) { + auto block = it->get(); + if (ExecutionBlock* seenDependency = + block->isDependencyInList(seenBlocks); + seenDependency != nullptr) { + // We have a dependency that has already been seen, we need to log this + // situation in theory this could lead to deadlocks. Some Blocks are + // fine we just want to see those here. + LOG_TOPIC("a6c2b", WARN, Logger::AQL) + << "Stopping async tasks for " << block->printBlockInfo() + << " but have already stopped dependency " + << seenDependency->printBlockInfo(); + LOG_TOPIC("a6c2c", WARN, Logger::AQL) << "Full list of blocks:"; + for (auto it2 = _blocks.rbegin(); it2 != _blocks.rend(); ++it2) { + LOG_TOPIC("a6c2d", WARN, Logger::AQL) << (*it2)->printBlockAndDependenciesInfo(); + } + } + block->stopAsyncTasks(); + seenBlocks.insert(block); + } } - if (_sharedState) { // ensure no async task is working anymore _sharedState->invalidate(); } From 72f550b0c61d43e912ca110f7593582bc793850f Mon Sep 17 00:00:00 2001 From: Michael Hackstein Date: Wed, 30 Apr 2025 14:17:31 +0200 Subject: [PATCH 2/7] Exclude GatherNodes from order violation checks. Added more informative printing --- arangod/Aql/ExecutionBlock.cpp | 2 ++ arangod/Aql/ExecutionEngine.cpp | 4 +++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/arangod/Aql/ExecutionBlock.cpp b/arangod/Aql/ExecutionBlock.cpp index 27ec29f42d25..5d3b03547cc4 100644 --- a/arangod/Aql/ExecutionBlock.cpp +++ b/arangod/Aql/ExecutionBlock.cpp @@ -221,8 +221,10 @@ auto ExecutionBlock::isDependencyInList(std::unordered_set cons } auto ExecutionBlock::printBlockAndDependenciesInfo() const noexcept -> std::string const { + std::stringstream ss; ss << printBlockInfo(); + ss << " async prefetching type: " <<(int) getPlanNode()->canUseAsyncPrefetching(); ss << " calls: ["; for (auto const& dependency : _dependencies) { ss << " " << dependency->printBlockInfo() << ","; diff --git a/arangod/Aql/ExecutionEngine.cpp b/arangod/Aql/ExecutionEngine.cpp index afc869e5aaa5..3bcdd2134cb4 100644 --- a/arangod/Aql/ExecutionEngine.cpp +++ b/arangod/Aql/ExecutionEngine.cpp @@ -282,10 +282,11 @@ ExecutionEngine::~ExecutionEngine() { auto block = it->get(); if (ExecutionBlock* seenDependency = block->isDependencyInList(seenBlocks); - seenDependency != nullptr) { + seenDependency != nullptr && block->getPlanNode()->getType() != ExecutionNode::GATHER) { // We have a dependency that has already been seen, we need to log this // situation in theory this could lead to deadlocks. Some Blocks are // fine we just want to see those here. + // Gather Nodes are known to violate this, but they are safe. LOG_TOPIC("a6c2b", WARN, Logger::AQL) << "Stopping async tasks for " << block->printBlockInfo() << " but have already stopped dependency " @@ -294,6 +295,7 @@ ExecutionEngine::~ExecutionEngine() { for (auto it2 = _blocks.rbegin(); it2 != _blocks.rend(); ++it2) { LOG_TOPIC("a6c2d", WARN, Logger::AQL) << (*it2)->printBlockAndDependenciesInfo(); } + TRI_ASSERT(false) << "Triggered violation in ExecutionBlock ordering"; } block->stopAsyncTasks(); seenBlocks.insert(block); From ea856464d788bfe6ba09bb04c551e806a0f70c4d Mon Sep 17 00:00:00 2001 From: Michael Hackstein Date: Wed, 30 Apr 2025 15:08:35 +0200 Subject: [PATCH 3/7] Applied review comment. Also added ALERT. Also print if we are still starting async tasks although we already stopped them --- arangod/Aql/ExecutionBlock.cpp | 15 +++++++++++---- arangod/Aql/ExecutionBlock.h | 6 +++++- arangod/Aql/ExecutionBlockImpl.tpp | 25 +++++++++++++++++++++++++ arangod/Aql/ExecutionEngine.cpp | 19 ++++++++++++------- 4 files changed, 53 insertions(+), 12 deletions(-) diff --git a/arangod/Aql/ExecutionBlock.cpp b/arangod/Aql/ExecutionBlock.cpp index 5d3b03547cc4..59302174c1e2 100644 --- a/arangod/Aql/ExecutionBlock.cpp +++ b/arangod/Aql/ExecutionBlock.cpp @@ -211,7 +211,9 @@ auto ExecutionBlock::printBlockInfo() const -> std::string const { auto ExecutionBlock::stopAsyncTasks() -> void {} -auto ExecutionBlock::isDependencyInList(std::unordered_set const& seenBlocks) const noexcept -> ExecutionBlock* { +auto ExecutionBlock::isDependencyInList( + std::unordered_set const& seenBlocks) const noexcept + -> ExecutionBlock* { for (auto const& dependency : _dependencies) { if (seenBlocks.find(dependency) != seenBlocks.end()) { return dependency; @@ -220,15 +222,20 @@ auto ExecutionBlock::isDependencyInList(std::unordered_set cons return nullptr; } -auto ExecutionBlock::printBlockAndDependenciesInfo() const noexcept -> std::string const { - +auto ExecutionBlock::printBlockAndDependenciesInfo() const noexcept + -> std::string const { std::stringstream ss; ss << printBlockInfo(); - ss << " async prefetching type: " <<(int) getPlanNode()->canUseAsyncPrefetching(); + ss << " async prefetching type: " + << (int)getPlanNode()->canUseAsyncPrefetching(); ss << " calls: ["; for (auto const& dependency : _dependencies) { ss << " " << dependency->printBlockInfo() << ","; } ss << " ]"; return ss.str(); +} + +auto ExecutionBlock::hasStoppedAsyncTasks() const noexcept -> bool { + return _stoppedAsyncTasks; } \ No newline at end of file diff --git a/arangod/Aql/ExecutionBlock.h b/arangod/Aql/ExecutionBlock.h index d07c81e2cac3..9ea21aba5d2a 100644 --- a/arangod/Aql/ExecutionBlock.h +++ b/arangod/Aql/ExecutionBlock.h @@ -36,7 +36,6 @@ #include #include - namespace arangodb { namespace transaction { class Methods; @@ -141,6 +140,8 @@ class ExecutionBlock { [[nodiscard]] auto isDependencyInList( std::unordered_set const& seenBlocks) const noexcept -> ExecutionBlock*; + + [[nodiscard]] auto hasStoppedAsyncTasks() const noexcept -> bool; protected: // Trace the start of a execute call @@ -184,6 +185,9 @@ class ExecutionBlock { /// @brief if this is set, we are done, this is reset to false by execute() bool _done; + /// @brief if this is set, we have stopped async tasks, this is set to true by stopAsyncTasks() + bool _stoppedAsyncTasks{false}; + #ifdef ARANGODB_ENABLE_MAINTAINER_MODE /// @brief if this is set to true, one thread is using this block, so we can /// assert that no other thread can access this block at the same time - as diff --git a/arangod/Aql/ExecutionBlockImpl.tpp b/arangod/Aql/ExecutionBlockImpl.tpp index bf465fcc08f7..418b2ae017df 100644 --- a/arangod/Aql/ExecutionBlockImpl.tpp +++ b/arangod/Aql/ExecutionBlockImpl.tpp @@ -354,6 +354,8 @@ ExecutionBlockImpl::~ExecutionBlockImpl() { template void ExecutionBlockImpl::stopAsyncTasks() { + TRI_ASSERT(!_stoppedAsyncTasks) << "Someone already stopped async tasks for " << printBlockInfo(); + _stoppedAsyncTasks = true; if (_prefetchTask && !_prefetchTask->isConsumed() && !_prefetchTask->tryClaim()) { // some thread is still working on our prefetch task @@ -1047,6 +1049,29 @@ auto ExecutionBlockImpl::executeFetcher(ExecutionContext& ctx, return; } + // We are entering debugging land here. + // Someone hasasked as to stop async tasks. + // But here we are just starting to work on one. + // This is okay and can rarely happen. But if it happens + // We want to know if we start the task and finish it quickly + + bool hasStoppedAsyncTasks = block->hasStoppedAsyncTasks(); + if (hasStoppedAsyncTasks) { + LOG_TOPIC("14d20", WARN, Logger::AQL) + << "[query#" << block->getQuery().id() << "] ALERT" + << block->printBlockInfo() + << " was asked to stop async task. We still start one. This is an allowed rare race."; + } + + auto stopGuard = ScopeGuard([block, hasStoppedAsyncTasks]() noexcept { + if (hasStoppedAsyncTasks) { + LOG_TOPIC("14d21", WARN, Logger::AQL) + << "[query#" << block->getQuery().id() << "] CLEAR ALERT" + << block->printBlockInfo() + << " We completed the task of the aforementioned race. All is fine."; + } + }); + TRI_IF_FAILURE("AsyncPrefetch::blocksDestroyedOutOfOrder") { using namespace std::chrono_literals; std::this_thread::sleep_for(100ms); diff --git a/arangod/Aql/ExecutionEngine.cpp b/arangod/Aql/ExecutionEngine.cpp index 3bcdd2134cb4..c21fb4f0701e 100644 --- a/arangod/Aql/ExecutionEngine.cpp +++ b/arangod/Aql/ExecutionEngine.cpp @@ -278,28 +278,33 @@ ExecutionEngine::~ExecutionEngine() { // vector. Also we are in the destructor here, so we have guaranteed, // that no one else is cleaning up the blocks. std::unordered_set seenBlocks; + bool needToPrintViolation = false; for (auto it = _blocks.rbegin(); it != _blocks.rend(); ++it) { auto block = it->get(); if (ExecutionBlock* seenDependency = block->isDependencyInList(seenBlocks); - seenDependency != nullptr && block->getPlanNode()->getType() != ExecutionNode::GATHER) { + seenDependency != nullptr && + block->getPlanNode()->getType() != ExecutionNode::GATHER) { // We have a dependency that has already been seen, we need to log this // situation in theory this could lead to deadlocks. Some Blocks are // fine we just want to see those here. // Gather Nodes are known to violate this, but they are safe. LOG_TOPIC("a6c2b", WARN, Logger::AQL) - << "Stopping async tasks for " << block->printBlockInfo() + << "ALERT Stopping async tasks for " << block->printBlockInfo() << " but have already stopped dependency " << seenDependency->printBlockInfo(); - LOG_TOPIC("a6c2c", WARN, Logger::AQL) << "Full list of blocks:"; - for (auto it2 = _blocks.rbegin(); it2 != _blocks.rend(); ++it2) { - LOG_TOPIC("a6c2d", WARN, Logger::AQL) << (*it2)->printBlockAndDependenciesInfo(); - } - TRI_ASSERT(false) << "Triggered violation in ExecutionBlock ordering"; + needToPrintViolation = true; } block->stopAsyncTasks(); seenBlocks.insert(block); } + if (needToPrintViolation) { + for (auto it2 = _blocks.rbegin(); it2 != _blocks.rend(); ++it2) { + LOG_TOPIC("a6c2d", WARN, Logger::AQL) + << (*it2)->printBlockAndDependenciesInfo(); + } + TRI_ASSERT(false) << "Triggered violation in ExecutionBlock ordering"; + } } if (_sharedState) { // ensure no async task is working anymore _sharedState->invalidate(); From 50c07157c557eaf33d9c534c1ea36299f7ffa1e1 Mon Sep 17 00:00:00 2001 From: Kaveh Vahedipour Date: Fri, 25 Apr 2025 11:48:57 +0200 Subject: [PATCH 4/7] Sleeping barber in SharedQueryState (#21732) * sleeping barber in SharedQueryState * double entry in change log * Add oskar branch parameter to CircleCI * disable vector index on ARM for now, faiss is known to be crashy now. (#21718) * disable vector index on ARM for now, faiss is known to be crashy now. * lint * lint * disable on ARM * disable on ARM --------- Co-authored-by: Vadim Kondratev Co-authored-by: Wilfried Goesgens --- .circleci/base_config.yml | 6 ++- .circleci/config.yml | 4 ++ CHANGELOG | 5 +++ arangod/Aql/SharedQueryState.cpp | 13 ++++++- arangod/Aql/SharedQueryState.h | 38 +++++++++++++++++++ .../@arangodb/testutils/client-tools.js | 10 +++++ .../vector/aql-vector-create-and-remove.js | 9 +++-- .../aql/vector/aql-vector-full-count.js | 12 +++--- .../js/client/aql/vector/aql-vector-nprobe.js | 6 ++- tests/js/client/aql/vector/aql-vector.js | 11 +++--- 10 files changed, 96 insertions(+), 18 deletions(-) diff --git a/.circleci/base_config.yml b/.circleci/base_config.yml index 16cb50b36199..8285db0e320f 100644 --- a/.circleci/base_config.yml +++ b/.circleci/base_config.yml @@ -24,6 +24,9 @@ parameters: enterprise-branch: type: string default: "" + oskar-branch: + type: string + default: "master" dont-cancel-pipelines: type: boolean default: false @@ -363,7 +366,8 @@ jobs: curl -s -L -o build/bin/arangodb "https://github.com/arangodb-helper/arangodb/releases/download/$STARTER_REV/arangodb-linux-$arch" chmod a+x build/bin/arangodb if [ << parameters.enterprise >> = true ]; then - curl -s -L -o build/bin/rclone-arangodb "https://github.com/arangodb/oskar/raw/master/rclone/v$RCLONE_VERSION/rclone-arangodb-linux-$arch" + OSKAR_BRANCH=<< pipeline.parameters.oskar-branch >> + curl -s -L -o build/bin/rclone-arangodb "https://github.com/arangodb/oskar/raw/$OSKAR_BRANCH/rclone/v$RCLONE_VERSION/rclone-arangodb-linux-$arch" chmod a+x build/bin/rclone-arangodb fi - when: diff --git a/.circleci/config.yml b/.circleci/config.yml index 9dce2bd80029..092e9fd2f461 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -12,6 +12,9 @@ parameters: # contains a branch with the same name as the arangodb repo. If this is the case # we use it, otherwise we fall back to "devel". default: "" + oskar-branch: + type: string + default: "master" arangosh_args: type: string default: "" @@ -137,6 +140,7 @@ jobs: name: Print pipeline parameters command: | echo "enterprise-branch: << pipeline.parameters.enterprise-branch >>" + echo "oskar-branch: << pipeline.parameters.oskar-branch >>" echo "create-docker-images: << pipeline.parameters.create-docker-images >>" echo "rebuild-test-docker-images: << pipeline.parameters.rebuild-test-docker-images >>" echo "build-docker-image: << pipeline.parameters.build-docker-image >>" diff --git a/CHANGELOG b/CHANGELOG index 7ca0c64521a2..932580fc52b6 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,8 @@ +3.12.4.3 (XXXX-XX-XX) +--------------------- + +* Fix concurrency bug which can lead to lost threads. See BTS-2087. + 3.12.4.2 (2025-04-09) --------------------- diff --git a/arangod/Aql/SharedQueryState.cpp b/arangod/Aql/SharedQueryState.cpp index 1efb0b274ada..39419c754277 100644 --- a/arangod/Aql/SharedQueryState.cpp +++ b/arangod/Aql/SharedQueryState.cpp @@ -24,6 +24,7 @@ #include "SharedQueryState.h" #include "ApplicationFeatures/ApplicationServer.h" +#include "Logger/LogMacros.h" #include "Basics/Exceptions.h" #include "Cluster/ServerState.h" #include "RestServer/QueryRegistryFeature.h" @@ -60,8 +61,16 @@ void SharedQueryState::invalidate() { _cv.notify_all(); // wakeup everyone else if (_numTasks.load() > 0) { - std::unique_lock guard(_mutex); - _cv.wait(guard, [&] { return _numTasks.load() == 0; }); + while (true) { + std::unique_lock guard(_mutex); + _cv.wait_for(guard, std::chrono::milliseconds(1000), + [&] { return _numTasks.load() == 0; }); + if (_numTasks.load() == 0) { + break; + } + LOG_TOPIC("abcee", DEBUG, Logger::QUERIES) + << "Waiting for " << _numTasks.load() << " tasks to finish"; + } } } diff --git a/arangod/Aql/SharedQueryState.h b/arangod/Aql/SharedQueryState.h index 58eda262b60d..54f3cf8ddaef 100644 --- a/arangod/Aql/SharedQueryState.h +++ b/arangod/Aql/SharedQueryState.h @@ -101,9 +101,36 @@ class SharedQueryState final /// execute a task in parallel if capacity is there template bool asyncExecuteAndWakeup(F&& cb) { + // The atomic _numTasks counts the number of ongoing tasks asynchronous + // tasks. We need this for two purposes: One is to limit parallelism + // so we need to know how many tasks we have already launched. But + // Secondly, we want to wait for them to finish when the query is + // shut down, in particular when it is killed or has run into an + // exception. Note that this is *not* necessary for synchronous + // tasks. + // When _numTasks drops to 0, we need to wake up a thread which + // is waiting for this on the condition variable _cv. We must + // not miss this event, or else we might have a thread which is + // waiting forever. The waiting thread uses a predicate to check + // if _numTasks is 0, and only goes to sleep when it is not. This + // happens under the mutex _mutex and releasing the mutex and going + // to sleep is an atomic operation. Thus, to not miss the event that + // _numTasks is reduced to zero, we must, whenever we decrement it, + // do this under the mutex, and then, after releasing the mutex, + // notify the condition variable _cv! Then either the decrement or + // the going to sleep happens first (serialized by the mutex). If + // the decrement happens first, the waiting thread is not even going + // to sleep, if the going to sleep happens first, then we will wake + // it up. unsigned num = _numTasks.fetch_add(1); if (num + 1 > _maxTasks) { + // We first count down _numTasks to revert the counting up, since + // we have not - after all - started a new async task. Then we run + // the callback synchronously. + std::unique_lock guard(_mutex); _numTasks.fetch_sub(1); // revert + guard.unlock(); + _cv.notify_all(); std::forward(cb)(false); return false; } @@ -130,7 +157,13 @@ class SharedQueryState final }); if (!queued) { + // We first count down _numTasks to revert the counting up, since + // we have not - after all - started a new async task. Then we run + // the callback synchronously. + std::unique_lock guard(_mutex); _numTasks.fetch_sub(1); // revert + guard.unlock(); + _cv.notify_all(); std::forward(cb)(false); } return queued; @@ -166,6 +199,11 @@ class SharedQueryState final unsigned _callbackVersion; unsigned _maxTasks; + // Note that we are waiting for _numTasks to drop down to zero using + // the condition Variable _cv above, which is protected by the mutex + // _mutex above. Therefore, to avoid losing wakeups, it is necessary + // to only ever reduce the value of _numTasks under the mutex and then + // wake up the condition variable _cv! std::atomic _numTasks; std::atomic _valid; }; diff --git a/js/client/modules/@arangodb/testutils/client-tools.js b/js/client/modules/@arangodb/testutils/client-tools.js index 5d001ec87674..fa4a97f0daaa 100644 --- a/js/client/modules/@arangodb/testutils/client-tools.js +++ b/js/client/modules/@arangodb/testutils/client-tools.js @@ -555,6 +555,16 @@ function rtaMakedata(options, instanceManager, writeReadClean, msg, logFile, mor if (addArgs !== undefined) { args = Object.assign(args, addArgs); } + // TODO: vector index broken on circleci-ARM + if (versionHas("arm")) { + let skipOffset = moreargv.findIndex(i => {return i === '--skip';}); + if (skipOffset >= 0) { + moreargv[skipOffset + 1] += ',107'; + } else { + moreargv = ['--skip', '107_']; + } + } + let argv = toArgv(args); argv = argv.concat(['--', options.makedataDB], moreargv, [ diff --git a/tests/js/client/aql/vector/aql-vector-create-and-remove.js b/tests/js/client/aql/vector/aql-vector-create-and-remove.js index 364ffe9a794a..772bc09e14eb 100644 --- a/tests/js/client/aql/vector/aql-vector-create-and-remove.js +++ b/tests/js/client/aql/vector/aql-vector-create-and-remove.js @@ -35,6 +35,8 @@ const { randomNumberGeneratorFloat, } = require("@arangodb/testutils/seededRandom"); +const { versionHas } = require("@arangodb/test-helper"); + const dbName = "vectorDB"; const collName = "coll"; const indexName = "vectorIndex"; @@ -286,7 +288,8 @@ function VectorIndexTestCreationWithVectors() { } -jsunity.run(VectorIndexCreateAndRemoveTestSuite); -jsunity.run(VectorIndexTestCreationWithVectors); - +if (!versionHas("arm")) { + jsunity.run(VectorIndexCreateAndRemoveTestSuite); + jsunity.run(VectorIndexTestCreationWithVectors); +} return jsunity.done(); diff --git a/tests/js/client/aql/vector/aql-vector-full-count.js b/tests/js/client/aql/vector/aql-vector-full-count.js index 49aedb88e8f0..779e366c6743 100644 --- a/tests/js/client/aql/vector/aql-vector-full-count.js +++ b/tests/js/client/aql/vector/aql-vector-full-count.js @@ -37,6 +37,7 @@ const { randomNumberGeneratorFloat, } = require("@arangodb/testutils/seededRandom"); +const { versionHas } = require("@arangodb/test-helper"); const isCluster = require("internal").isCluster(); const dbName = "vectorDB"; const collName = "vectorColl"; @@ -416,8 +417,9 @@ function VectorIndexFullCountCollectionWithSmallAmountOfDocs() { }; } -jsunity.run(VectorIndexFullCountTestSuite); -jsunity.run(VectorIndexFullCountWithNotEnoughNListsTestSuite); -jsunity.run(VectorIndexFullCountCollectionWithSmallAmountOfDocs); - -return jsunity.done(); \ No newline at end of file +if (!versionHas("arm")) { + jsunity.run(VectorIndexFullCountTestSuite); + jsunity.run(VectorIndexFullCountWithNotEnoughNListsTestSuite); + jsunity.run(VectorIndexFullCountCollectionWithSmallAmountOfDocs); +} +return jsunity.done(); diff --git a/tests/js/client/aql/vector/aql-vector-nprobe.js b/tests/js/client/aql/vector/aql-vector-nprobe.js index 2524ab94dc71..ffb6c5827669 100644 --- a/tests/js/client/aql/vector/aql-vector-nprobe.js +++ b/tests/js/client/aql/vector/aql-vector-nprobe.js @@ -37,6 +37,7 @@ const { randomNumberGeneratorFloat, } = require("@arangodb/testutils/seededRandom"); +const { versionHas } = require("@arangodb/test-helper"); const isCluster = require("internal").isCluster(); const dbName = "vectorDB"; const collName = "vectorColl"; @@ -162,6 +163,7 @@ function VectorIndexL2NprobeTestSuite() { }; } -jsunity.run(VectorIndexL2NprobeTestSuite); - +if (!versionHas("arm")) { + jsunity.run(VectorIndexL2NprobeTestSuite); +} return jsunity.done(); diff --git a/tests/js/client/aql/vector/aql-vector.js b/tests/js/client/aql/vector/aql-vector.js index 65946395ea46..08a055176120 100644 --- a/tests/js/client/aql/vector/aql-vector.js +++ b/tests/js/client/aql/vector/aql-vector.js @@ -36,7 +36,7 @@ const db = internal.db; const { randomNumberGeneratorFloat, } = require("@arangodb/testutils/seededRandom"); - +const { versionHas } = require("@arangodb/test-helper"); const isCluster = require("internal").isCluster(); const dbName = "vectorDb"; const collName = "vectorColl"; @@ -872,9 +872,10 @@ function MultipleVectorIndexesOnField() { }; } -jsunity.run(VectorIndexL2TestSuite); -jsunity.run(VectorIndexCosineTestSuite); -jsunity.run(MultipleVectorIndexesOnField); - +if (!versionHas("arm")) { + jsunity.run(VectorIndexL2TestSuite); + jsunity.run(VectorIndexCosineTestSuite); + jsunity.run(MultipleVectorIndexesOnField); +} return jsunity.done(); From 76d2d558e02be95befed77a4cf4f4604803e1b29 Mon Sep 17 00:00:00 2001 From: Vadim Kondratev Date: Fri, 25 Apr 2025 12:21:34 +0200 Subject: [PATCH 5/7] arangodb release 3.12.4.3 --- ARANGO-VERSION | 2 +- CHANGELOG | 3 ++- CMakeLists.txt | 2 +- js/apps/system/_admin/aardvark/APP/api-docs.json | 2 +- 4 files changed, 5 insertions(+), 4 deletions(-) diff --git a/ARANGO-VERSION b/ARANGO-VERSION index 53546811017b..f44c9d113be2 100644 --- a/ARANGO-VERSION +++ b/ARANGO-VERSION @@ -1 +1 @@ -3.12.4.2 +3.12.4.3 diff --git a/CHANGELOG b/CHANGELOG index 932580fc52b6..bfe66ed04c3d 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,8 +1,9 @@ -3.12.4.3 (XXXX-XX-XX) +3.12.4.3 (2025-04-25) --------------------- * Fix concurrency bug which can lead to lost threads. See BTS-2087. + 3.12.4.2 (2025-04-09) --------------------- diff --git a/CMakeLists.txt b/CMakeLists.txt index c86dbd0b5822..2e6d04958803 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -74,7 +74,7 @@ set(ARANGODB_VERSION_MINOR "12") # when building the nightly ARANGODB_VERSION_PATCH will be set if (NOT DEFINED ARANGODB_VERSION_PATCH) set(ARANGODB_VERSION_PATCH "4") - set(ARANGODB_VERSION_RELEASE_TYPE "2") + set(ARANGODB_VERSION_RELEASE_TYPE "3") set(ARANGODB_VERSION_RELEASE_NUMBER "") else() unset (ARANGODB_VERSION_RELEASE_TYPE) # do not remove space diff --git a/js/apps/system/_admin/aardvark/APP/api-docs.json b/js/apps/system/_admin/aardvark/APP/api-docs.json index 60a9b1a0c234..c5e1be091b71 100644 --- a/js/apps/system/_admin/aardvark/APP/api-docs.json +++ b/js/apps/system/_admin/aardvark/APP/api-docs.json @@ -2,7 +2,7 @@ "info": { "description": "ArangoDB REST API Interface", "title": "ArangoDB", - "version": "3.12.4-2" + "version": "3.12.4-3" }, "openapi": "3.1.0", "paths": { From 6f08b1a42790d3e8a5fe6821825571c560a537c5 Mon Sep 17 00:00:00 2001 From: Max Neunhoeffer Date: Fri, 2 May 2025 12:14:37 +0200 Subject: [PATCH 6/7] Non-unique log id. --- arangod/Aql/ExecutionBlockImpl.tpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arangod/Aql/ExecutionBlockImpl.tpp b/arangod/Aql/ExecutionBlockImpl.tpp index 4b0e8e553d32..7bb3c8d4b430 100644 --- a/arangod/Aql/ExecutionBlockImpl.tpp +++ b/arangod/Aql/ExecutionBlockImpl.tpp @@ -1090,7 +1090,7 @@ auto ExecutionBlockImpl::executeFetcher(ExecutionContext& ctx, bool hasStoppedAsyncTasks = block->hasStoppedAsyncTasks(); if (hasStoppedAsyncTasks) { - LOG_TOPIC("14d20", WARN, Logger::AQL) + LOG_TOPIC("14d22", WARN, Logger::AQL) << "[query#" << block->getQuery().id() << "] ALERT" << block->printBlockInfo() << " was asked to stop async task. We still start one. " From 347ea6b489633e1a353d70c0c40d5fb1e3f4b752 Mon Sep 17 00:00:00 2001 From: Max Neunhoeffer Date: Fri, 2 May 2025 12:21:22 +0200 Subject: [PATCH 7/7] Take out wrong assertion. --- arangod/Aql/ExecutionBlockImpl.tpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/arangod/Aql/ExecutionBlockImpl.tpp b/arangod/Aql/ExecutionBlockImpl.tpp index 7bb3c8d4b430..741548111e6a 100644 --- a/arangod/Aql/ExecutionBlockImpl.tpp +++ b/arangod/Aql/ExecutionBlockImpl.tpp @@ -354,8 +354,6 @@ ExecutionBlockImpl::~ExecutionBlockImpl() { template void ExecutionBlockImpl::stopAsyncTasks() { - TRI_ASSERT(!_stoppedAsyncTasks) - << "Someone already stopped async tasks for " << printBlockInfo(); _stoppedAsyncTasks = true; if (_prefetchTask) { // Double use diagnostics: