From 8dfb58764bf1d0c857f935e0c27e02ad345f243a Mon Sep 17 00:00:00 2001 From: jimingquan <6930445+nevermore3@users.noreply.github.com> Date: Tue, 7 Nov 2023 10:29:16 +0800 Subject: [PATCH 01/21] fix noloop path limit (#5751) * fix oneway path limit error * add test case --- src/graph/executor/algo/AllPathsExecutor.cpp | 12 ++++++------ src/parser/scanner.lex | 2 +- tests/tck/features/path/AllPath.IntVid.feature | 10 ++++++++++ tests/tck/features/path/AllPath.feature | 10 ++++++++++ 4 files changed, 27 insertions(+), 7 deletions(-) diff --git a/src/graph/executor/algo/AllPathsExecutor.cpp b/src/graph/executor/algo/AllPathsExecutor.cpp index 0dd2cfba7ff..d5f1f9d5439 100644 --- a/src/graph/executor/algo/AllPathsExecutor.cpp +++ b/src/graph/executor/algo/AllPathsExecutor.cpp @@ -273,6 +273,12 @@ folly::Future AllPathsExecutor::buildPathMultiJobs() { }) .thenValue([this, conjunctPathTime](auto&& resps) { NG_RETURN_IF_ERROR(resps); + if (result_.rows.size() > limit_) { + result_.rows.resize(limit_); + } + if (offset_ != 0) { + result_.rows.erase(result_.rows.begin(), result_.rows.begin() + offset_); + } addState("conjunct_path_time", conjunctPathTime); return Status::OK(); }); @@ -557,12 +563,6 @@ folly::Future AllPathsExecutor::conjunctPath(std::vector& leftPa std::make_move_iterator(rows.begin()), std::make_move_iterator(rows.end())); } - if (result_.rows.size() > limit_) { - result_.rows.resize(limit_); - } - if (offset_ != 0) { - result_.rows.erase(result_.rows.begin(), result_.rows.begin() + offset_); - } return Status::OK(); }) .thenError(folly::tag_t{}, diff --git a/src/parser/scanner.lex b/src/parser/scanner.lex index ca3c1f3aaee..ba4e539c895 100644 --- a/src/parser/scanner.lex +++ b/src/parser/scanner.lex @@ -258,7 +258,7 @@ LABEL_FULL_WIDTH {CN_EN_FULL_WIDTH}{CN_EN_NUM_FULL_WIDTH}* "SHORTEST" { return TokenType::KW_SHORTEST; } "NOLOOP" { return TokenType::KW_NOLOOP; } "SHORTESTPATH" { return TokenType::KW_SHORTESTPATH; } -"AllSHORTESTPATHS" { return TokenType::KW_ALLSHORTESTPATHS; } +"ALLSHORTESTPATHS" { return TokenType::KW_ALLSHORTESTPATHS; } "OUT" { return TokenType::KW_OUT; } "BOTH" { return TokenType::KW_BOTH; } "SUBGRAPH" { return TokenType::KW_SUBGRAPH; } diff --git a/tests/tck/features/path/AllPath.IntVid.feature b/tests/tck/features/path/AllPath.IntVid.feature index 18ac5bc4d1c..4787c7b802b 100644 --- a/tests/tck/features/path/AllPath.IntVid.feature +++ b/tests/tck/features/path/AllPath.IntVid.feature @@ -125,6 +125,16 @@ Feature: Integer Vid All Path | <("Tony Parker")-[:like@0]->("Manu Ginobili")-[:like@0]->("Tim Duncan")> | | <("Tony Parker")-[:like@0]->("Tim Duncan")> | | <("Tony Parker")-[:like@0]->("Tim Duncan")-[:like@0]->("Manu Ginobili")-[:like@0]->("Tim Duncan")> | + When executing query: + """ + lookup on player where player.age>20 YIELD id(vertex) as vid + | go 1 step from $-.vid over * where "player" in labels($$) yield distinct id($$) as dst,$-.vid as src + | find noloop path from $-.src to $-.dst over * upto 1 step yield path as p | limit 10,10 + | yield count(*) + """ + Then the result should be, in any order, with relax comparison: + | count(*) | + | 10 | Scenario: Integer Vid [1] ALL PATH REVERSELY Given a graph with space named "nba_int_vid" diff --git a/tests/tck/features/path/AllPath.feature b/tests/tck/features/path/AllPath.feature index b17c6c4ef7b..596f8709b5d 100644 --- a/tests/tck/features/path/AllPath.feature +++ b/tests/tck/features/path/AllPath.feature @@ -279,6 +279,16 @@ Feature: All Path Then the result should be, in any order, with relax comparison: | count(*) | | 0 | + When executing query: + """ + lookup on player where player.age>20 YIELD id(vertex) as vid + | go 1 step from $-.vid over * where "player" in labels($$) yield distinct id($$) as dst,$-.vid as src + | find noloop path from $-.src to $-.dst over * upto 1 step yield path as p | limit 10,10 + | yield count(*) + """ + Then the result should be, in any order, with relax comparison: + | count(*) | + | 10 | Scenario: [1] ALL PATH REVERSELY When executing query: From 4c6a0a7dae7df0373b7e8eb7537e27f7de012422 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=85=B0=E5=B7=9E=E5=B0=8F=E7=BA=A2=E9=B8=A1?= Date: Wed, 15 Nov 2023 16:19:17 +0800 Subject: [PATCH 02/21] Reduce the blocking time of the write lock when deleting space (#5754) * Reduce the blocking time of the write lock when deleting space When the number of parts of a space is relatively large and the amount of data written is also large, it will block for a long time in the removeSpace function when deleting the space. Affect business read and write * Resolve compilation issues Resolve compilation issues --- src/kvstore/NebulaStore.cpp | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/src/kvstore/NebulaStore.cpp b/src/kvstore/NebulaStore.cpp index 218062413e3..5fc947b9ac8 100644 --- a/src/kvstore/NebulaStore.cpp +++ b/src/kvstore/NebulaStore.cpp @@ -516,13 +516,17 @@ std::shared_ptr NebulaStore::newPart(GraphSpaceID spaceId, } void NebulaStore::removeSpace(GraphSpaceID spaceId) { - folly::RWSpinLock::WriteHolder wh(&lock_); - if (beforeRemoveSpace_) { - beforeRemoveSpace_(spaceId); + { + folly::RWSpinLock::WriteHolder wh(&lock_); + if (beforeRemoveSpace_) { + beforeRemoveSpace_(spaceId); + } } - auto spaceIt = this->spaces_.find(spaceId); - if (spaceIt != this->spaces_.end()) { + auto spaceOr = space(spaceId); + if (ok(spaceOr)) { + folly::RWSpinLock::WriteHolder wh(&lock_); + auto spaceIt = this->spaces_.find(spaceId); for (auto& [partId, part] : spaceIt->second->parts_) { // before calling removeSpace, meta client would call removePart to remove all parts in // meta cache, which do not contain learners, so we remove them here @@ -530,7 +534,11 @@ void NebulaStore::removeSpace(GraphSpaceID spaceId) { removePart(spaceId, partId, false); } } - auto& engines = spaceIt->second->engines_; + this->spaces_.erase(spaceIt); + } + if (ok(spaceOr)) { + auto spaceIt = value(spaceOr); + auto& engines = spaceIt->engines_; for (auto& engine : engines) { auto parts = engine->allParts(); for (auto& partId : parts) { @@ -538,14 +546,13 @@ void NebulaStore::removeSpace(GraphSpaceID spaceId) { } CHECK_EQ(0, engine->totalPartsNum()); } - CHECK(spaceIt->second->parts_.empty()); + CHECK(spaceIt->parts_.empty()); std::vector enginePaths; if (FLAGS_auto_remove_invalid_space) { for (auto& engine : engines) { enginePaths.emplace_back(engine->getDataRoot()); } } - this->spaces_.erase(spaceIt); if (FLAGS_auto_remove_invalid_space) { for (const auto& path : enginePaths) { removeSpaceDir(path); From 54d18fb219bf75c0fbf1d12a99cef7d12c0e7c7e Mon Sep 17 00:00:00 2001 From: "Harris.Chu" <1726587+HarrisChu@users.noreply.github.com> Date: Wed, 29 Nov 2023 10:20:13 +0800 Subject: [PATCH 03/21] fix round crash (#5773) --- src/common/function/FunctionManager.cpp | 2 +- .../features/expression/FunctionCall.feature | 32 ++++++++++++++++++- 2 files changed, 32 insertions(+), 2 deletions(-) diff --git a/src/common/function/FunctionManager.cpp b/src/common/function/FunctionManager.cpp index 0d9e6cd93ee..cc2393a775d 100644 --- a/src/common/function/FunctionManager.cpp +++ b/src/common/function/FunctionManager.cpp @@ -584,7 +584,7 @@ FunctionManager::FunctionManager() { case Value::Type::FLOAT: { if (args.size() >= 2) { if (args[1].get().type() == Value::Type::INT) { - auto val = args[0].get().getFloat(); + auto val = args[0].get().isInt() ? args[0].get().getInt() : args[0].get().getFloat(); auto decimal = args[1].get().getInt(); auto factor = pow(10.0, decimal); diff --git a/tests/tck/features/expression/FunctionCall.feature b/tests/tck/features/expression/FunctionCall.feature index dc569e50294..541f5b1443b 100644 --- a/tests/tck/features/expression/FunctionCall.feature +++ b/tests/tck/features/expression/FunctionCall.feature @@ -10,7 +10,7 @@ Feature: Function Call Expression When executing query: """ YIELD sign(38) AS a, sign(-2) AS b, sign(0.421) AS c, - sign(-1.0) AS d, sign(0) AS e, sign(abs(-3)) AS f + sign(-1.0) AS d, sign(0) AS e, sign(abs(-3)) AS f """ Then the result should be, in any order: | a | b | c | d | e | f | @@ -185,6 +185,36 @@ Feature: Function Call Expression | result | | 0.0 | + Scenario: round int + When executing query: + """ + YIELD round(12345, 2) as result + """ + Then the result should be, in any order: + | result | + | 12345.0 | + When executing query: + """ + YIELD round(12345, 0) as result + """ + Then the result should be, in any order: + | result | + | 12345.0 | + When executing query: + """ + YIELD round(12345, -2) as result + """ + Then the result should be, in any order: + | result | + | 12300.0 | + When executing query: + """ + YIELD round(12345, -5) as result + """ + Then the result should be, in any order: + | result | + | 0.0 | + Scenario: error check When executing query: """ From 82565cd47d581d1ad4110c286a00ba9f9b5830b5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=85=B0=E5=B7=9E=E5=B0=8F=E7=BA=A2=E9=B8=A1?= Date: Mon, 11 Dec 2023 15:03:20 +0800 Subject: [PATCH 04/21] Optimize the code of meta session manager and remove the session lock (#5762) * Optimize the code of meta session management and remove the session lock https://discuss.nebula-graph.com.cn/t/topic/14340/6 https://github.com/vesoft-inc/nebula/issues/5760 The session management operation in the meta service will increase the delay in the highly concurrent session write request scenario due to the existence of locks. Now rewrite the code using the atomic operations of rocksdb * handle cpplint check * handle cpplint check * format SessionManagerProcessor.cpp * Update SessionManagerProcessor.cpp --------- Co-authored-by: Wey Gu --- .../session/SessionManagerProcessor.cpp | 326 ++++++++++-------- 1 file changed, 176 insertions(+), 150 deletions(-) diff --git a/src/meta/processors/session/SessionManagerProcessor.cpp b/src/meta/processors/session/SessionManagerProcessor.cpp index e1860e4b24b..47449671ef2 100644 --- a/src/meta/processors/session/SessionManagerProcessor.cpp +++ b/src/meta/processors/session/SessionManagerProcessor.cpp @@ -8,17 +8,8 @@ namespace nebula { namespace meta { -void CreateSessionProcessor::process(const cpp2::CreateSessionReq& req) { - folly::SharedMutex::WriteHolder holder(LockUtils::sessionLock()); - const auto& user = req.get_user(); - auto ret = userExist(user); - if (ret != nebula::cpp2::ErrorCode::SUCCEEDED) { - LOG(INFO) << "User does not exist, errorCode: " << apache::thrift::util::enumNameSafe(ret); - handleErrorCode(ret); - onFinished(); - return; - } - +void CreateSessionProcessor::process(const cpp2::CreateSessionReq &req) { + auto user = req.get_user(); cpp2::Session session; // The sessionId is generated by microsecond timestamp session.session_id_ref() = time::WallClock::fastNowInMicroSec(); @@ -27,97 +18,120 @@ void CreateSessionProcessor::process(const cpp2::CreateSessionReq& req) { session.user_name_ref() = user; session.graph_addr_ref() = req.get_graph_addr(); session.client_ip_ref() = req.get_client_ip(); - - std::vector data; - data.emplace_back(MetaKeyUtils::sessionKey(session.get_session_id()), - MetaKeyUtils::sessionVal(session)); resp_.session_ref() = session; - ret = doSyncPut(std::move(data)); - if (ret != nebula::cpp2::ErrorCode::SUCCEEDED) { - LOG(INFO) << "Put data error on meta server, errorCode: " - << apache::thrift::util::enumNameSafe(ret); - } - handleErrorCode(ret); - onFinished(); -} -void UpdateSessionsProcessor::process(const cpp2::UpdateSessionsReq& req) { - folly::SharedMutex::WriteHolder holder(LockUtils::sessionLock()); - std::vector data; - std::unordered_map> - killedQueries; + // AtomicOp for create + auto getAtomicOp = [this, session = std::move(session), user = std::move(user)]() mutable { + kvstore::MergeableAtomicOpResult atomicOp; + // read userKey + atomicOp.readSet.emplace_back(MetaKeyUtils::userKey(user)); + auto ret = userExist(user); + if (ret != nebula::cpp2::ErrorCode::SUCCEEDED) { + LOG(INFO) << "User does not exist, errorCode: " << apache::thrift::util::enumNameSafe(ret); + atomicOp.code = ret; + return atomicOp; + } + auto batchHolder = std::make_unique(); + auto sessionKey = MetaKeyUtils::sessionKey(session.get_session_id()); + // write sessionKey + atomicOp.writeSet.emplace_back(sessionKey); + batchHolder->put(std::move(sessionKey), MetaKeyUtils::sessionVal(session)); + atomicOp.batch = encodeBatchValue(batchHolder->getBatch()); + atomicOp.code = nebula::cpp2::ErrorCode::SUCCEEDED; + return atomicOp; + }; + + auto cb = [this](nebula::cpp2::ErrorCode ec) { + if (ec != nebula::cpp2::ErrorCode::SUCCEEDED) { + LOG(INFO) << "Put data error on meta server, errorCode: " + << apache::thrift::util::enumNameSafe(ec); + } + handleErrorCode(ec); + onFinished(); + }; - std::vector killedSessions; + kvstore_->asyncAtomicOp(kDefaultSpaceId, kDefaultPartId, std::move(getAtomicOp), std::move(cb)); +} - for (auto& session : req.get_sessions()) { - auto sessionId = session.get_session_id(); - auto sessionKey = MetaKeyUtils::sessionKey(sessionId); - auto ret = doGet(sessionKey); - if (!nebula::ok(ret)) { - auto errCode = nebula::error(ret); - LOG(INFO) << "Session id '" << sessionId << "' not found"; - // If the session requested to be updated can not be found in meta, we consider the session - // has been killed - if (errCode == nebula::cpp2::ErrorCode::E_KEY_NOT_FOUND) { - killedSessions.emplace_back(sessionId); - continue; - } else { - handleErrorCode(errCode); - onFinished(); - return; +void UpdateSessionsProcessor::process(const cpp2::UpdateSessionsReq &req) { + // AtomicOp for update + auto getAtomicOp = [this, req]() mutable { + kvstore::MergeableAtomicOpResult atomicOp; + auto batchHolder = std::make_unique(); + std::unordered_map> + killedQueries; + std::vector killedSessions; + + for (auto &session : req.get_sessions()) { + auto sessionId = session.get_session_id(); + auto sessionKey = MetaKeyUtils::sessionKey(sessionId); + atomicOp.readSet.emplace_back(sessionKey); + auto ret = doGet(sessionKey); + if (!nebula::ok(ret)) { + auto errCode = nebula::error(ret); + // If the session requested to be updated can not be found in meta, we consider the session + // has been killed + if (errCode == nebula::cpp2::ErrorCode::E_KEY_NOT_FOUND) { + killedSessions.emplace_back(sessionId); + continue; + } else { + atomicOp.code = errCode; + return atomicOp; + } } - } - // update sessions to be saved if query is being killed, and return them to - // client. - auto& newQueries = *session.queries_ref(); - std::unordered_map killedQueriesInCurrentSession; - auto sessionInMeta = MetaKeyUtils::parseSessionVal(nebula::value(ret)); - for (const auto& savedQuery : sessionInMeta.get_queries()) { - auto epId = savedQuery.first; - auto newQuery = newQueries.find(epId); - if (newQuery == newQueries.end()) { - continue; + // update sessions to be saved if query is being killed, and return them to + // client. + auto &newQueries = *session.queries_ref(); + std::unordered_map killedQueriesInCurrentSession; + auto sessionInMeta = MetaKeyUtils::parseSessionVal(nebula::value(ret)); + for (const auto &savedQuery : sessionInMeta.get_queries()) { + auto epId = savedQuery.first; + auto newQuery = newQueries.find(epId); + if (newQuery == newQueries.end()) { + continue; + } + auto &desc = savedQuery.second; + if (desc.get_status() == cpp2::QueryStatus::KILLING) { + const_cast(newQuery->second).status_ref() = cpp2::QueryStatus::KILLING; + killedQueriesInCurrentSession.emplace(epId, desc); + } } - auto& desc = savedQuery.second; - if (desc.get_status() == cpp2::QueryStatus::KILLING) { - const_cast(newQuery->second).status_ref() = cpp2::QueryStatus::KILLING; - killedQueriesInCurrentSession.emplace(epId, desc); + if (!killedQueriesInCurrentSession.empty()) { + killedQueries[sessionId] = std::move(killedQueriesInCurrentSession); } - } - if (!killedQueriesInCurrentSession.empty()) { - killedQueries[sessionId] = std::move(killedQueriesInCurrentSession); - } - if (sessionInMeta.get_update_time() > session.get_update_time()) { - VLOG(3) << "The session id: " << session.get_session_id() - << ", the new update time: " << session.get_update_time() - << ", the old update time: " << sessionInMeta.get_update_time(); - continue; + if (sessionInMeta.get_update_time() > session.get_update_time()) { + continue; + } + + atomicOp.writeSet.emplace_back(sessionKey); + batchHolder->put(std::move(sessionKey), MetaKeyUtils::sessionVal(session)); } - data.emplace_back(MetaKeyUtils::sessionKey(sessionId), MetaKeyUtils::sessionVal(session)); - } + resp_.killed_queries_ref() = std::move(killedQueries); + resp_.killed_sessions_ref() = std::move(killedSessions); + + atomicOp.batch = encodeBatchValue(batchHolder->getBatch()); + atomicOp.code = nebula::cpp2::ErrorCode::SUCCEEDED; + return atomicOp; + }; - auto ret = doSyncPut(std::move(data)); - if (ret != nebula::cpp2::ErrorCode::SUCCEEDED) { - LOG(INFO) << "Put data error on meta server, errorCode: " - << apache::thrift::util::enumNameSafe(ret); - handleErrorCode(ret); + auto cb = [this](nebula::cpp2::ErrorCode ec) { + if (ec != nebula::cpp2::ErrorCode::SUCCEEDED) { + LOG(INFO) << "Put data error on meta server, errorCode: " + << apache::thrift::util::enumNameSafe(ec); + } + handleErrorCode(ec); onFinished(); - return; - } + }; - resp_.killed_queries_ref() = std::move(killedQueries); - resp_.killed_sessions_ref() = std::move(killedSessions); - handleErrorCode(nebula::cpp2::ErrorCode::SUCCEEDED); - onFinished(); + kvstore_->asyncAtomicOp(kDefaultSpaceId, kDefaultPartId, std::move(getAtomicOp), std::move(cb)); } -void ListSessionsProcessor::process(const cpp2::ListSessionsReq&) { - folly::SharedMutex::ReadHolder holder(LockUtils::sessionLock()); - auto& prefix = MetaKeyUtils::sessionPrefix(); +void ListSessionsProcessor::process(const cpp2::ListSessionsReq &) { + auto &prefix = MetaKeyUtils::sessionPrefix(); auto ret = doPrefix(prefix); if (!nebula::ok(ret)) { handleErrorCode(nebula::error(ret)); @@ -139,8 +153,7 @@ void ListSessionsProcessor::process(const cpp2::ListSessionsReq&) { onFinished(); } -void GetSessionProcessor::process(const cpp2::GetSessionReq& req) { - folly::SharedMutex::ReadHolder holder(LockUtils::sessionLock()); +void GetSessionProcessor::process(const cpp2::GetSessionReq &req) { auto sessionId = req.get_session_id(); auto sessionKey = MetaKeyUtils::sessionKey(sessionId); auto ret = doGet(sessionKey); @@ -161,47 +174,53 @@ void GetSessionProcessor::process(const cpp2::GetSessionReq& req) { onFinished(); } -void RemoveSessionProcessor::process(const cpp2::RemoveSessionReq& req) { - folly::SharedMutex::WriteHolder holder(LockUtils::sessionLock()); +void RemoveSessionProcessor::process(const cpp2::RemoveSessionReq &req) { std::vector killedSessions; - auto sessionIds = req.get_session_ids(); for (auto sessionId : sessionIds) { - auto sessionKey = MetaKeyUtils::sessionKey(sessionId); - auto ret = doGet(sessionKey); - - if (!nebula::ok(ret)) { - auto errCode = nebula::error(ret); - LOG(INFO) << "Session id `" << sessionId << "' not found"; - - // If the session is not found, we should continue to remove other sessions. - if (errCode == nebula::cpp2::ErrorCode::E_KEY_NOT_FOUND) { - continue; - } else { // for other error like leader change, we handle the error and return. - handleErrorCode(errCode); - onFinished(); - return; + // AtomicOp for remove + auto getAtomicOp = [this, sessionId] { + kvstore::MergeableAtomicOpResult atomicOp; + auto batchHolder = std::make_unique(); + auto sessionKey = MetaKeyUtils::sessionKey(sessionId); + atomicOp.readSet.emplace_back(sessionKey); + auto ret = doGet(sessionKey); + if (!nebula::ok(ret)) { + atomicOp.code = nebula::error(ret); + return atomicOp; } - } + atomicOp.writeSet.emplace_back(sessionKey); + batchHolder->remove(std::move(sessionKey)); + atomicOp.batch = encodeBatchValue(batchHolder->getBatch()); + atomicOp.code = nebula::cpp2::ErrorCode::SUCCEEDED; + return atomicOp; + }; // Remove session key from kvstore folly::Baton baton; nebula::cpp2::ErrorCode errorCode; - kvstore_->asyncRemove(kDefaultSpaceId, - kDefaultPartId, - sessionKey, - [this, &baton, &errorCode](nebula::cpp2::ErrorCode code) { - this->handleErrorCode(code); - errorCode = code; - baton.post(); - }); + kvstore_->asyncAtomicOp(kDefaultSpaceId, + kDefaultPartId, + std::move(getAtomicOp), + [this, &baton, &errorCode](nebula::cpp2::ErrorCode code) { + this->handleErrorCode(code); + errorCode = code; + baton.post(); + }); baton.wait(); // continue if the session is not removed successfully if (errorCode != nebula::cpp2::ErrorCode::SUCCEEDED) { LOG(ERROR) << "Remove session key failed, error code: " << static_cast(errorCode); - continue; + if (errorCode == nebula::cpp2::ErrorCode::E_KEY_NOT_FOUND) { + continue; + } else { + // for other error like leader change, we handle the error and return. + handleErrorCode(errorCode); + onFinished(); + return; + } } // record the removed session id @@ -213,47 +232,54 @@ void RemoveSessionProcessor::process(const cpp2::RemoveSessionReq& req) { onFinished(); } -void KillQueryProcessor::process(const cpp2::KillQueryReq& req) { - folly::SharedMutex::WriteHolder holder(LockUtils::sessionLock()); - auto& killQueries = req.get_kill_queries(); - - std::vector data; - for (auto& kv : killQueries) { - auto sessionId = kv.first; - auto sessionKey = MetaKeyUtils::sessionKey(sessionId); - auto ret = doGet(sessionKey); - if (!nebula::ok(ret)) { - auto errCode = nebula::error(ret); - LOG(INFO) << "Session id `" << sessionId << "' not found"; - if (errCode == nebula::cpp2::ErrorCode::E_KEY_NOT_FOUND) { - errCode = nebula::cpp2::ErrorCode::E_SESSION_NOT_FOUND; +void KillQueryProcessor::process(const cpp2::KillQueryReq &req) { + auto &killQueries = req.get_kill_queries(); + auto getAtomicOp = [this, killQueries] { + kvstore::MergeableAtomicOpResult atomicOp; + auto batchHolder = std::make_unique(); + for (auto &kv : killQueries) { + auto sessionId = kv.first; + auto sessionKey = MetaKeyUtils::sessionKey(sessionId); + atomicOp.readSet.emplace_back(sessionKey); + auto ret = doGet(sessionKey); + if (!nebula::ok(ret)) { + auto errCode = nebula::error(ret); + if (errCode == nebula::cpp2::ErrorCode::E_KEY_NOT_FOUND) { + errCode = nebula::cpp2::ErrorCode::E_SESSION_NOT_FOUND; + } + atomicOp.code = errCode; + return atomicOp; } - handleErrorCode(errCode); - onFinished(); - return; - } - auto session = MetaKeyUtils::parseSessionVal(nebula::value(ret)); - for (auto& epId : kv.second) { - auto query = session.queries_ref()->find(epId); - if (query == session.queries_ref()->end()) { - handleErrorCode(nebula::cpp2::ErrorCode::E_QUERY_NOT_FOUND); - onFinished(); - return; + auto session = MetaKeyUtils::parseSessionVal(nebula::value(ret)); + for (auto &epId : kv.second) { + auto query = session.queries_ref()->find(epId); + if (query == session.queries_ref()->end()) { + atomicOp.code = nebula::cpp2::ErrorCode::E_QUERY_NOT_FOUND; + return atomicOp; + } + query->second.status_ref() = cpp2::QueryStatus::KILLING; } - query->second.status_ref() = cpp2::QueryStatus::KILLING; + + atomicOp.writeSet.emplace_back(sessionKey); + batchHolder->put(std::move(sessionKey), MetaKeyUtils::sessionVal(session)); } - data.emplace_back(MetaKeyUtils::sessionKey(sessionId), MetaKeyUtils::sessionVal(session)); - } + atomicOp.batch = encodeBatchValue(batchHolder->getBatch()); + atomicOp.code = nebula::cpp2::ErrorCode::SUCCEEDED; + return atomicOp; + }; - auto putRet = doSyncPut(std::move(data)); - if (putRet != nebula::cpp2::ErrorCode::SUCCEEDED) { - LOG(INFO) << "Put data error on meta server, errorCode: " - << apache::thrift::util::enumNameSafe(putRet); - } - handleErrorCode(putRet); - onFinished(); + auto cb = [this](nebula::cpp2::ErrorCode ec) { + if (ec != nebula::cpp2::ErrorCode::SUCCEEDED) { + LOG(INFO) << "Put data error on meta server, errorCode: " + << apache::thrift::util::enumNameSafe(ec); + } + handleErrorCode(ec); + onFinished(); + }; + + kvstore_->asyncAtomicOp(kDefaultSpaceId, kDefaultPartId, std::move(getAtomicOp), std::move(cb)); } } // namespace meta From 3305c8753fa506bdd265d201a60f7c2e105808ad Mon Sep 17 00:00:00 2001 From: "hs.zhang" <22708345+cangfengzhs@users.noreply.github.com> Date: Mon, 18 Dec 2023 19:10:20 +0800 Subject: [PATCH 05/21] copy local id when clone space (#3005) (#5781) * copy local id when clone space * add test * fix bug * fix bug --------- Co-authored-by: Sophie <84560950+Sophie-Xie@users.noreply.github.com> Co-authored-by: Doodle <13706157+critical27@users.noreply.github.com> --- .../parts/CreateSpaceAsProcessor.cpp | 35 +++++++++++++++++++ .../processors/parts/CreateSpaceAsProcessor.h | 3 ++ .../tck/features/schema/CreateSpaceAs.feature | 18 ++++++++++ 3 files changed, 56 insertions(+) diff --git a/src/meta/processors/parts/CreateSpaceAsProcessor.cpp b/src/meta/processors/parts/CreateSpaceAsProcessor.cpp index b2f87c9ac78..dd3a77a1c35 100644 --- a/src/meta/processors/parts/CreateSpaceAsProcessor.cpp +++ b/src/meta/processors/parts/CreateSpaceAsProcessor.cpp @@ -92,6 +92,15 @@ void CreateSpaceAsProcessor::process(const cpp2::CreateSpaceAsReq &req) { return; } + auto newLocalIdKey = makeLocalIDKey(nebula::value(oldSpaceId), nebula::value(newSpaceId)); + if (nebula::ok(newLocalIdKey)) { + data.push_back(nebula::value(newLocalIdKey)); + } else { + rc_ = nebula::error(newLocalIdKey); + LOG(INFO) << "Make new local id failed, " << apache::thrift::util::enumNameSafe(rc_); + return; + } + resp_.id_ref() = to(nebula::value(newSpaceId), EntryType::SPACE); auto timeInMilliSec = time::WallClock::fastNowInMilliSec(); LastUpdateTimeMan::update(data, timeInMilliSec); @@ -231,5 +240,31 @@ ErrorOr> CreateSpaceAsProcesso return data; } +ErrorOr CreateSpaceAsProcessor::makeLocalIDKey( + GraphSpaceID oldSpaceId, GraphSpaceID newSpaceId) { + auto localIdkey = MetaKeyUtils::localIdKey(oldSpaceId); + int32_t id; + std::string val; + auto ret = kvstore_->get(kDefaultSpaceId, kDefaultPartId, localIdkey, &val); + if (ret != nebula::cpp2::ErrorCode::SUCCEEDED) { + if (ret != nebula::cpp2::ErrorCode::E_KEY_NOT_FOUND) { + return ret; + } + + // In order to be compatible with the existing old schema, and simple to implement, + // when the local_id record does not exist in space, directly use the smallest + // id available globally. + auto globalIdRet = getAvailableGlobalId(); + if (!nebula::ok(globalIdRet)) { + return nebula::error(globalIdRet); + } + id = nebula::value(globalIdRet); + } else { + id = *reinterpret_cast(val.c_str()); + } + auto newLocalIdKey = MetaKeyUtils::localIdKey(newSpaceId); + return {newLocalIdKey, std::string(reinterpret_cast(&id), sizeof(id))}; +} + } // namespace meta } // namespace nebula diff --git a/src/meta/processors/parts/CreateSpaceAsProcessor.h b/src/meta/processors/parts/CreateSpaceAsProcessor.h index 84f7536371a..5d9f5d4270a 100644 --- a/src/meta/processors/parts/CreateSpaceAsProcessor.h +++ b/src/meta/processors/parts/CreateSpaceAsProcessor.h @@ -43,6 +43,9 @@ class CreateSpaceAsProcessor : public BaseProcessor { ErrorOr> makeNewIndexes( GraphSpaceID oldSpaceId, GraphSpaceID newSpaceId); + ErrorOr makeLocalIDKey(GraphSpaceID oldSpaceId, + GraphSpaceID newSpaceId); + nebula::cpp2::ErrorCode rc_{nebula::cpp2::ErrorCode::SUCCEEDED}; private: diff --git a/tests/tck/features/schema/CreateSpaceAs.feature b/tests/tck/features/schema/CreateSpaceAs.feature index 9963d24a274..a7e345fe444 100644 --- a/tests/tck/features/schema/CreateSpaceAs.feature +++ b/tests/tck/features/schema/CreateSpaceAs.feature @@ -164,6 +164,24 @@ Feature: Create space as another space Then the result should be, in any order: | src | dst | rank | | "1" | "2" | 0 | + When executing query: + """ + create tag t2 (col1 int); + """ + Then the execution should be successful + When executing query: + """ + create tag index i3 on t2(col1); + """ + Then the execution should be successful + When executing query: + """ + show tag indexes; + """ + Then the result should be, in any order: + | Index Name | By Tag | Columns | + | "i1" | "t1" | ["col1"] | + | "i3" | "t2" | ["col1"] | Then drop the used space Scenario: clone space if not exist From a10aac8180b7f12f0fc641b15842d26cecb6e4c0 Mon Sep 17 00:00:00 2001 From: jimingquan <6930445+nevermore3@users.noreply.github.com> Date: Thu, 21 Dec 2023 17:24:37 +0800 Subject: [PATCH 06/21] fix allpath without prop when one step (#5759) --- src/graph/executor/algo/AllPathsExecutor.cpp | 4 ++-- tests/tck/features/path/AllPath.feature | 8 ++++++++ 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/src/graph/executor/algo/AllPathsExecutor.cpp b/src/graph/executor/algo/AllPathsExecutor.cpp index d5f1f9d5439..aa4422e089e 100644 --- a/src/graph/executor/algo/AllPathsExecutor.cpp +++ b/src/graph/executor/algo/AllPathsExecutor.cpp @@ -457,8 +457,8 @@ void AllPathsExecutor::buildOneWayPath(std::vector& paths, bool reverse) auto iter = emptyPropVertices_.find(emptyPropVertex); if (iter == emptyPropVertices_.end()) { emptyPropVids_.emplace_back(dst); - emptyPropVertices_.emplace(emptyPropVertex); } + emptyPropVertices_.emplace(emptyPropVertex); result_.rows.emplace_back(std::move(row)); } } @@ -506,8 +506,8 @@ std::vector AllPathsExecutor::buildOneWayPathFromHashTable(bool reverse) { auto iter = emptyPropVertices_.find(emptyPropVertex); if (iter == emptyPropVertices_.end()) { emptyPropVids_.emplace_back(vid); - emptyPropVertices_.emplace(emptyPropVertex); } + emptyPropVertices_.emplace(emptyPropVertex); } return result; } diff --git a/tests/tck/features/path/AllPath.feature b/tests/tck/features/path/AllPath.feature index 596f8709b5d..cc9a8184cb2 100644 --- a/tests/tck/features/path/AllPath.feature +++ b/tests/tck/features/path/AllPath.feature @@ -371,6 +371,14 @@ Feature: All Path | <("Tim Duncan" :bachelor{name: "Tim Duncan", speciality: "psychology"} :player{age: 42, name: "Tim Duncan"})-[:like@0 {likeness: 95}]->("Tony Parker" :player{age: 36, name: "Tony Parker"})> | | <("Tim Duncan" :bachelor{name: "Tim Duncan", speciality: "psychology"} :player{age: 42, name: "Tim Duncan"})-[:like@0 {likeness: 95}]->("Manu Ginobili" :player{age: 41, name: "Manu Ginobili"})-[:like@0 {likeness: 90}]->("Tim Duncan" :bachelor{name: "Tim Duncan", speciality: "psychology"} :player{age: 42, name: "Tim Duncan"})-[:like@0 {likeness: 95}]->("Tony Parker" :player{age: 36, name: "Tony Parker"})> | | <("Tim Duncan" :bachelor{name: "Tim Duncan", speciality: "psychology"} :player{age: 42, name: "Tim Duncan"})-[:like@0 {likeness: 95}]->("Tony Parker" :player{age: 36, name: "Tony Parker"})-[:like@0 {likeness: 90}]->("LaMarcus Aldridge" :player{age: 33, name: "LaMarcus Aldridge"})-[:like@0 {likeness: 75}]->("Tony Parker" :player{age: 36, name: "Tony Parker"})> | + When executing query: + """ + FIND ALL PATH WITH PROP FROM "Tim Duncan" TO "Tony Parker" OVER * UPTO 1 STEPS YIELD path as p + """ + Then the result should be, in any order, with relax comparison: + | p | + | <("Tim Duncan" :player{age: 42, name: "Tim Duncan"} :bachelor{name: "Tim Duncan", speciality: "psychology"})-[:like@0 {likeness: 95}]->("Tony Parker" :player{age: 36, name: "Tony Parker"})> | + | <("Tim Duncan" :player{age: 42, name: "Tim Duncan"} :bachelor{name: "Tim Duncan", speciality: "psychology"})-[:teammate@0 {end_year: 2016, start_year: 2001}]->("Tony Parker" :player{age: 36, name: "Tony Parker"})> | Scenario: ALL Path constant filter When executing query: From b84afe6d0c1200ab57be1562e4b26e97a57e9aaf Mon Sep 17 00:00:00 2001 From: jimingquan <6930445+nevermore3@users.noreply.github.com> Date: Thu, 21 Dec 2023 18:14:42 +0800 Subject: [PATCH 07/21] fix limit bug (#5787) * check vector size before erase * add test case --- src/graph/executor/algo/AllPathsExecutor.cpp | 6 +++++- tests/tck/features/path/AllPath.feature | 10 ++++++++++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/src/graph/executor/algo/AllPathsExecutor.cpp b/src/graph/executor/algo/AllPathsExecutor.cpp index aa4422e089e..22a82a31bde 100644 --- a/src/graph/executor/algo/AllPathsExecutor.cpp +++ b/src/graph/executor/algo/AllPathsExecutor.cpp @@ -277,7 +277,11 @@ folly::Future AllPathsExecutor::buildPathMultiJobs() { result_.rows.resize(limit_); } if (offset_ != 0) { - result_.rows.erase(result_.rows.begin(), result_.rows.begin() + offset_); + if (result_.rows.size() <= offset_) { + result_.rows.clear(); + } else { + result_.rows.erase(result_.rows.begin(), result_.rows.begin() + offset_); + } } addState("conjunct_path_time", conjunctPathTime); return Status::OK(); diff --git a/tests/tck/features/path/AllPath.feature b/tests/tck/features/path/AllPath.feature index cc9a8184cb2..08275deb942 100644 --- a/tests/tck/features/path/AllPath.feature +++ b/tests/tck/features/path/AllPath.feature @@ -289,6 +289,16 @@ Feature: All Path Then the result should be, in any order, with relax comparison: | count(*) | | 10 | + When executing query: + """ + lookup on player where player.age>20 YIELD id(vertex) as vid + | go 1 step from $-.vid over * where "player" in labels($$) yield distinct id($$) as dst,$-.vid as src + | find noloop path from $-.src to $-.dst over * upto 1 step yield path as p | limit 10000,10 + | yield count(*) + """ + Then the result should be, in any order, with relax comparison: + | count(*) | + | 0 | Scenario: [1] ALL PATH REVERSELY When executing query: From 5d308fc6e4f36f9f1688b579077eaf8b8a392743 Mon Sep 17 00:00:00 2001 From: jimingquan <6930445+nevermore3@users.noreply.github.com> Date: Tue, 26 Dec 2023 13:04:58 +0800 Subject: [PATCH 08/21] change collect to collectAll (#5789) * change collect to collectAll * fix compiler error --- src/graph/executor/algo/AllPathsExecutor.cpp | 52 +++++++++++++------ src/graph/executor/algo/BatchShortestPath.cpp | 49 +++++++++++------ .../executor/algo/SingleShortestPath.cpp | 47 ++++++++++++----- 3 files changed, 103 insertions(+), 45 deletions(-) diff --git a/src/graph/executor/algo/AllPathsExecutor.cpp b/src/graph/executor/algo/AllPathsExecutor.cpp index 22a82a31bde..13e7c93ee29 100644 --- a/src/graph/executor/algo/AllPathsExecutor.cpp +++ b/src/graph/executor/algo/AllPathsExecutor.cpp @@ -102,19 +102,29 @@ folly::Future AllPathsExecutor::doAllPaths() { break; } } - return folly::collect(futures).via(runner()).thenValue([this](auto&& resps) { - memory::MemoryCheckGuard guard; - for (auto& resp : resps) { - if (!resp.ok()) { - return folly::makeFuture(std::move(resp)); - } - } - if (leftSteps_ + rightSteps_ >= maxStep_ || leftNextStepVids_.empty() || - rightNextStepVids_.empty()) { - return buildResult(); - } - return doAllPaths(); - }); + return folly::collectAll(futures).via(runner()).thenValue( + [this](std::vector>&& resps) { + memory::MemoryCheckGuard guard; + for (auto& respVal : resps) { + if (respVal.hasException()) { + auto ex = respVal.exception().get_exception(); + if (ex) { + throw std::bad_alloc(); + } else { + throw std::runtime_error(respVal.exception().what().c_str()); + } + } + auto resp = std::move(respVal).value(); + if (!resp.ok()) { + return folly::makeFuture(std::move(resp)); + } + } + if (leftSteps_ + rightSteps_ >= maxStep_ || leftNextStepVids_.empty() || + rightNextStepVids_.empty()) { + return buildResult(); + } + return doAllPaths(); + }); } folly::Future AllPathsExecutor::getNeighbors(bool reverse) { @@ -545,12 +555,22 @@ folly::Future AllPathsExecutor::conjunctPath(std::vector& leftPa runner(), [this, start, end, reverse]() { return probe(start, end, reverse); })); } } - return folly::collect(futures) + return folly::collectAll(futures) .via(runner()) - .thenValue([this, path = std::move(oneWayPath)](std::vector>&& resps) { + .thenValue([this, + path = std::move(oneWayPath)](std::vector>>&& resps) { memory::MemoryCheckGuard guard; result_.rows = std::move(path); - for (auto& rows : resps) { + for (auto& respVal : resps) { + if (respVal.hasException()) { + auto ex = respVal.exception().get_exception(); + if (ex) { + throw std::bad_alloc(); + } else { + throw std::runtime_error(respVal.exception().what().c_str()); + } + } + auto rows = std::move(respVal).value(); if (rows.empty()) { continue; } diff --git a/src/graph/executor/algo/BatchShortestPath.cpp b/src/graph/executor/algo/BatchShortestPath.cpp index ad5e74baedc..846a4d56657 100644 --- a/src/graph/executor/algo/BatchShortestPath.cpp +++ b/src/graph/executor/algo/BatchShortestPath.cpp @@ -27,18 +27,28 @@ folly::Future BatchShortestPath::execute(const HashSet& startVids, resultDs_[rowNum].colNames = pathNode_->colNames(); futures.emplace_back(shortestPath(rowNum, 1)); } - return folly::collect(futures).via(runner()).thenValue([this, result](auto&& resps) { - // MemoryTrackerVerified - memory::MemoryCheckGuard guard; - for (auto& resp : resps) { - NG_RETURN_IF_ERROR(resp); - } - result->colNames = pathNode_->colNames(); - for (auto& ds : resultDs_) { - result->append(std::move(ds)); - } - return Status::OK(); - }); + return folly::collectAll(futures).via(runner()).thenValue( + [this, result](std::vector>&& resps) { + // MemoryTrackerVerified + memory::MemoryCheckGuard guard; + for (auto& respVal : resps) { + if (respVal.hasException()) { + auto ex = respVal.exception().get_exception(); + if (ex) { + throw std::bad_alloc(); + } else { + throw std::runtime_error(respVal.exception().what().c_str()); + } + } + auto resp = std::move(respVal).value(); + NG_RETURN_IF_ERROR(resp); + } + result->colNames = pathNode_->colNames(); + for (auto& ds : resultDs_) { + result->append(std::move(ds)); + } + return Status::OK(); + }); } size_t BatchShortestPath::init(const HashSet& startVids, const HashSet& endVids) { @@ -100,12 +110,21 @@ folly::Future BatchShortestPath::shortestPath(size_t rowNum, size_t step std::vector> futures; futures.emplace_back(getNeighbors(rowNum, stepNum, false)); futures.emplace_back(getNeighbors(rowNum, stepNum, true)); - return folly::collect(futures) + return folly::collectAll(futures) .via(runner()) - .thenValue([this, rowNum, stepNum](auto&& resps) { + .thenValue([this, rowNum, stepNum](std::vector>&& resps) { // MemoryTrackerVerified memory::MemoryCheckGuard guard; - for (auto& resp : resps) { + for (auto& respVal : resps) { + if (respVal.hasException()) { + auto ex = respVal.exception().get_exception(); + if (ex) { + throw std::bad_alloc(); + } else { + throw std::runtime_error(respVal.exception().what().c_str()); + } + } + auto resp = std::move(respVal).value(); if (!resp.ok()) { return folly::makeFuture(std::move(resp)); } diff --git a/src/graph/executor/algo/SingleShortestPath.cpp b/src/graph/executor/algo/SingleShortestPath.cpp index fc306815cdf..bc110acd98b 100644 --- a/src/graph/executor/algo/SingleShortestPath.cpp +++ b/src/graph/executor/algo/SingleShortestPath.cpp @@ -25,17 +25,27 @@ folly::Future SingleShortestPath::execute(const HashSet& startVids, resultDs_[rowNum].colNames = pathNode_->colNames(); futures.emplace_back(shortestPath(rowNum, 1)); } - return folly::collect(futures).via(runner()).thenValue([this, result](auto&& resps) { - memory::MemoryCheckGuard guard; - for (auto& resp : resps) { - NG_RETURN_IF_ERROR(resp); - } - result->colNames = pathNode_->colNames(); - for (auto& ds : resultDs_) { - result->append(std::move(ds)); - } - return Status::OK(); - }); + return folly::collectAll(futures).via(runner()).thenValue( + [this, result](std::vector>&& resps) { + memory::MemoryCheckGuard guard; + for (auto& respVal : resps) { + if (respVal.hasException()) { + auto ex = respVal.exception().get_exception(); + if (ex) { + throw std::bad_alloc(); + } else { + throw std::runtime_error(respVal.exception().what().c_str()); + } + } + auto resp = std::move(respVal).value(); + NG_RETURN_IF_ERROR(resp); + } + result->colNames = pathNode_->colNames(); + for (auto& ds : resultDs_) { + result->append(std::move(ds)); + } + return Status::OK(); + }); } void SingleShortestPath::init(const HashSet& startVids, const HashSet& endVids, size_t rowSize) { @@ -69,11 +79,20 @@ folly::Future SingleShortestPath::shortestPath(size_t rowNum, size_t ste futures.reserve(2); futures.emplace_back(getNeighbors(rowNum, stepNum, false)); futures.emplace_back(getNeighbors(rowNum, stepNum, true)); - return folly::collect(futures) + return folly::collectAll(futures) .via(runner()) - .thenValue([this, rowNum, stepNum](auto&& resps) { + .thenValue([this, rowNum, stepNum](std::vector>&& resps) { memory::MemoryCheckGuard guard; - for (auto& resp : resps) { + for (auto& respVal : resps) { + if (respVal.hasException()) { + auto ex = respVal.exception().get_exception(); + if (ex) { + throw std::bad_alloc(); + } else { + throw std::runtime_error(respVal.exception().what().c_str()); + } + } + auto resp = std::move(respVal).value(); if (!resp.ok()) { return folly::makeFuture(std::move(resp)); } From cba6f5fb5fe93c3f102219754a8740f518216317 Mon Sep 17 00:00:00 2001 From: "yuxuan.wang" <48981679+Salieri-004@users.noreply.github.com> Date: Fri, 29 Dec 2023 17:57:58 +0800 Subject: [PATCH 09/21] fix PrunePropertiesVisitor bug (#5793) --- src/graph/optimizer/Optimizer.cpp | 6 +++-- src/graph/visitor/PropertyTrackerVisitor.cpp | 12 ++------- src/graph/visitor/PrunePropertiesVisitor.cpp | 21 +++++++++++++++ .../bugfix/PrunePropertiesError.feature | 27 +++++++++++++++++++ 4 files changed, 54 insertions(+), 12 deletions(-) create mode 100644 tests/tck/features/bugfix/PrunePropertiesError.feature diff --git a/src/graph/optimizer/Optimizer.cpp b/src/graph/optimizer/Optimizer.cpp index 648d883a47b..938c379cf99 100644 --- a/src/graph/optimizer/Optimizer.cpp +++ b/src/graph/optimizer/Optimizer.cpp @@ -35,8 +35,10 @@ StatusOr Optimizer::findBestPlan(QueryContext *qctx) { auto optCtx = std::make_unique(qctx); auto root = qctx->plan()->root(); - auto spaceID = qctx->rctx()->session()->space().id; - + auto spaceID = nebula::graph::kInvalidSpaceID; + if (qctx->vctx()->spaceChosen()) { + spaceID = qctx->vctx()->whichSpace().id; + } NG_RETURN_IF_ERROR(checkPlanDepth(root)); auto ret = prepare(optCtx.get(), root); NG_RETURN_IF_ERROR(ret); diff --git a/src/graph/visitor/PropertyTrackerVisitor.cpp b/src/graph/visitor/PropertyTrackerVisitor.cpp index 8fd0e42513f..d5717f7a93f 100644 --- a/src/graph/visitor/PropertyTrackerVisitor.cpp +++ b/src/graph/visitor/PropertyTrackerVisitor.cpp @@ -169,16 +169,8 @@ void PropertyTrackerVisitor::visit(LabelTagPropertyExpression *expr) { auto ret = qctx_->schemaMng()->toTagID(space_, tagName); if (!ret.ok()) { - // if the we switch space in the query, we need to get the space id from the validation context - // use xxx; match xxx - if (qctx_->vctx()->spaceChosen()) { - space_ = qctx_->vctx()->whichSpace().id; - ret = qctx_->schemaMng()->toTagID(qctx_->vctx()->whichSpace().id, tagName); - if (!ret.ok()) { - status_ = std::move(ret).status(); - return; - } - } + status_ = std::move(ret).status(); + return; } auto tagId = ret.value(); diff --git a/src/graph/visitor/PrunePropertiesVisitor.cpp b/src/graph/visitor/PrunePropertiesVisitor.cpp index eb4219637a8..33d047fc89c 100644 --- a/src/graph/visitor/PrunePropertiesVisitor.cpp +++ b/src/graph/visitor/PrunePropertiesVisitor.cpp @@ -27,6 +27,9 @@ void PrunePropertiesVisitor::visit(Filter *node) { return; } visitCurrent(node); // Filter will use properties in filter expression + if (!status_.ok()) { + return; + } status_ = depsPruneProperties(node->dependencies()); } @@ -44,6 +47,9 @@ void PrunePropertiesVisitor::visit(Project *node) { return; } visitCurrent(node); // Project won't use properties in column expression + if (!status_.ok()) { + return; + } status_ = depsPruneProperties(node->dependencies()); } @@ -120,6 +126,9 @@ void PrunePropertiesVisitor::visit(Aggregate *node) { return; } visitCurrent(node); + if (!status_.ok()) { + return; + } status_ = depsPruneProperties(node->dependencies()); } @@ -170,6 +179,9 @@ void PrunePropertiesVisitor::visit(ScanEdges *node) { } rootNode_ = false; pruneCurrent(node); + if (!status_.ok()) { + return; + } status_ = depsPruneProperties(node->dependencies()); } @@ -228,6 +240,9 @@ void PrunePropertiesVisitor::visit(Traverse *node) { } rootNode_ = false; visitCurrent(node); + if (!status_.ok()) { + return; + } status_ = depsPruneProperties(node->dependencies()); } @@ -380,6 +395,9 @@ void PrunePropertiesVisitor::visit(AppendVertices *node) { return; } visitCurrent(node); + if (!status_.ok()) { + return; + } status_ = depsPruneProperties(node->dependencies()); } @@ -524,6 +542,9 @@ void PrunePropertiesVisitor::visit(Unwind *node) { return; } visitCurrent(node); + if (!status_.ok()) { + return; + } status_ = depsPruneProperties(node->dependencies()); } diff --git a/tests/tck/features/bugfix/PrunePropertiesError.feature b/tests/tck/features/bugfix/PrunePropertiesError.feature new file mode 100644 index 00000000000..b726ae39e57 --- /dev/null +++ b/tests/tck/features/bugfix/PrunePropertiesError.feature @@ -0,0 +1,27 @@ +# Copyright (c) 2023 vesoft inc. All rights reserved. +# +# This source code is licensed under Apache 2.0 License. +Feature: Test PrunePropertiesVisitor when switching space + + Scenario: Test PrunePropertiesVisitor when switching space + When executing query: + """ + USE student; + """ + Then the execution should be successful + When profiling query: + """ + USE nba; + MATCH (u:player) + RETURN count(*) + """ + Then the result should be, in any order: + | count(*) | + | 56 | + And the execution plan should be: + | id | name | dependencies | operator info | + | 6 | Aggregate | 8 | | + | 8 | AppendVertices | 2 | { "props": "[{\"props\":[\"_tag\"]}]" } | + | 2 | IndexScan | 1 | | + | 1 | RegisterSpaceToSession | 0 | | + | 0 | Start | | | From 66dfbf5ddcdbc67df290b92e2ee77dbf04e5160c Mon Sep 17 00:00:00 2001 From: jimingquan <6930445+nevermore3@users.noreply.github.com> Date: Fri, 5 Jan 2024 09:46:48 +0800 Subject: [PATCH 10/21] check max validate depth (#5790) * check max validate depth * throw error when statements is exceeds the threshold * address comment --- src/graph/validator/AssignmentValidator.cpp | 1 + src/graph/validator/SequentialValidator.cpp | 1 - src/graph/validator/Validator.cpp | 31 +++++++++++++++------ src/graph/validator/Validator.h | 1 + 4 files changed, 24 insertions(+), 10 deletions(-) diff --git a/src/graph/validator/AssignmentValidator.cpp b/src/graph/validator/AssignmentValidator.cpp index b554af92407..e8d11553d88 100644 --- a/src/graph/validator/AssignmentValidator.cpp +++ b/src/graph/validator/AssignmentValidator.cpp @@ -13,6 +13,7 @@ namespace graph { Status AssignmentValidator::validateImpl() { auto *assignSentence = static_cast(sentence_); + NG_RETURN_IF_ERROR(validator_->validate()); auto outputs = validator_->outputCols(); diff --git a/src/graph/validator/SequentialValidator.cpp b/src/graph/validator/SequentialValidator.cpp index 3f1e60ad5d2..52700709474 100644 --- a/src/graph/validator/SequentialValidator.cpp +++ b/src/graph/validator/SequentialValidator.cpp @@ -18,7 +18,6 @@ namespace graph { // Validator of sequential sentences which combine multiple sentences, e.g. GO ...; GO ...; // Call validator of sub-sentences. Status SequentialValidator::validateImpl() { - Status status; if (sentence_->kind() != Sentence::Kind::kSequential) { return Status::SemanticError( "Sequential validator validates a SequentialSentences, but %ld is " diff --git a/src/graph/validator/Validator.cpp b/src/graph/validator/Validator.cpp index b459b0a308d..437b8db942b 100644 --- a/src/graph/validator/Validator.cpp +++ b/src/graph/validator/Validator.cpp @@ -39,10 +39,14 @@ #include "graph/visitor/DeduceTypeVisitor.h" #include "graph/visitor/EvaluableExprVisitor.h" #include "parser/Sentence.h" - +DEFINE_uint32(max_statements, + 1024, + "threshold for maximun number of statements that can be validate"); namespace nebula { namespace graph { +thread_local uint32_t Validator::maxStatements_ = 0; + Validator::Validator(Sentence* sentence, QueryContext* qctx) : sentence_(DCHECK_NOTNULL(sentence)), qctx_(DCHECK_NOTNULL(qctx)), @@ -50,6 +54,10 @@ Validator::Validator(Sentence* sentence, QueryContext* qctx) // Create validator according to sentence type. std::unique_ptr Validator::makeValidator(Sentence* sentence, QueryContext* context) { + if (++maxStatements_ > FLAGS_max_statements * 2) { + throw std::runtime_error( + fmt::format("the number of statements exceeds max_statements : {}", FLAGS_max_statements)); + } auto kind = sentence->kind(); switch (kind) { case Sentence::Kind::kExplain: @@ -273,22 +281,27 @@ std::unique_ptr Validator::makeValidator(Sentence* sentence, QueryCon Status Validator::validate(Sentence* sentence, QueryContext* qctx) { DCHECK(sentence != nullptr); DCHECK(qctx != nullptr); - // Check if space chosen from session. if chosen, add it to context. auto session = qctx->rctx()->session(); if (session->space().id > kInvalidSpaceID) { auto spaceInfo = session->space(); qctx->vctx()->switchToSpace(std::move(spaceInfo)); } + try { + auto validator = makeValidator(sentence, qctx); + NG_RETURN_IF_ERROR(validator->validate()); - auto validator = makeValidator(sentence, qctx); - NG_RETURN_IF_ERROR(validator->validate()); - - auto root = validator->root(); - if (!root) { - return Status::SemanticError("Get null plan from sequential validator"); + auto root = validator->root(); + if (!root) { + return Status::SemanticError("Get null plan from sequential validator"); + } + qctx->plan()->setRoot(root); + // reset maxStatements + maxStatements_ = 0; + } catch (const std::exception& error) { + maxStatements_ = 0; + return Status::SemanticError(std::string(error.what())); } - qctx->plan()->setRoot(root); return Status::OK(); } diff --git a/src/graph/validator/Validator.h b/src/graph/validator/Validator.h index d7bbcb516de..e8542c62907 100644 --- a/src/graph/validator/Validator.h +++ b/src/graph/validator/Validator.h @@ -203,6 +203,7 @@ class Validator { std::set userDefinedVarNameList_; // vid's Type Value::Type vidType_; + static thread_local uint32_t maxStatements_; }; } // namespace graph From b53554b875a8c5a79b53a6d346059f54333fce06 Mon Sep 17 00:00:00 2001 From: Anqi Date: Fri, 5 Jan 2024 16:47:41 +0800 Subject: [PATCH 11/21] fix the error message for verifyVersion (#5797) --- src/graph/service/GraphFlags.cpp | 2 +- src/graph/service/GraphService.cpp | 6 ++---- src/graph/service/test/StandAloneTestGraphFlags.cpp | 2 +- .../processors/admin/VerifyClientVersionProcessor.cpp | 8 +++----- 4 files changed, 7 insertions(+), 11 deletions(-) diff --git a/src/graph/service/GraphFlags.cpp b/src/graph/service/GraphFlags.cpp index 96f035f09c5..534c61cab34 100644 --- a/src/graph/service/GraphFlags.cpp +++ b/src/graph/service/GraphFlags.cpp @@ -65,7 +65,7 @@ DEFINE_uint32(ft_request_retry_times, 3, "Retry times if fulltext request failed DEFINE_bool(enable_client_white_list, true, "Turn on/off the client white list."); DEFINE_string(client_white_list, nebula::getOriginVersion() + ":3.0.0", - "A white list for different client versions, separate with colon."); + "A white list for different client handshakeKey, separate with colon."); #endif diff --git a/src/graph/service/GraphService.cpp b/src/graph/service/GraphService.cpp index 76fd70fee3d..72fb94045bb 100644 --- a/src/graph/service/GraphService.cpp +++ b/src/graph/service/GraphService.cpp @@ -263,10 +263,8 @@ folly::Future GraphService::future_verifyClientVe uniqueWhiteList.append(version); }); resp.error_code_ref() = nebula::cpp2::ErrorCode::E_CLIENT_SERVER_INCOMPATIBLE; - resp.error_msg_ref() = folly::stringPrintf( - "Graph client version(%s) is not accepted, current graph client white list: %s.", - req.get_version().c_str(), - uniqueWhiteList.c_str()); + resp.error_msg_ref() = folly::stringPrintf("Graph client handshakeKey(%s) is not accepted.", + req.get_version().c_str()); } else { resp.error_code_ref() = nebula::cpp2::ErrorCode::SUCCEEDED; } diff --git a/src/graph/service/test/StandAloneTestGraphFlags.cpp b/src/graph/service/test/StandAloneTestGraphFlags.cpp index f53f1b44453..dd8a16e1621 100644 --- a/src/graph/service/test/StandAloneTestGraphFlags.cpp +++ b/src/graph/service/test/StandAloneTestGraphFlags.cpp @@ -10,4 +10,4 @@ DEFINE_uint32(ft_request_retry_times, 3, "Retry times if fulltext request failed DEFINE_bool(enable_client_white_list, true, "Turn on/off the client white list."); DEFINE_string(client_white_list, nebula::getOriginVersion() + ":3.0.0", - "A white list for different client versions, separate with colon."); + "A white list for different client handshakeKey, separate with colon."); diff --git a/src/meta/processors/admin/VerifyClientVersionProcessor.cpp b/src/meta/processors/admin/VerifyClientVersionProcessor.cpp index b95f2f2f648..421f0056a4f 100644 --- a/src/meta/processors/admin/VerifyClientVersionProcessor.cpp +++ b/src/meta/processors/admin/VerifyClientVersionProcessor.cpp @@ -10,7 +10,7 @@ DEFINE_bool(enable_client_white_list, true, "Turn on/off the client white list."); DEFINE_string(client_white_list, nebula::getOriginVersion() + ":3.0.0", - "A white list for different client versions, separate with colon."); + "A white list for different client handshakeKey, separate with colon."); namespace nebula { namespace meta { @@ -21,10 +21,8 @@ void VerifyClientVersionProcessor::process(const cpp2::VerifyClientVersionReq& r if (FLAGS_enable_client_white_list && whiteList.find(req.get_client_version()) == whiteList.end()) { resp_.code_ref() = nebula::cpp2::ErrorCode::E_CLIENT_SERVER_INCOMPATIBLE; - resp_.error_msg_ref() = folly::stringPrintf( - "Meta client version(%s) is not accepted, current meta client white list: %s.", - req.get_client_version().c_str(), - FLAGS_client_white_list.c_str()); + resp_.error_msg_ref() = folly::stringPrintf("Meta client handshakeKey(%s) is not accepted.", + req.get_client_version().c_str()); } onFinished(); From be4f1991001539573707865ddfcdbd839b2dea13 Mon Sep 17 00:00:00 2001 From: jimingquan <6930445+nevermore3@users.noreply.github.com> Date: Thu, 11 Jan 2024 10:13:31 +0800 Subject: [PATCH 12/21] add GFlag handshakeKey for graph & storage (#5801) * add GFlag handshakeKey for graph & storage * fix test error * address comment --- src/clients/meta/MetaClient.cpp | 12 ++++++++---- src/clients/meta/MetaClient.h | 6 ++++-- src/graph/service/GraphFlags.cpp | 4 ++++ src/graph/service/GraphFlags.h | 1 + src/graph/service/GraphService.cpp | 2 +- src/meta/test/MetaClientTest.cpp | 8 ++++---- src/storage/StorageFlags.cpp | 5 +++++ src/storage/StorageFlags.h | 2 ++ src/storage/StorageServer.cpp | 2 +- src/tools/db-dump/DbDumper.cpp | 2 +- src/tools/db-upgrade/DbUpgraderTool.cpp | 2 +- 11 files changed, 32 insertions(+), 14 deletions(-) diff --git a/src/clients/meta/MetaClient.cpp b/src/clients/meta/MetaClient.cpp index df4e3dc91f4..72f5e6b4aa9 100644 --- a/src/clients/meta/MetaClient.cpp +++ b/src/clients/meta/MetaClient.cpp @@ -125,7 +125,9 @@ bool MetaClient::isMetadReady() { return ready_; } -bool MetaClient::waitForMetadReady(int count, int retryIntervalSecs) { +bool MetaClient::waitForMetadReady(const std::string& handshakeKey, + int count, + int retryIntervalSecs) { if (!options_.skipConfig_) { std::string gflagsJsonPath; GflagsManager::getGflagsModule(gflagsModule_); @@ -145,7 +147,7 @@ bool MetaClient::waitForMetadReady(int count, int retryIntervalSecs) { } // Verify the graph server version - auto status = verifyVersion(); + auto status = verifyVersion(handshakeKey); if (!status.ok()) { LOG(ERROR) << status; return false; @@ -3845,10 +3847,12 @@ bool MetaClient::checkIsPlanKilled(SessionID sessionId, ExecutionPlanID planId) return metadata_.load()->killedPlans_.count({sessionId, planId}); } -Status MetaClient::verifyVersion() { +Status MetaClient::verifyVersion(const std::string& handshakeKey) { memory::MemoryCheckOffGuard g; auto req = cpp2::VerifyClientVersionReq(); - req.build_version_ref() = getOriginVersion(); + if (!handshakeKey.empty()) { + req.build_version_ref() = handshakeKey; + } req.host_ref() = options_.localHost_; folly::Promise> promise; auto future = promise.getFuture(); diff --git a/src/clients/meta/MetaClient.h b/src/clients/meta/MetaClient.h index 471804df3a8..b443c3105e1 100644 --- a/src/clients/meta/MetaClient.h +++ b/src/clients/meta/MetaClient.h @@ -248,7 +248,9 @@ class MetaClient : public BaseMetaClient { bool isMetadReady(); - bool waitForMetadReady(int count = -1, int retryIntervalSecs = FLAGS_heartbeat_interval_secs); + bool waitForMetadReady(const std::string& handshakeKey = "", + int count = -1, + int retryIntervalSecs = FLAGS_heartbeat_interval_secs); void notifyStop(); @@ -752,7 +754,7 @@ class MetaClient : public BaseMetaClient { // Checks if the client version is compatible with the server version by checking the // whitelist in meta. - Status verifyVersion(); + Status verifyVersion(const std::string& handshakeKey); // Save the version of the graph service into meta so that it could be looked up. // This method should be only called in the internal client. diff --git a/src/graph/service/GraphFlags.cpp b/src/graph/service/GraphFlags.cpp index 534c61cab34..0f79a4ae1a5 100644 --- a/src/graph/service/GraphFlags.cpp +++ b/src/graph/service/GraphFlags.cpp @@ -63,6 +63,10 @@ DEFINE_bool(enable_optimizer, false, "Whether to enable optimizer"); #ifndef BUILD_STANDALONE DEFINE_uint32(ft_request_retry_times, 3, "Retry times if fulltext request failed"); DEFINE_bool(enable_client_white_list, true, "Turn on/off the client white list."); +DEFINE_string( + handshakeKey, + "", + "set handshakeKey for graph, please make the handshakeKey is in meta's client_white_list"); DEFINE_string(client_white_list, nebula::getOriginVersion() + ":3.0.0", "A white list for different client handshakeKey, separate with colon."); diff --git a/src/graph/service/GraphFlags.h b/src/graph/service/GraphFlags.h index 28a361171d4..b80dec7ac0f 100644 --- a/src/graph/service/GraphFlags.h +++ b/src/graph/service/GraphFlags.h @@ -61,6 +61,7 @@ DECLARE_bool(enable_experimental_feature); DECLARE_bool(enable_data_balance); DECLARE_bool(enable_client_white_list); +DECLARE_string(handshakeKey); DECLARE_string(client_white_list); DECLARE_int32(num_rows_to_check_memory); diff --git a/src/graph/service/GraphService.cpp b/src/graph/service/GraphService.cpp index 72fb94045bb..b28d53b5a0f 100644 --- a/src/graph/service/GraphService.cpp +++ b/src/graph/service/GraphService.cpp @@ -43,7 +43,7 @@ Status GraphService::init(std::shared_ptr ioExecuto metaClient_ = std::make_unique(ioExecutor, std::move(addrs.value()), options); // Load data try 3 time - bool loadDataOk = metaClient_->waitForMetadReady(3); + bool loadDataOk = metaClient_->waitForMetadReady(FLAGS_handshakeKey, 3); if (!loadDataOk) { // Resort to retrying in the background LOG(ERROR) << "Failed to wait for meta service ready synchronously."; diff --git a/src/meta/test/MetaClientTest.cpp b/src/meta/test/MetaClientTest.cpp index d8cf7fc606a..0f1d0164658 100644 --- a/src/meta/test/MetaClientTest.cpp +++ b/src/meta/test/MetaClientTest.cpp @@ -1712,23 +1712,23 @@ TEST(MetaClientTest, VerifyClientTest) { FLAGS_enable_client_white_list = true; { FLAGS_client_white_list = nebula::cpp2::common_constants::version(); - auto status = client->verifyVersion(); + auto status = client->verifyVersion(""); EXPECT_TRUE(status.ok()); } { FLAGS_client_white_list = ""; - auto status = client->verifyVersion(); + auto status = client->verifyVersion(""); EXPECT_FALSE(status.ok()); } { FLAGS_client_white_list = "1.0.0:1.2.0:"; - auto status = client->verifyVersion(); + auto status = client->verifyVersion(""); EXPECT_FALSE(status.ok()); } { FLAGS_enable_client_white_list = false; FLAGS_client_white_list = "1.0.0:1.2.0:"; - auto status = client->verifyVersion(); + auto status = client->verifyVersion(""); EXPECT_TRUE(status.ok()); } FLAGS_enable_client_white_list = false; diff --git a/src/storage/StorageFlags.cpp b/src/storage/StorageFlags.cpp index bd100191c9f..220fe313e87 100644 --- a/src/storage/StorageFlags.cpp +++ b/src/storage/StorageFlags.cpp @@ -5,6 +5,11 @@ #include "storage/StorageFlags.h" +DEFINE_string( + handshakeKey, + "", + "set handshakeKey for storage, please make the handshakeKey is in meta's client_white_list"); + DEFINE_string(store_type, "nebula", "Which type of KVStore to be used by the storage daemon." diff --git a/src/storage/StorageFlags.h b/src/storage/StorageFlags.h index 197f9318c5c..01197ab5874 100644 --- a/src/storage/StorageFlags.h +++ b/src/storage/StorageFlags.h @@ -8,6 +8,8 @@ #include "common/base/Base.h" +DECLARE_string(handshakeKey); + DECLARE_string(store_type); DECLARE_int32(waiting_catch_up_retry_times); diff --git a/src/storage/StorageServer.cpp b/src/storage/StorageServer.cpp index 228bf7ef284..45fb5a129ff 100644 --- a/src/storage/StorageServer.cpp +++ b/src/storage/StorageServer.cpp @@ -233,7 +233,7 @@ bool StorageServer::start() { } #endif - if (!metaClient_->waitForMetadReady()) { + if (!metaClient_->waitForMetadReady(FLAGS_handshakeKey)) { LOG(ERROR) << "waitForMetadReady error!"; return false; } diff --git a/src/tools/db-dump/DbDumper.cpp b/src/tools/db-dump/DbDumper.cpp index e7341cf1b44..eb8d496f419 100644 --- a/src/tools/db-dump/DbDumper.cpp +++ b/src/tools/db-dump/DbDumper.cpp @@ -56,7 +56,7 @@ Status DbDumper::initMeta() { meta::MetaClientOptions options; options.skipConfig_ = true; metaClient_ = std::make_unique(ioExecutor, std::move(addrs.value()), options); - if (!metaClient_->waitForMetadReady(1)) { + if (!metaClient_->waitForMetadReady("", 1)) { return Status::Error("Meta is not ready: '%s'.", FLAGS_meta_server.c_str()); } schemaMng_ = std::make_unique(); diff --git a/src/tools/db-upgrade/DbUpgraderTool.cpp b/src/tools/db-upgrade/DbUpgraderTool.cpp index b4e05cd143b..dc4444922bf 100644 --- a/src/tools/db-upgrade/DbUpgraderTool.cpp +++ b/src/tools/db-upgrade/DbUpgraderTool.cpp @@ -153,7 +153,7 @@ int main(int argc, char* argv[]) { auto metaClient = std::make_unique(ioExecutor, std::move(addrs.value()), options); CHECK_NOTNULL(metaClient); - if (!metaClient->waitForMetadReady(1)) { + if (!metaClient->waitForMetadReady("", 1)) { LOG(ERROR) << "Meta is not ready: " << FLAGS_upgrade_meta_server; return EXIT_FAILURE; } From 44a7d2ea1ef2af20c7091d13ef1f53e1e96fefd1 Mon Sep 17 00:00:00 2001 From: jimingquan <6930445+nevermore3@users.noreply.github.com> Date: Thu, 11 Jan 2024 11:14:36 +0800 Subject: [PATCH 13/21] fix max_statements (#5802) * fix max_statements * Update SequentialValidator.cpp --- src/graph/service/GraphFlags.cpp | 3 +++ src/graph/service/GraphFlags.h | 1 + src/graph/validator/SequentialValidator.cpp | 3 +++ src/graph/validator/Validator.cpp | 3 --- 4 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/graph/service/GraphFlags.cpp b/src/graph/service/GraphFlags.cpp index 0f79a4ae1a5..4c52788d1d9 100644 --- a/src/graph/service/GraphFlags.cpp +++ b/src/graph/service/GraphFlags.cpp @@ -54,6 +54,9 @@ DEFINE_string(cloud_http_url, "", "cloud http url including ip, port, url path") DEFINE_uint32(max_allowed_statements, 512, "Max allowed sequential statements"); DEFINE_uint32(max_allowed_query_size, 4194304, "Max allowed sequential query size"); +DEFINE_uint32(max_statements, + 1024, + "threshold for maximun number of statements that can be validate"); DEFINE_int64(max_allowed_connections, std::numeric_limits::max(), "Max connections of the whole cluster"); diff --git a/src/graph/service/GraphFlags.h b/src/graph/service/GraphFlags.h index b80dec7ac0f..24df125c6c5 100644 --- a/src/graph/service/GraphFlags.h +++ b/src/graph/service/GraphFlags.h @@ -42,6 +42,7 @@ DECLARE_string(cloud_http_url); DECLARE_uint32(max_allowed_statements); DECLARE_int32(max_sessions_per_ip_per_user); +DECLARE_uint32(max_statements); // Failed login attempt // value of failed_login_attempts is in the range from 0 to 32767. // The deault value is 0. A value of 0 disables the option. diff --git a/src/graph/validator/SequentialValidator.cpp b/src/graph/validator/SequentialValidator.cpp index 52700709474..06359959bbf 100644 --- a/src/graph/validator/SequentialValidator.cpp +++ b/src/graph/validator/SequentialValidator.cpp @@ -27,6 +27,9 @@ Status SequentialValidator::validateImpl() { auto seqSentence = static_cast(sentence_); auto sentences = seqSentence->sentences(); + if (sentences.size() > static_cast(FLAGS_max_statements)) { + return Status::SemanticError("The maximum number of statements has been exceeded"); + } if (sentences.size() > static_cast(FLAGS_max_allowed_statements)) { return Status::SemanticError("The maximum number of statements allowed has been exceeded"); } diff --git a/src/graph/validator/Validator.cpp b/src/graph/validator/Validator.cpp index 437b8db942b..3ba99753cf2 100644 --- a/src/graph/validator/Validator.cpp +++ b/src/graph/validator/Validator.cpp @@ -39,9 +39,6 @@ #include "graph/visitor/DeduceTypeVisitor.h" #include "graph/visitor/EvaluableExprVisitor.h" #include "parser/Sentence.h" -DEFINE_uint32(max_statements, - 1024, - "threshold for maximun number of statements that can be validate"); namespace nebula { namespace graph { From 228a308d670a4fd4aa0eddb882a97ff331ce648e Mon Sep 17 00:00:00 2001 From: jimingquan <6930445+nevermore3@users.noreply.github.com> Date: Thu, 11 Jan 2024 15:51:45 +0800 Subject: [PATCH 14/21] Revert "add GFlag handshakeKey for graph & storage" (#5803) Revert "add GFlag handshakeKey for graph & storage (#5801)" This reverts commit be4f1991001539573707865ddfcdbd839b2dea13. --- src/clients/meta/MetaClient.cpp | 12 ++++-------- src/clients/meta/MetaClient.h | 6 ++---- src/graph/service/GraphFlags.cpp | 4 ---- src/graph/service/GraphFlags.h | 1 - src/graph/service/GraphService.cpp | 2 +- src/meta/test/MetaClientTest.cpp | 8 ++++---- src/storage/StorageFlags.cpp | 5 ----- src/storage/StorageFlags.h | 2 -- src/storage/StorageServer.cpp | 2 +- src/tools/db-dump/DbDumper.cpp | 2 +- src/tools/db-upgrade/DbUpgraderTool.cpp | 2 +- 11 files changed, 14 insertions(+), 32 deletions(-) diff --git a/src/clients/meta/MetaClient.cpp b/src/clients/meta/MetaClient.cpp index 72f5e6b4aa9..df4e3dc91f4 100644 --- a/src/clients/meta/MetaClient.cpp +++ b/src/clients/meta/MetaClient.cpp @@ -125,9 +125,7 @@ bool MetaClient::isMetadReady() { return ready_; } -bool MetaClient::waitForMetadReady(const std::string& handshakeKey, - int count, - int retryIntervalSecs) { +bool MetaClient::waitForMetadReady(int count, int retryIntervalSecs) { if (!options_.skipConfig_) { std::string gflagsJsonPath; GflagsManager::getGflagsModule(gflagsModule_); @@ -147,7 +145,7 @@ bool MetaClient::waitForMetadReady(const std::string& handshakeKey, } // Verify the graph server version - auto status = verifyVersion(handshakeKey); + auto status = verifyVersion(); if (!status.ok()) { LOG(ERROR) << status; return false; @@ -3847,12 +3845,10 @@ bool MetaClient::checkIsPlanKilled(SessionID sessionId, ExecutionPlanID planId) return metadata_.load()->killedPlans_.count({sessionId, planId}); } -Status MetaClient::verifyVersion(const std::string& handshakeKey) { +Status MetaClient::verifyVersion() { memory::MemoryCheckOffGuard g; auto req = cpp2::VerifyClientVersionReq(); - if (!handshakeKey.empty()) { - req.build_version_ref() = handshakeKey; - } + req.build_version_ref() = getOriginVersion(); req.host_ref() = options_.localHost_; folly::Promise> promise; auto future = promise.getFuture(); diff --git a/src/clients/meta/MetaClient.h b/src/clients/meta/MetaClient.h index b443c3105e1..471804df3a8 100644 --- a/src/clients/meta/MetaClient.h +++ b/src/clients/meta/MetaClient.h @@ -248,9 +248,7 @@ class MetaClient : public BaseMetaClient { bool isMetadReady(); - bool waitForMetadReady(const std::string& handshakeKey = "", - int count = -1, - int retryIntervalSecs = FLAGS_heartbeat_interval_secs); + bool waitForMetadReady(int count = -1, int retryIntervalSecs = FLAGS_heartbeat_interval_secs); void notifyStop(); @@ -754,7 +752,7 @@ class MetaClient : public BaseMetaClient { // Checks if the client version is compatible with the server version by checking the // whitelist in meta. - Status verifyVersion(const std::string& handshakeKey); + Status verifyVersion(); // Save the version of the graph service into meta so that it could be looked up. // This method should be only called in the internal client. diff --git a/src/graph/service/GraphFlags.cpp b/src/graph/service/GraphFlags.cpp index 4c52788d1d9..662d7a53246 100644 --- a/src/graph/service/GraphFlags.cpp +++ b/src/graph/service/GraphFlags.cpp @@ -66,10 +66,6 @@ DEFINE_bool(enable_optimizer, false, "Whether to enable optimizer"); #ifndef BUILD_STANDALONE DEFINE_uint32(ft_request_retry_times, 3, "Retry times if fulltext request failed"); DEFINE_bool(enable_client_white_list, true, "Turn on/off the client white list."); -DEFINE_string( - handshakeKey, - "", - "set handshakeKey for graph, please make the handshakeKey is in meta's client_white_list"); DEFINE_string(client_white_list, nebula::getOriginVersion() + ":3.0.0", "A white list for different client handshakeKey, separate with colon."); diff --git a/src/graph/service/GraphFlags.h b/src/graph/service/GraphFlags.h index 24df125c6c5..8713911316c 100644 --- a/src/graph/service/GraphFlags.h +++ b/src/graph/service/GraphFlags.h @@ -62,7 +62,6 @@ DECLARE_bool(enable_experimental_feature); DECLARE_bool(enable_data_balance); DECLARE_bool(enable_client_white_list); -DECLARE_string(handshakeKey); DECLARE_string(client_white_list); DECLARE_int32(num_rows_to_check_memory); diff --git a/src/graph/service/GraphService.cpp b/src/graph/service/GraphService.cpp index b28d53b5a0f..72fb94045bb 100644 --- a/src/graph/service/GraphService.cpp +++ b/src/graph/service/GraphService.cpp @@ -43,7 +43,7 @@ Status GraphService::init(std::shared_ptr ioExecuto metaClient_ = std::make_unique(ioExecutor, std::move(addrs.value()), options); // Load data try 3 time - bool loadDataOk = metaClient_->waitForMetadReady(FLAGS_handshakeKey, 3); + bool loadDataOk = metaClient_->waitForMetadReady(3); if (!loadDataOk) { // Resort to retrying in the background LOG(ERROR) << "Failed to wait for meta service ready synchronously."; diff --git a/src/meta/test/MetaClientTest.cpp b/src/meta/test/MetaClientTest.cpp index 0f1d0164658..d8cf7fc606a 100644 --- a/src/meta/test/MetaClientTest.cpp +++ b/src/meta/test/MetaClientTest.cpp @@ -1712,23 +1712,23 @@ TEST(MetaClientTest, VerifyClientTest) { FLAGS_enable_client_white_list = true; { FLAGS_client_white_list = nebula::cpp2::common_constants::version(); - auto status = client->verifyVersion(""); + auto status = client->verifyVersion(); EXPECT_TRUE(status.ok()); } { FLAGS_client_white_list = ""; - auto status = client->verifyVersion(""); + auto status = client->verifyVersion(); EXPECT_FALSE(status.ok()); } { FLAGS_client_white_list = "1.0.0:1.2.0:"; - auto status = client->verifyVersion(""); + auto status = client->verifyVersion(); EXPECT_FALSE(status.ok()); } { FLAGS_enable_client_white_list = false; FLAGS_client_white_list = "1.0.0:1.2.0:"; - auto status = client->verifyVersion(""); + auto status = client->verifyVersion(); EXPECT_TRUE(status.ok()); } FLAGS_enable_client_white_list = false; diff --git a/src/storage/StorageFlags.cpp b/src/storage/StorageFlags.cpp index 220fe313e87..bd100191c9f 100644 --- a/src/storage/StorageFlags.cpp +++ b/src/storage/StorageFlags.cpp @@ -5,11 +5,6 @@ #include "storage/StorageFlags.h" -DEFINE_string( - handshakeKey, - "", - "set handshakeKey for storage, please make the handshakeKey is in meta's client_white_list"); - DEFINE_string(store_type, "nebula", "Which type of KVStore to be used by the storage daemon." diff --git a/src/storage/StorageFlags.h b/src/storage/StorageFlags.h index 01197ab5874..197f9318c5c 100644 --- a/src/storage/StorageFlags.h +++ b/src/storage/StorageFlags.h @@ -8,8 +8,6 @@ #include "common/base/Base.h" -DECLARE_string(handshakeKey); - DECLARE_string(store_type); DECLARE_int32(waiting_catch_up_retry_times); diff --git a/src/storage/StorageServer.cpp b/src/storage/StorageServer.cpp index 45fb5a129ff..228bf7ef284 100644 --- a/src/storage/StorageServer.cpp +++ b/src/storage/StorageServer.cpp @@ -233,7 +233,7 @@ bool StorageServer::start() { } #endif - if (!metaClient_->waitForMetadReady(FLAGS_handshakeKey)) { + if (!metaClient_->waitForMetadReady()) { LOG(ERROR) << "waitForMetadReady error!"; return false; } diff --git a/src/tools/db-dump/DbDumper.cpp b/src/tools/db-dump/DbDumper.cpp index eb8d496f419..e7341cf1b44 100644 --- a/src/tools/db-dump/DbDumper.cpp +++ b/src/tools/db-dump/DbDumper.cpp @@ -56,7 +56,7 @@ Status DbDumper::initMeta() { meta::MetaClientOptions options; options.skipConfig_ = true; metaClient_ = std::make_unique(ioExecutor, std::move(addrs.value()), options); - if (!metaClient_->waitForMetadReady("", 1)) { + if (!metaClient_->waitForMetadReady(1)) { return Status::Error("Meta is not ready: '%s'.", FLAGS_meta_server.c_str()); } schemaMng_ = std::make_unique(); diff --git a/src/tools/db-upgrade/DbUpgraderTool.cpp b/src/tools/db-upgrade/DbUpgraderTool.cpp index dc4444922bf..b4e05cd143b 100644 --- a/src/tools/db-upgrade/DbUpgraderTool.cpp +++ b/src/tools/db-upgrade/DbUpgraderTool.cpp @@ -153,7 +153,7 @@ int main(int argc, char* argv[]) { auto metaClient = std::make_unique(ioExecutor, std::move(addrs.value()), options); CHECK_NOTNULL(metaClient); - if (!metaClient->waitForMetadReady("", 1)) { + if (!metaClient->waitForMetadReady(1)) { LOG(ERROR) << "Meta is not ready: " << FLAGS_upgrade_meta_server; return EXIT_FAILURE; } From 5e9d93445b3fa032d97b839be771af7aa445159c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BF=92=E4=BC=91=E6=96=AF=7ETheseus?= Date: Thu, 18 Jan 2024 09:53:34 +0800 Subject: [PATCH 15/21] fix:a single node self-loop when executing NOLOOP (#5805) * Fix a single node self-loop when executing NOLOOP * Added test cases for noloop * Update NoLoop.feature * update code fmt * delete unused code * update test case --- src/graph/executor/algo/AllPathsExecutor.cpp | 5 ++ tests/tck/features/path/NoLoop.feature | 57 ++++++++++++++++++++ 2 files changed, 62 insertions(+) diff --git a/src/graph/executor/algo/AllPathsExecutor.cpp b/src/graph/executor/algo/AllPathsExecutor.cpp index 13e7c93ee29..351719a306d 100644 --- a/src/graph/executor/algo/AllPathsExecutor.cpp +++ b/src/graph/executor/algo/AllPathsExecutor.cpp @@ -331,6 +331,11 @@ folly::Future> AllPathsExecutor::doBuildPa continue; } for (auto& edge : adjEdges) { + if (noLoop_) { + if (edge.getEdge().dst == edge.getEdge().src) { + continue; + } + } threadLocalPtr_->emplace_back(NPath(src, edge)); newPathsPtr->emplace_back(&threadLocalPtr_->back()); } diff --git a/tests/tck/features/path/NoLoop.feature b/tests/tck/features/path/NoLoop.feature index cba4baeafbe..462f4a2eb0d 100644 --- a/tests/tck/features/path/NoLoop.feature +++ b/tests/tck/features/path/NoLoop.feature @@ -242,3 +242,60 @@ Feature: NoLoop Path | [[:like "Tony Parker"->"Tim Duncan" @0 {}]] | | [[:like "LaMarcus Aldridge"->"Tim Duncan" @0 {}], [:like "Tony Parker"->"LaMarcus Aldridge" @0 {}]] | | [[:like "Manu Ginobili"->"Tim Duncan" @0 {}], [:like "Tony Parker"->"Manu Ginobili" @0 {}]] | + + Scenario: Query with NO LOOP on a node without self-loop + When executing query: + """ + CREATE SPACE TestNoLoopSpace(vid_type=fixed_string(20)); + """ + And wait 3 seconds + Then the execution should be successful + When executing query: + """ + USE TestNoLoopSpace; + """ + And wait 3 seconds + Then the execution should be successful + When executing query: + """ + CREATE TAG Person(name string); + """ + And wait 1 seconds + Then the execution should be successful + When executing query: + """ + CREATE EDGE Link(); + """ + And wait 1 seconds + Then the execution should be successful + When executing query: + """ + INSERT VERTEX Person(name) VALUES "nodea":("Node A"); + """ + And wait 1 seconds + Then the execution should be successful + When executing query: + """ + INSERT EDGE Link() VALUES "nodea" -> "nodea":(); + """ + And wait 1 seconds + Then the execution should be successful + When executing query: + """ + FIND NOLOOP PATH FROM "nodea" TO "nodea" OVER Link YIELD PATH AS p; + """ + Then the result should be, in any order: + | p | + When executing query: + """ + FIND ALL PATH FROM "nodea" TO "nodea" OVER Link YIELD PATH AS p; + """ + Then the result should be, in any order: + | p | + | <("nodea")<-[:Link@0 {}]-("nodea")> | + When executing query: + """ + DROP SPACE TestNoLoopSpace + """ + And wait 1 seconds + Then the execution should be successful From fc3417053045c1ad002f598b792729b0960a7849 Mon Sep 17 00:00:00 2001 From: dinosaur Date: Thu, 1 Feb 2024 18:40:55 +0800 Subject: [PATCH 16/21] fix-MemoryTracker master (#5808) --- src/common/memory/MemoryTracker.h | 3 ++- tests/tck/features/path/NoLoop.feature | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/common/memory/MemoryTracker.h b/src/common/memory/MemoryTracker.h index a1c4a646c6a..120b115b807 100644 --- a/src/common/memory/MemoryTracker.h +++ b/src/common/memory/MemoryTracker.h @@ -5,6 +5,7 @@ #pragma once #include +#include #include "common/base/Base.h" @@ -29,7 +30,7 @@ static std::string ReadableSize(double size) { constexpr size_t #if defined(__cpp_lib_hardware_interference_size) - CACHE_LINE_SIZE = hardware_destructive_interference_size; + CACHE_LINE_SIZE = std::hardware_destructive_interference_size; #else CACHE_LINE_SIZE = 64; #endif diff --git a/tests/tck/features/path/NoLoop.feature b/tests/tck/features/path/NoLoop.feature index 462f4a2eb0d..67e25890209 100644 --- a/tests/tck/features/path/NoLoop.feature +++ b/tests/tck/features/path/NoLoop.feature @@ -243,6 +243,7 @@ Feature: NoLoop Path | [[:like "LaMarcus Aldridge"->"Tim Duncan" @0 {}], [:like "Tony Parker"->"LaMarcus Aldridge" @0 {}]] | | [[:like "Manu Ginobili"->"Tim Duncan" @0 {}], [:like "Tony Parker"->"Manu Ginobili" @0 {}]] | + @skip Scenario: Query with NO LOOP on a node without self-loop When executing query: """ From c4713882c232d1ba1538e75a8826c9f9679897ff Mon Sep 17 00:00:00 2001 From: "yuxuan.wang" <48981679+Salieri-004@users.noreply.github.com> Date: Fri, 2 Feb 2024 10:43:30 +0800 Subject: [PATCH 17/21] fix compare node (#5816) * fix compare node * remove @skip mark --- tests/common/comparator.py | 9 ++++----- tests/tck/features/path/NoLoop.feature | 7 +------ 2 files changed, 5 insertions(+), 11 deletions(-) diff --git a/tests/common/comparator.py b/tests/common/comparator.py index d496a38dcfa..ae884fd4858 100644 --- a/tests/common/comparator.py +++ b/tests/common/comparator.py @@ -295,21 +295,20 @@ def compare_vid(self, lid: Value, rid: Value) -> bool: return False def compare_node(self, lhs: Vertex, rhs: Vertex): - rtags = [] + rtags = [] if rhs.tags is None else rhs.tags if self._strict: assert rhs.vid is not None if not self.compare_vid(lhs.vid, rhs.vid): return False - if rhs.tags is None or len(lhs.tags) != len(rhs.tags): + if len(lhs.tags) != len(rtags): return False - rtags = rhs.tags else: if rhs.vid is not None: if not self.compare_vid(lhs.vid, rhs.vid): return False - if rhs.tags is not None and len(lhs.tags) < len(rhs.tags): + if len(lhs.tags) < len(rtags): return False - rtags = [] if rhs.tags is None else rhs.tags + for tag in rtags: ltag = [ [lt.name, lt.props] for lt in lhs.tags if self.bstr(tag.name) == lt.name diff --git a/tests/tck/features/path/NoLoop.feature b/tests/tck/features/path/NoLoop.feature index 67e25890209..26c8d2ba229 100644 --- a/tests/tck/features/path/NoLoop.feature +++ b/tests/tck/features/path/NoLoop.feature @@ -243,7 +243,6 @@ Feature: NoLoop Path | [[:like "LaMarcus Aldridge"->"Tim Duncan" @0 {}], [:like "Tony Parker"->"LaMarcus Aldridge" @0 {}]] | | [[:like "Manu Ginobili"->"Tim Duncan" @0 {}], [:like "Tony Parker"->"Manu Ginobili" @0 {}]] | - @skip Scenario: Query with NO LOOP on a node without self-loop When executing query: """ @@ -261,25 +260,22 @@ Feature: NoLoop Path """ CREATE TAG Person(name string); """ - And wait 1 seconds Then the execution should be successful When executing query: """ CREATE EDGE Link(); """ - And wait 1 seconds Then the execution should be successful + And wait 6 seconds When executing query: """ INSERT VERTEX Person(name) VALUES "nodea":("Node A"); """ - And wait 1 seconds Then the execution should be successful When executing query: """ INSERT EDGE Link() VALUES "nodea" -> "nodea":(); """ - And wait 1 seconds Then the execution should be successful When executing query: """ @@ -298,5 +294,4 @@ Feature: NoLoop Path """ DROP SPACE TestNoLoopSpace """ - And wait 1 seconds Then the execution should be successful From f7036b96ec63506f04ff49b25feca286b401ae2f Mon Sep 17 00:00:00 2001 From: Wey Gu Date: Fri, 1 Mar 2024 11:56:17 +0800 Subject: [PATCH 18/21] chore: fix broken image and lift docs URLs (#5824) --- README.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 0024a99f4ae..70cc1e8103d 100644 --- a/README.md +++ b/README.md @@ -69,7 +69,7 @@ See our [Roadmap](https://github.com/vesoft-inc/nebula/wiki/Nebula-Graph-Roadmap ## Quick start -Read the [getting started](https://docs.nebula-graph.io/3.2.0/2.quick-start/1.quick-start-workflow/) article for a quick start. +Read the [getting started](https://docs.nebula-graph.io/3.6.0/2.quick-start/1.quick-start-workflow/) docs for a quick start. ## Using NebulaGraph @@ -82,13 +82,13 @@ NebulaGraph is a distributed graph database with multiple components. You can [d ## Getting help In case you encounter any problems playing around **NebulaGraph**, please reach out for help: -* [FAQ](https://docs.nebula-graph.io/3.3.0/20.appendix/0.FAQ/) +* [FAQ](https://docs.nebula-graph.io/3.6.0/20.appendix/0.FAQ/) * [Discussions](https://github.com/vesoft-inc/nebula/discussions) * [Documentation](https://docs.nebula-graph.io/) ## DevTools -NebulaGraph comes with a set of tools to help you manage and monitor your graph database. See [Ecosystem](https://docs.nebula-graph.io/3.3.0/20.appendix/6.eco-tool-version/). +NebulaGraph comes with a set of tools to help you manage and monitor your graph database. See [Ecosystem](https://docs.nebula-graph.io/3.6.0/20.appendix/6.eco-tool-version/). ## Contributing @@ -100,7 +100,7 @@ Contributions are warmly welcomed and greatly appreciated. And here are a few wa ## Landscape

-   +
[NebulaGraph](https://landscape.cncf.io/?selected=nebula-graph) enriches the [CNCF Database Landscape](https://landscape.cncf.io/card-mode?category=database&grouping=category). @@ -116,7 +116,7 @@ You can also freely deploy **NebulaGraph** as a back-end service to support your * [Community Chat](https://community-chat.nebula-graph.io/) * [Slack Channel](https://join.slack.com/t/nebulagraph/shared_invite/zt-7ybejuqa-NCZBroh~PCh66d9kOQj45g) * [Stack Overflow](https://stackoverflow.com/questions/tagged/nebula-graph) -* Twitter: [@NebulaGraph](https://twitter.com/NebulaGraph) +* X(Twitter): [@NebulaGraph](https://twitter.com/NebulaGraph) * [LinkedIn Page](https://www.linkedin.com/company/nebula-graph/) * Email: info@vesoft.com From 63688f5c1b3692ed4de6b67556c647c255e7c7d8 Mon Sep 17 00:00:00 2001 From: Steam Date: Fri, 1 Mar 2024 18:02:04 +0800 Subject: [PATCH 19/21] Create Security.md (#5825) as titled --- .github/Security.md | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 .github/Security.md diff --git a/.github/Security.md b/.github/Security.md new file mode 100644 index 00000000000..67d9a318d93 --- /dev/null +++ b/.github/Security.md @@ -0,0 +1,30 @@ +# Vulnerability Assessment Reporting: Beginner's Guide + +NebulaGraph is dedicated to offering stable and secure data services. We recognize the importance of community contributions to our security posture and invite you to report any vulnerabilities you may discover. + +Should you identify a potential security vulnerability within NebulaGraph or encounter a security incident, we urge you to get in touch with our team. + +For efficient communication, please send your findings to (security@vesoft.com) with the following details: + +* Vulnerability name (*): Provide a clear, concise title. Include a CVE identifier if available. +* Description of the security issue (*): Elaborate on the security concern. +* Impacted Components (*): Specify affected modules and their version numbers. +* Reproduction Steps (*): Detail the process to verify the vulnerability. +* Suggested Remediation: Offer potential solutions if possible. +* Contact information (*): + * Name + * Email + * Organization + * Consent for Identity Disclosure + + > Fields marked with an asterisk `(*)` are mandatory. + +## Response Protocol + +The NebulaGraph security team pledges to acknowledge receipt of your report via email within one working day. + +Post-resolution, we will promptly notify you and extend our gratitude for your invaluable assistance in enhancing NebulaGraph's security. + +Disclosure of the vulnerability will be withheld until an official patch is released. We appreciate your discretion and cooperation. + +We thank you for your attention to these guidelines and look forward to your participation in securing NebulaGraph. From 4913d19d9a86980cf28fdc4a6f3e1d16aeeab336 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kiryl=20Valkovich=20=F0=9F=9B=B8?= Date: Fri, 8 Mar 2024 09:32:09 +0400 Subject: [PATCH 20/21] Fix links to CNCF landscape in README.md (#5830) --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 70cc1e8103d..b1d778f51f4 100644 --- a/README.md +++ b/README.md @@ -103,7 +103,7 @@ Contributions are warmly welcomed and greatly appreciated. And here are a few wa
-[NebulaGraph](https://landscape.cncf.io/?selected=nebula-graph) enriches the [CNCF Database Landscape](https://landscape.cncf.io/card-mode?category=database&grouping=category). +[NebulaGraph](https://landscape.cncf.io/?item=app-definition-and-development--database--nebulagraph) enriches the [CNCF Database Landscape](https://landscape.cncf.io/?group=projects-and-products&view-mode=card#app-definition-and-development--database).

## Licensing From 4b94ada030d8a1dc4473e0968ccea762958a2b35 Mon Sep 17 00:00:00 2001 From: Vee Zhang Date: Thu, 21 Mar 2024 09:59:18 +0800 Subject: [PATCH 21/21] Fixed nebula-python version instead of master (#5839) --- tests/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/Makefile b/tests/Makefile index caf4f48176c..9f7249749b3 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -47,7 +47,7 @@ install-deps: pip3 install --user -Ur $(CURR_DIR)/requirements.txt -i $(PYPI_MIRROR) install-nebula-py: install-deps - git clone --branch master https://github.com/vesoft-inc/nebula-python $(CURR_DIR)/nebula-python + git clone --branch release-3.5 https://github.com/vesoft-inc/nebula-python $(CURR_DIR)/nebula-python cd $(CURR_DIR)/nebula-python \ && pip3 install --user . -i $(PYPI_MIRROR) --upgrade rm -rf $(CURR_DIR)/nebula-python