diff --git a/src/storage/exec/MultiTagNode.h b/src/storage/exec/MultiTagNode.h index 46e92adbcb6..474148efaca 100644 --- a/src/storage/exec/MultiTagNode.h +++ b/src/storage/exec/MultiTagNode.h @@ -14,9 +14,12 @@ namespace nebula { namespace storage { -// MultiTagNode is a replacement of HashJoinNode -// in execution of "go over" -// if Graph don't pass any Edge prop +/** + * @brief MultiTagNode is a replacement of HashJoinNode in execution of "go over" if Graph don't + * pass any Edge prop + * + * @see IterateNode + */ class MultiTagNode : public IterateNode { public: using RelNode::doExecute; diff --git a/src/storage/exec/QueryUtils.h b/src/storage/exec/QueryUtils.h index ddce512ef42..bd802c4d32a 100644 --- a/src/storage/exec/QueryUtils.h +++ b/src/storage/exec/QueryUtils.h @@ -31,7 +31,13 @@ class QueryUtils final { kDst, kOther, }; - + /** + * @brief Get return col type by name + * + * @param name + * @return ReturnColType + * @see ReturnColType + */ static ReturnColType toReturnColType(const std::string& name) { if (name == kVid) { return ReturnColType::kVid; @@ -49,7 +55,14 @@ class QueryUtils final { return ReturnColType::kOther; } } - + /** + * @brief Get value with propName from reader + * + * @param reader Value set + * @param propName Filed name + * @param field Field definition + * @return StatusOr + */ static StatusOr readValue(RowReader* reader, const std::string& propName, const meta::SchemaProviderIf::Field* field) { @@ -84,9 +97,15 @@ class QueryUtils final { return value; } - // read prop value, If the RowReader contains this field, - // read from the rowreader, otherwise read the default value - // or null value from the latest schema + /** + * @brief read prop value, If the RowReader contains this field, read from the rowreader, + * otherwise read the default value or null value from the latest schema + * + * @param reader + * @param propName + * @param schema + * @return StatusOr + */ static StatusOr readValue(RowReader* reader, const std::string& propName, const meta::NebulaSchemaProvider* schema) { @@ -215,7 +234,13 @@ class QueryUtils final { return Status::OK(); } - // return none if no valid ttl, else return the ttl property name and time + /** + * @brief Get the Edge TTL Info object + * + * @param edgeContext + * @param edgeType + * @return return none if no valid ttl, else return the ttl property name and time + */ static folly::Optional> getEdgeTTLInfo(EdgeContext* edgeContext, EdgeType edgeType) { folly::Optional> ret; @@ -226,7 +251,13 @@ class QueryUtils final { return ret; } - // return none if no valid ttl, else return the ttl property name and time + /** + * @brief Get the Tag TTL Info object + * + * @param tagContext + * @param tagId + * @return return none if no valid ttl, else return the ttl property name and time + */ static folly::Optional> getTagTTLInfo(TagContext* tagContext, TagID tagId) { folly::Optional> ret; diff --git a/src/storage/exec/RelNode.h b/src/storage/exec/RelNode.h index 1d01dc6d041..45a99e42b29 100644 --- a/src/storage/exec/RelNode.h +++ b/src/storage/exec/RelNode.h @@ -27,13 +27,22 @@ using PropHandler = std::function class StoragePlan; -// RelNode is shortcut for relational algebra node, each RelNode has an execute -// method, which will be invoked in dag when all its dependencies have finished +/** + * @brief RelNode is shortcut for relational algebra node, each RelNode has an execute method, which + * will be invoked in dag when all its dependencies have finished + * + * @tparam T is input data type of plan + */ template class RelNode { friend class StoragePlan; public: + /** + * @brief start execution with `input` and `partId` + * + * + */ virtual nebula::cpp2::ErrorCode execute(PartitionID partId, const T& input) { duration_.resume(); auto ret = doExecute(partId, input); diff --git a/src/storage/exec/ScanNode.h b/src/storage/exec/ScanNode.h index c5157d4a462..a0446203682 100644 --- a/src/storage/exec/ScanNode.h +++ b/src/storage/exec/ScanNode.h @@ -14,11 +14,25 @@ namespace storage { using Cursor = std::string; -// Node to scan vertices of one partition +/** + * @brief Node to scan vertices of one partition + */ class ScanVertexPropNode : public QueryNode { public: using RelNode::doExecute; + /** + * @brief Construct a new Scan Vertex Prop Node object + * + * @param context + * @param tagNodes + * @param enableReadFollower + * @param limit + * @param cursors + * @param resultDataSet + * @param expCtx + * @param filter + */ ScanVertexPropNode(RuntimeContext* context, std::vector> tagNodes, bool enableReadFollower, diff --git a/src/storage/exec/StorageIterator.h b/src/storage/exec/StorageIterator.h index 9597a117ed9..6deede4da3f 100644 --- a/src/storage/exec/StorageIterator.h +++ b/src/storage/exec/StorageIterator.h @@ -14,27 +14,67 @@ namespace nebula { namespace storage { +/** + * @brief Storage iterate Interface + * + */ class StorageIterator { public: virtual ~StorageIterator() = default; + /** + * @brief check if there is any data + * + * @return true if there is still data to be accessed + * @return false if there is no data to be accessed + */ virtual bool valid() const = 0; - // next will skip invalid data, until it points to a valid data or it is - // invalid + /** + * @brief next will skip invalid data, until it points to a valid data or it is invalid + * + */ virtual void next() = 0; + /** + * @brief Return the key of current data. + * + * All data is iterated in key-value format. + * + * @return folly::StringPiece + */ virtual folly::StringPiece key() const = 0; + /** + * @brief Return the value of current data. + * + */ virtual folly::StringPiece val() const = 0; + /** + * @brief Returns the encapsulation of key-value data + * + * @see RowReader + */ virtual RowReader* reader() const = 0; }; -// Iterator of single specified type +/** + * @brief Iterator of single specified type + * + */ class SingleEdgeIterator : public StorageIterator { public: SingleEdgeIterator() = default; + /** + * @brief Construct a new Single Edge Iterator object + * + * @param context + * @param iter Kvstore's iterator. + * @param edgeType EdgeType to be read. + * @param schemas EdgeType's all version schemas. + * @param ttl + */ SingleEdgeIterator(RuntimeContext* context, std::unique_ptr iter, EdgeType edgeType, @@ -83,7 +123,9 @@ class SingleEdgeIterator : public StorageIterator { } protected: - // return true when the value iter to a valid edge value + /** + * @brief return true when the value iter to a valid edge value + */ bool check() { reader_.reset(*schemas_, iter_->val()); if (!reader_) { @@ -113,11 +155,14 @@ class SingleEdgeIterator : public StorageIterator { VertexID lastDstId_ = ""; }; -// Iterator of multiple SingleEdgeIterator, it will iterate over edges of -// different types +/** + * @brief Iterator of multiple SingleEdgeIterator, it will iterate over edges of different types + */ class MultiEdgeIterator : public StorageIterator { public: - // will move to a valid SingleEdgeIterator if there is one + /** + * @brief will move to a valid SingleEdgeIterator if there is one + */ explicit MultiEdgeIterator(std::vector iters) : iters_(std::move(iters)) { moveToNextValidIterator(); } @@ -149,7 +194,9 @@ class MultiEdgeIterator : public StorageIterator { return iters_[curIter_]->edgeType(); } - // return the index of multiple iterators + /** + * @brief return the index of multiple iterators + */ size_t getIdx() const { return curIter_; } @@ -168,91 +215,6 @@ class MultiEdgeIterator : public StorageIterator { std::vector iters_; size_t curIter_ = 0; }; - -class IndexIterator : public StorageIterator { - public: - explicit IndexIterator(std::unique_ptr iter) : iter_(std::move(iter)) {} - - virtual IndexID indexId() const = 0; - - bool valid() const override { - return !!iter_ && iter_->valid(); - } - - void next() override { - iter_->next(); - } - - folly::StringPiece key() const override { - return iter_->key(); - } - - folly::StringPiece val() const override { - return iter_->val(); - } - - protected: - std::unique_ptr iter_; -}; - -class VertexIndexIterator : public IndexIterator { - public: - VertexIndexIterator(std::unique_ptr iter, size_t vIdLen) - : IndexIterator(std::move(iter)), vIdLen_(vIdLen) {} - - RowReader* reader() const override { - return nullptr; - } - - IndexID indexId() const override { - return IndexKeyUtils::getIndexId(iter_->key()); - } - - VertexID vId() const { - return IndexKeyUtils::getIndexVertexID(vIdLen_, iter_->key()).str(); - } - - folly::StringPiece val() const override { - return iter_->val(); - } - - protected: - size_t vIdLen_; -}; - -class EdgeIndexIterator : public IndexIterator { - public: - EdgeIndexIterator(std::unique_ptr iter, size_t vIdLen) - : IndexIterator(std::move(iter)), vIdLen_(vIdLen) {} - - RowReader* reader() const override { - return nullptr; - } - - IndexID indexId() const override { - return IndexKeyUtils::getIndexId(iter_->key()); - } - - VertexID srcId() const { - return IndexKeyUtils::getIndexSrcId(vIdLen_, iter_->key()).str(); - } - - VertexID dstId() const { - return IndexKeyUtils::getIndexDstId(vIdLen_, iter_->key()).str(); - } - - EdgeRanking ranking() const { - return IndexKeyUtils::getIndexRank(vIdLen_, iter_->key()); - } - - folly::StringPiece val() const override { - return iter_->val(); - } - - protected: - size_t vIdLen_; -}; - } // namespace storage } // namespace nebula diff --git a/src/storage/exec/StoragePlan.h b/src/storage/exec/StoragePlan.h index bb05f267eec..129d2c9d160 100644 --- a/src/storage/exec/StoragePlan.h +++ b/src/storage/exec/StoragePlan.h @@ -13,25 +13,25 @@ namespace nebula { namespace storage { -/* -Originated from folly::FutureDAG, not thread-safe. - -The StoragePlan contains a set of RelNode, all you need to do is define a -RelNode, add it to plan by calling addNode, which will return the index of the -RelNode in this plan. The dependencies between different nodes is defined by -calling addDependency in RelNode. - -To run the plan, call the go method, you could get the final result. - -For simplicity, StoragePlan has not detect if has cycle in it for now, user must -make sure no cycle dependency in it. - -For this version, if there are more than one node depends on the same node, that -node will be executed **more than once**. If you want to make sure each node -would be executed exactly once, StoragePlan would be inappropriate. In that -case, please refer to the previous implement, FutureDAG in -StorageDAGBenchmark.cpp -*/ +/** + * @brief Storage query plan + * + * The StoragePlan contains a set of RelNode, all you need to do is define a RelNode, add it to plan + * by calling addNode, which will return the index of the RelNode in this plan. The dependencies + * between different nodes is defined by calling addDependency in RelNode. + * + * To run the plan, call the go method, you could get the final result. + * + * For simplicity, StoragePlan has not detect if has cycle in it for now, user must make sure no + * cycle dependency in it. + * + * For this version, if there are more than one node depends on the same node, that node will be + * executed **more than once**. If you want to make sure each node would be executed exactly once, + * StoragePlan would be inappropriate. In that case, please refer to the previous implement, + * FutureDAG in StorageDAGBenchmark.cpp + * + * @tparam T Iterated data type + */ template class StoragePlan { public: diff --git a/src/storage/exec/TagNode.h b/src/storage/exec/TagNode.h index 80c46f9874f..003d917a55e 100644 --- a/src/storage/exec/TagNode.h +++ b/src/storage/exec/TagNode.h @@ -13,11 +13,23 @@ namespace nebula { namespace storage { -// TagNode will return a DataSet of specified props of tagId +/** + * @brief TagNode will return a DataSet of specified props of tagId + * + * @see IterateNode + */ class TagNode final : public IterateNode { public: using RelNode::doExecute; + /** + * @brief Construct a new Tag Node object + * + * @param context Runtime Context. + * @param ctx Tag Context. + * @param tagId Tag id to get. + * @param props Tag's props to get. + */ TagNode(RuntimeContext* context, TagContext* ctx, TagID tagId, @@ -61,6 +73,13 @@ class TagNode final : public IterateNode { return ret; } + /** + * @brief For resuming from a breakpoint. + * + * @param key Next key to be read + * @param value Next value to be read + * @return nebula::cpp2::ErrorCode + */ nebula::cpp2::ErrorCode doExecute(const std::string& key, const std::string& value) { key_ = key; value_ = value; @@ -68,6 +87,13 @@ class TagNode final : public IterateNode { return nebula::cpp2::ErrorCode::SUCCEEDED; } + /** + * @brief Collect tag's prop + * + * @param nullHandler Callback if prop is null. + * @param valueHandler Callback if prop is not null. + * @return nebula::cpp2::ErrorCode + */ nebula::cpp2::ErrorCode collectTagPropsIfValid(NullHandler nullHandler, PropHandler valueHandler) { if (!valid()) { diff --git a/src/storage/exec/UpdateNode.h b/src/storage/exec/UpdateNode.h index b2114e05878..0b79198ce52 100644 --- a/src/storage/exec/UpdateNode.h +++ b/src/storage/exec/UpdateNode.h @@ -17,10 +17,33 @@ namespace nebula { namespace storage { - +/** + * @brief Updatenode will calculate new values of properties that need to be updated and write them + * back to kvstore + * + * @tparam T input data type + * @see RelNode + */ template class UpdateNode : public RelNode { public: + /** + * @brief Construct a new Update Node object + * + * @param context Runtime context. + * @param indexes Indexes of the updated Tags/Edges. + * @param updatedProps Updated properties of Tags/Edges. + * @param filterNode Filter node.Note that in the current implementation, FilterNode can never be + * Null. If there is no filter condition, the check inside FilterNode will always return true. + * @param insertable Flag of upsert. + * @param depPropMap Dependent properties when executing update + * @param expCtx Expression context. + * @param isEdge Is Edge or not. + * + * @see FilterNode + * @todo If there is no filter condition, skip filterNode directly when building the execution + * plan. + */ UpdateNode(RuntimeContext* context, std::vector> indexes, std::vector& updatedProps, @@ -39,7 +62,9 @@ class UpdateNode : public RelNode { isEdge_(isEdge) { RelNode::name_ = "UpdateNode"; } - + /** + * @brief Check if Field exists + */ nebula::cpp2::ErrorCode checkField(const meta::SchemaProviderIf::Field* field) { if (!field) { VLOG(1) << "Fail to read prop"; @@ -51,6 +76,14 @@ class UpdateNode : public RelNode { return nebula::cpp2::ErrorCode::SUCCEEDED; } + /** + * @brief Get the Default Or Null Value object + * + * @param field Field to be computed. + * @param name Property name + * @return E_INVALID_FIELD_VALUE if the field can't be null and doesn't have default value, else + * SUCCEEDED. + */ nebula::cpp2::ErrorCode getDefaultOrNullValue(const meta::SchemaProviderIf::Field* field, const std::string& name) { if (field->hasDefault()) { @@ -65,8 +98,11 @@ class UpdateNode : public RelNode { } return nebula::cpp2::ErrorCode::SUCCEEDED; } - - // Used for upsert tag/edge + /** + * @brief Used for upsert tag/edge + * + * @return nebula::cpp2::ErrorCode + */ nebula::cpp2::ErrorCode checkPropsAndGetDefaultValue() { // Store checked props // For example: @@ -125,10 +161,14 @@ class UpdateNode : public RelNode { // ===================================================== RuntimeContext* context_; std::vector> indexes_; - // update + /** + * @brief update := + */ std::vector updatedProps_; FilterNode* filterNode_; - // Whether to allow insert + /** + * @brief Whether to allow insert + */ bool insertable_{false}; std::string key_; @@ -136,26 +176,39 @@ class UpdateNode : public RelNode { const meta::NebulaSchemaProvider* schema_{nullptr}; - // use to save old row value + /** + * @brief use to save old row value + */ std::string val_; std::unique_ptr rowWriter_; - // prop -> value + /** + * @brief value of prop + */ std::unordered_map props_; std::atomic exeResult_; - // updatedProps_ dependent props in value expression + /** + * @brief updatedProps_ dependent props in value expression + */ std::vector>> depPropMap_; StorageExpressionContext* expCtx_; bool isEdge_{false}; }; -// Only use for update vertex -// Update records, write to kvstore +/** + * @brief Only use for update vertex + * + * Update records, write to kvstore + */ class UpdateTagNode : public UpdateNode { public: using RelNode::doExecute; - + /** + * @brief Construct a new Update Tag Node object + * + * @see UpdateNode + */ UpdateTagNode(RuntimeContext* context, std::vector> indexes, std::vector& updatedProps, @@ -230,7 +283,11 @@ class UpdateTagNode : public UpdateNode { baton.wait(); return ret; } - + /** + * @brief Get the Latest Tag Schema And Name object + * + * @return E_TAG_NOT_FOUND if tag not found. + */ nebula::cpp2::ErrorCode getLatestTagSchemaAndName() { auto schemaIter = tagContext_->schemas_.find(tagId_); if (schemaIter == tagContext_->schemas_.end() || schemaIter->second.empty()) { @@ -251,9 +308,12 @@ class UpdateTagNode : public UpdateNode { return nebula::cpp2::ErrorCode::SUCCEEDED; } - // Insert props row, - // For insert, condition is always true, - // Props must have default value or nullable, or set in UpdatedProp_ + /** + * @brief Insert props row. + * + * For insert, condition is always true, + * Props must have default value or nullable, or set in UpdatedProp_ + */ nebula::cpp2::ErrorCode insertTagProps(PartitionID partId, const VertexID& vId) { context_->insert_ = true; auto ret = getLatestTagSchemaAndName(); @@ -276,8 +336,10 @@ class UpdateTagNode : public UpdateNode { return nebula::cpp2::ErrorCode::SUCCEEDED; } - - // collect tag prop + /** + * @brief collect tag prop + * + */ nebula::cpp2::ErrorCode collTagProp(const VertexID& vId) { auto ret = getLatestTagSchemaAndName(); if (ret != nebula::cpp2::ErrorCode::SUCCEEDED) { @@ -314,6 +376,17 @@ class UpdateTagNode : public UpdateNode { return nebula::cpp2::ErrorCode::SUCCEEDED; } + /** + * @brief Calculate updated propertis and indexes + * + * This function will calculate the properties to be updated and those indexes if exist, and + * encode them into key-value format. + * + * @param partId + * @param vId + * @return folly::Optional BatchHolder encode value. + * @see BatchHolder + */ folly::Optional updateAndWriteBack(const PartitionID partId, const VertexID vId) { ObjectPool pool; for (auto& updateProp : updatedProps_) { @@ -419,6 +492,9 @@ class UpdateTagNode : public UpdateNode { return encodeBatchValue(batchHolder->getBatch()); } + /** + * @brief Generate index keys + */ std::vector indexKeys(PartitionID partId, const VertexID& vId, RowReader* reader, @@ -437,12 +513,20 @@ class UpdateTagNode : public UpdateNode { std::string tagName_; }; -// Only use for update edge -// Update records, write to kvstore +/** + * @brief Only use for update edge + * + * Update records, write to kvstore + */ class UpdateEdgeNode : public UpdateNode { public: using RelNode::doExecute; + /** + * @brief Construct a new Update Edge Node object + * + * @see UpdateNode + */ UpdateEdgeNode(RuntimeContext* context, std::vector> indexes, std::vector& updatedProps, @@ -540,7 +624,11 @@ class UpdateEdgeNode : public UpdateNode { baton.wait(); return ret; } - + /** + * @brief Get the Latest Edge Schema And Name object + * + * @return E_EDGE_NOT_FOUND if edge not found + */ nebula::cpp2::ErrorCode getLatestEdgeSchemaAndName() { auto schemaIter = edgeContext_->schemas_.find(std::abs(edgeType_)); if (schemaIter == edgeContext_->schemas_.end() || schemaIter->second.empty()) { @@ -561,8 +649,11 @@ class UpdateEdgeNode : public UpdateNode { return nebula::cpp2::ErrorCode::SUCCEEDED; } - // Insert props row, - // Operator props must have default value or nullable, or set in UpdatedProp_ + /** + * @brief Insert props row + * + * Operator props must have default value or nullable, or set in UpdatedProp_ + */ nebula::cpp2::ErrorCode insertEdgeProps(const PartitionID partId, const cpp2::EdgeKey& edgeKey) { context_->insert_ = true; auto ret = getLatestEdgeSchemaAndName(); @@ -597,7 +688,9 @@ class UpdateEdgeNode : public UpdateNode { return nebula::cpp2::ErrorCode::SUCCEEDED; } - // Collect edge prop + /** + * @brief Collect edge prop + */ nebula::cpp2::ErrorCode collEdgeProp(const cpp2::EdgeKey& edgeKey) { auto ret = getLatestEdgeSchemaAndName(); if (ret != nebula::cpp2::ErrorCode::SUCCEEDED) { @@ -638,7 +731,13 @@ class UpdateEdgeNode : public UpdateNode { val_ = reader_->getData(); return nebula::cpp2::ErrorCode::SUCCEEDED; } - + /** + * @brief Calculate updated propertis and indexes + * + * Similar to UpdateTagNode::updateAndWriteBack + * + * @see UpdateTagNode::updateAndWriteBack + */ folly::Optional updateAndWriteBack(const PartitionID partId, const cpp2::EdgeKey& edgeKey) { ObjectPool pool; diff --git a/src/storage/exec/UpdateResultNode.h b/src/storage/exec/UpdateResultNode.h index 35df3cd43c5..af180947552 100644 --- a/src/storage/exec/UpdateResultNode.h +++ b/src/storage/exec/UpdateResultNode.h @@ -13,11 +13,29 @@ namespace nebula { namespace storage { +/** + * @brief UpdateResNode is used to calcaute the expressions whose results are need to return to + * graphd + * + * UpdateResNode is used to evaluate the expression in the yield clause + * + * @tparam T + * + * @see RelNode + */ template class UpdateResNode : public RelNode { public: using RelNode::doExecute; + /** + * @brief Construct a new Update Res Node object + * + * @param context Runtime context. + * @param updateNode UpdateNode may be UpdateTagNode or UpdateEdgeNode. + * @param returnPropsExp Expressions in yield clause. + * @param expCtx Expression context + */ UpdateResNode(RuntimeContext* context, RelNode* updateNode, std::vector returnPropsExp, @@ -66,7 +84,10 @@ class UpdateResNode : public RelNode { std::vector returnPropsExp_; StorageExpressionContext* expCtx_; - // return prop sets + /** + * @brief return prop sets + * + */ nebula::DataSet* result_; bool insert_{false}; };