#pragma once #include #include #include #include #include "common/kv/ITransaction.h" #include "common/utils/String.h" #include "foundationdb/fdb_c_options.g.h" #include "foundationdb/fdb_c_types.h" #define FDB_API_VERSION 710 #include namespace hf3fs::kv { class FDBKVEngine; namespace fdb { using folly::coro::Task; using KeyValue = IReadOnlyTransaction::KeyValue; // Structs for returned values. struct KeyRange { String beginKey; String endKey; }; // Structs for parameters. struct KeyRangeView { std::string_view beginKey; std::string_view endKey; }; struct KeySelector { std::string_view key; // Find the last item less than key bool orEqual = true; // (or equal to key, if this is true) int offset = 0; // and then move forward this many items (or backward if negative) KeySelector() = default; KeySelector(std::string_view key, bool orEqual, int offset) : key(std::move(key)), orEqual(orEqual), offset(offset) {} }; struct GetRangeLimits { std::optional rows; std::optional bytes; explicit GetRangeLimits(std::optional r = {}, std::optional b = {}) : rows(r), bytes(b) {} }; template class Result { public: fdb_error_t error() const { return error_; }; V &value() { return value_; } const V &value() const { return value_; } protected: friend class DB; friend class Transaction; static Task toTask(FDBFuture *f); void extractValue(); protected: struct FDBFutureDeleter { constexpr FDBFutureDeleter() noexcept = default; void operator()(FDBFuture *future) const { future ? fdb_future_destroy(future) : void(); } }; std::unique_ptr future_; fdb_error_t error_ = 0; V value_{}; }; class Int64Result : public Result {}; class KeyResult : public Result {}; class ValueResult : public Result> {}; class KeyArrayResult : public Result> {}; class StringArrayResult : public Result> {}; class KeyValueArrayResult : public Result, bool>> {}; class KeyRangeArrayResult : public Result> {}; struct EmptyValue {}; class EmptyResult : public Result {}; class DB { public: static fdb_error_t selectAPIVersion(int version); static std::string_view errorMsg(fdb_error_t code); static bool evaluatePredicate(int predicate_test, fdb_error_t code); // network static fdb_error_t setNetworkOption(FDBNetworkOption option, std::string_view value = {}); static fdb_error_t setupNetwork(); static fdb_error_t runNetwork(); static fdb_error_t stopNetwork(); public: DB() = default; explicit DB(const String &clusterFilePath, bool readonly) : readonly_(readonly) { auto path = clusterFilePath.empty() ? nullptr : clusterFilePath.c_str(); FDBDatabase *db; error_ = fdb_create_database(path, &db); if (error_ == 0) { db_.reset(db); } } fdb_error_t error() const { return error_; } explicit operator bool() const { return error() == 0; } operator FDBDatabase *() const { return db_.get(); } fdb_error_t setOption(FDBDatabaseOption option, std::string_view value = {}); Task rebootWorker(std::string_view address, bool check = false, int duration = 0); Task forceRecoveryWithDataLoss(std::string_view dcid); Task createSnapshot(std::string_view uid, std::string_view snapCommand); Task purgeBlobGranules(const KeyRangeView &range, int64_t purgeVersion, fdb_bool_t force); Task waitPurgeGranulesComplete(std::string_view purgeKey); bool readonly() const { return readonly_; } private: friend class hf3fs::kv::FDBKVEngine; struct FDBDatabaseDeleter { constexpr FDBDatabaseDeleter() noexcept = default; void operator()(FDBDatabase *db) const { db ? fdb_database_destroy(db) : void(); } }; std::unique_ptr db_; bool readonly_ = false; fdb_error_t error_ = 1; }; class Transaction final { public: Transaction(DB &db) : readonly_(db.readonly()) { FDBTransaction *tr; error_ = fdb_database_create_transaction(db, &tr); if (error_ == 0) { tr_.reset(tr); } } fdb_error_t error() const { return error_; } explicit operator bool() const { return error_ == 0 && tr_; } fdb_error_t setOption(FDBTransactionOption option, std::string_view value = {}); // Read transaction void setReadVersion(int64_t version); Task getReadVersion(); Task get(std::string_view key, fdb_bool_t snapshot = false); Task getKey(const KeySelector &selector, fdb_bool_t snapshot = false); Task watch(std::string_view key); Task getAddressesForKey(std::string_view key); Task getRange(const KeySelector &begin, const KeySelector &end, GetRangeLimits limits = GetRangeLimits(), int iteration = 0, bool snapshot = false, bool reverse = false, FDBStreamingMode streamingMode = FDB_STREAMING_MODE_SERIAL); Task getEstimatedRangeSizeBytes(const KeyRangeView &range); Task getRangeSplitPoints(const KeyRangeView &range, int64_t chunkSize); Task onError(fdb_error_t err); void cancel(); void reset(); // Write transaction fdb_error_t addConflictRange(const KeyRangeView &range, FDBConflictRangeType type); void atomicOp(std::string_view key, std::string_view param, FDBMutationType operationType); void set(std::string_view key, std::string_view value); void clear(std::string_view key); void clearRange(const KeyRangeView &range); Task commit(); fdb_error_t getCommittedVersion(int64_t *outVersion); Task getApproximateSize(); Task getVersionstamp(); private: struct FDBTransactionDeleter { constexpr FDBTransactionDeleter() noexcept = default; void operator()(FDBTransaction *tr) const { tr ? fdb_transaction_destroy(tr) : void(); } }; std::unique_ptr tr_; bool readonly_ = false; fdb_error_t error_ = 1; }; } // namespace fdb } // namespace hf3fs::kv