#pragma once #include #include #include #include #include #include #include #include #include #include #include #include #include #include "client/mgmtd/ICommonMgmtdClient.h" #include "client/mgmtd/IMgmtdClientForServer.h" #include "client/storage/StorageClient.h" #include "common/kv/IKVEngine.h" #include "common/kv/ITransaction.h" #include "common/kv/WithTransaction.h" #include "common/utils/BackgroundRunner.h" #include "common/utils/CPUExecutorGroup.h" #include "common/utils/Coroutine.h" #include "common/utils/CoroutinesPool.h" #include "common/utils/Result.h" #include "core/user/UserStoreEx.h" #include "fbs/meta/Common.h" #include "fbs/meta/Service.h" #include "fdb/FDBRetryStrategy.h" #include "meta/base/Config.h" #include "meta/components/ChainAllocator.h" #include "meta/components/Distributor.h" #include "meta/components/FileHelper.h" #include "meta/components/Forward.h" #include "meta/components/GcManager.h" #include "meta/components/SessionManager.h" #include "meta/store/Inode.h" #include "meta/store/MetaStore.h" #include "meta/store/ops/BatchOperation.h" namespace hf3fs::meta::server { class BatchedOp; class MetaOperator : public folly::NonCopyableNonMovable { public: MetaOperator(const Config &cfg, flat::NodeId nodeId, std::shared_ptr kvEngine, std::shared_ptr mgmtdClient, std::shared_ptr storageClient, std::unique_ptr forward); CoTryTask init(std::optional rootLayout); void start(CPUExecutorGroup &exec); void beforeStop(); void afterStop(); CoTryTask authenticate(AuthReq req); CoTryTask statFs(StatFsReq req); CoTryTask stat(StatReq req); CoTryTask getRealPath(GetRealPathReq req); CoTryTask open(OpenReq req); CoTryTask close(CloseReq req); CoTryTask create(CreateReq req); CoTryTask mkdirs(MkdirsReq req); CoTryTask symlink(SymlinkReq req); CoTryTask remove(RemoveReq req); CoTryTask rename(RenameReq req); CoTryTask list(ListReq req); CoTryTask truncate(TruncateReq req); CoTryTask sync(SyncReq req); CoTryTask hardLink(HardLinkReq req); CoTryTask setAttr(SetAttrReq req); CoTryTask pruneSession(PruneSessionReq req); CoTryTask dropUserCache(DropUserCacheReq req); CoTryTask lockDirectory(LockDirectoryReq req); CoTryTask testRpc(TestRpcReq req); CoTryTask batchStat(BatchStatReq req); CoTryTask batchStatByPath(BatchStatByPathReq req); private: friend class MockMeta; template FRIEND_TEST(TestBatchOp, batch); template FRIEND_TEST(TestCreate, batch); class Batch { public: void setNext(BatchedOp *op, folly::coro::Baton *baton) { next = op; nextBaton = baton; } bool wakeupNext() { if (!next) { return false; } nextBaton->post(); next = nullptr; nextBaton = nullptr; return true; } BatchedOp *getNext() const { return next; } private: BatchedOp *next = nullptr; folly::coro::Baton *nextBaton = nullptr; }; kv::FDBRetryStrategy::Config createRetryConfig() const; kv::FDBRetryStrategy createRetryStrategy() const { return kv::FDBRetryStrategy(createRetryConfig()); } template auto runOp(Func &&func, Arg &&arg) -> CoTryTask::element_type::RspT>; template std::unique_ptr addBatchReq(InodeId inodeId, BatchedOp::Waiter &waiter) { auto func = [&](auto &map) { auto [iter, inserted] = map.try_emplace(inodeId); auto &batch = iter->second; if (inserted) { assert(!batch.getNext()); auto op = std::make_unique(*metaStore_, inodeId); op->add(waiter); waiter.baton.post(); return op; } else if (!batch.getNext()) { auto op = std::make_unique(*metaStore_, inodeId); op->add(waiter); batch.setNext(op.get(), &waiter.baton); return op; } else { auto next = batch.getNext(); auto num_reqs = next->numReqs(); if (UNLIKELY(config_.max_batch_operations() != 0 && num_reqs >= config_.max_batch_operations())) { auto msg = fmt::format("too many batch operations on {}", inodeId); XLOG(WARN, msg); waiter.result = makeError(MetaCode::kBusy, std::move(msg)); waiter.baton.post(); } else { if (num_reqs && num_reqs % 1024 == 0) { XLOGF(WARN, "{} batch operations on {}", num_reqs, inodeId); } next->add(waiter); } return std::unique_ptr(); } }; return batches_.withLock(func, inodeId); } CoTryTask runBatch(InodeId inodeId, std::unique_ptr op, std::optional deadline = std::nullopt); template CoTryTask runInBatch(InodeId inodeId, Req req); CoTryTask authenticate(UserInfo &userInfo); const Config &config_; flat::NodeId nodeId_; analytics::StructuredTraceLog metaEventTraceLog_; std::shared_ptr kvEngine_; std::shared_ptr mgmtd_; std::shared_ptr distributor_; std::shared_ptr userStore_; std::shared_ptr inodeIdAlloc_; std::shared_ptr chainAlloc_; std::shared_ptr fileHelper_; std::shared_ptr sessionManager_; std::shared_ptr gcManager_; std::unique_ptr forward_; std::unique_ptr metaStore_; Shards, 63> batches_; std::atomic_bool stop_{false}; std::unique_ptr bgRunner_; }; } // namespace hf3fs::meta::server