/* * ThreadSafeTransaction.h * * This source file is part of the FoundationDB open source project * * Copyright 2013-2022 Apple Inc. and the FoundationDB project authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef FDBCLIENT_THREADSAFETRANSACTION_H #define FDBCLIENT_THREADSAFETRANSACTION_H #include "flow/ProtocolVersion.h" #pragma once #include "fdbclient/ReadYourWrites.h" #include "flow/ThreadHelper.actor.h" #include "fdbclient/ClusterInterface.h" #include "fdbclient/IClientApi.h" #include "fdbclient/ISingleThreadTransaction.h" // An implementation of IDatabase that serializes operations onto the network thread and interacts with the lower-level // client APIs exposed by NativeAPI and ReadYourWrites. class ThreadSafeDatabase : public IDatabase, public ThreadSafeReferenceCounted { public: ~ThreadSafeDatabase() override; static ThreadFuture> createFromExistingDatabase(Database cx); Reference openTenant(TenantNameRef tenantName) override; Reference createTransaction() override; void setOption(FDBDatabaseOptions::Option option, Optional value = Optional()) override; double getMainThreadBusyness() override; // Returns the protocol version reported by the coordinator this client is connected to // If an expected version is given, the future won't return until the protocol version is different than expected // Note: this will never return if the server is running a protocol from FDB 5.0 or older ThreadFuture getServerProtocol( Optional expectedVersion = Optional()) override; // Returns after a majority of coordination servers are available and have reported a leader. The // cluster file therefore is valid, but the database might be unavailable. ThreadFuture onConnected(); void addref() override { ThreadSafeReferenceCounted::addref(); } void delref() override { ThreadSafeReferenceCounted::delref(); } ThreadFuture rebootWorker(const StringRef& address, bool check, int duration) override; ThreadFuture forceRecoveryWithDataLoss(const StringRef& dcid) override; ThreadFuture createSnapshot(const StringRef& uid, const StringRef& snapshot_command) override; ThreadFuture purgeBlobGranules(const KeyRangeRef& keyRange, Version purgeVersion, bool force) override; ThreadFuture waitPurgeGranulesComplete(const KeyRef& purgeKey) override; ThreadFuture createSharedState() override; void setSharedState(DatabaseSharedState* p) override; private: friend class ThreadSafeTenant; friend class ThreadSafeTransaction; bool isConfigDB{ false }; DatabaseContext* db; public: // Internal use only ThreadSafeDatabase(std::string connFilename, int apiVersion); ThreadSafeDatabase(DatabaseContext* db) : db(db) {} DatabaseContext* unsafeGetPtr() const { return db; } }; class ThreadSafeTenant : public ITenant, ThreadSafeReferenceCounted, NonCopyable { public: ThreadSafeTenant(Reference db, StringRef name) : db(db), name(name) {} ~ThreadSafeTenant() override; Reference createTransaction() override; void addref() override { ThreadSafeReferenceCounted::addref(); } void delref() override { ThreadSafeReferenceCounted::delref(); } private: Reference db; Standalone name; }; // An implementation of ITransaction that serializes operations onto the network thread and interacts with the // lower-level client APIs exposed by ISingleThreadTransaction class ThreadSafeTransaction : public ITransaction, ThreadSafeReferenceCounted, NonCopyable { public: explicit ThreadSafeTransaction(DatabaseContext* cx, ISingleThreadTransaction::Type type, Optional tenant); ~ThreadSafeTransaction() override; // Note: used while refactoring fdbcli, need to be removed later explicit ThreadSafeTransaction(ReadYourWritesTransaction* ryw); void cancel() override; void setVersion(Version v) override; ThreadFuture getReadVersion() override; ThreadFuture> get(const KeyRef& key, bool snapshot = false) override; ThreadFuture getKey(const KeySelectorRef& key, bool snapshot = false) override; ThreadFuture getRange(const KeySelectorRef& begin, const KeySelectorRef& end, int limit, bool snapshot = false, bool reverse = false) override; ThreadFuture getRange(const KeySelectorRef& begin, const KeySelectorRef& end, GetRangeLimits limits, bool snapshot = false, bool reverse = false) override; ThreadFuture getRange(const KeyRangeRef& keys, int limit, bool snapshot = false, bool reverse = false) override { return getRange(firstGreaterOrEqual(keys.begin), firstGreaterOrEqual(keys.end), limit, snapshot, reverse); } ThreadFuture getRange(const KeyRangeRef& keys, GetRangeLimits limits, bool snapshot = false, bool reverse = false) override { return getRange(firstGreaterOrEqual(keys.begin), firstGreaterOrEqual(keys.end), limits, snapshot, reverse); } ThreadFuture getMappedRange(const KeySelectorRef& begin, const KeySelectorRef& end, const StringRef& mapper, GetRangeLimits limits, bool snapshot, bool reverse) override; ThreadFuture>> getAddressesForKey(const KeyRef& key) override; ThreadFuture> getVersionstamp() override; ThreadFuture getEstimatedRangeSizeBytes(const KeyRangeRef& keys) override; ThreadFuture>> getRangeSplitPoints(const KeyRangeRef& range, int64_t chunkSize) override; ThreadFuture>> getBlobGranuleRanges(const KeyRangeRef& keyRange) override; ThreadResult readBlobGranules(const KeyRangeRef& keyRange, Version beginVersion, Optional readVersion, ReadBlobGranuleContext granuleContext) override; void addReadConflictRange(const KeyRangeRef& keys) override; void makeSelfConflicting(); void atomicOp(const KeyRef& key, const ValueRef& value, uint32_t operationType) override; void set(const KeyRef& key, const ValueRef& value) override; void clear(const KeyRef& begin, const KeyRef& end) override; void clear(const KeyRangeRef& range) override; void clear(const KeyRef& key) override; ThreadFuture watch(const KeyRef& key) override; void addWriteConflictRange(const KeyRangeRef& keys) override; ThreadFuture commit() override; Version getCommittedVersion() override; VersionVector getVersionVector() override; UID getSpanID() override; ThreadFuture getApproximateSize() override; ThreadFuture getProtocolVersion(); void setOption(FDBTransactionOptions::Option option, Optional value = Optional()) override; ThreadFuture checkDeferredError(); ThreadFuture onError(Error const& e) override; Optional getTenant() override; // These are to permit use as state variables in actors: ThreadSafeTransaction() : tr(nullptr) {} void operator=(ThreadSafeTransaction&& r) noexcept; ThreadSafeTransaction(ThreadSafeTransaction&& r) noexcept; void reset() override; void addref() override { ThreadSafeReferenceCounted::addref(); } void delref() override { ThreadSafeReferenceCounted::delref(); } private: ISingleThreadTransaction* tr; const Optional tenantName; }; // An implementation of IClientApi that serializes operations onto the network thread and interacts with the lower-level // client APIs exposed by NativeAPI and ReadYourWrites. class ThreadSafeApi : public IClientApi, ThreadSafeReferenceCounted { public: void selectApiVersion(int apiVersion) override; const char* getClientVersion() override; void setNetworkOption(FDBNetworkOptions::Option option, Optional value = Optional()) override; void setupNetwork() override; void runNetwork() override; void stopNetwork() override; Reference createDatabase(const char* clusterFilePath) override; void addNetworkThreadCompletionHook(void (*hook)(void*), void* hookParameter) override; private: friend IClientApi* getLocalClientAPI(); ThreadSafeApi(); int apiVersion; const std::string clientVersion; uint64_t transportId; Mutex lock; std::vector> threadCompletionHooks; }; #endif