db.hpp 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705
  1. /*************************************************************************
  2. *
  3. * Copyright 2016 Realm Inc.
  4. *
  5. * Licensed under the Apache License, Version 2.0 (the "License");
  6. * you may not use this file except in compliance with the License.
  7. * You may obtain a copy of the License at
  8. *
  9. * http://www.apache.org/licenses/LICENSE-2.0
  10. *
  11. * Unless required by applicable law or agreed to in writing, software
  12. * distributed under the License is distributed on an "AS IS" BASIS,
  13. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14. * See the License for the specific language governing permissions and
  15. * limitations under the License.
  16. *
  17. **************************************************************************/
  18. #ifndef REALM_DB_HPP
  19. #define REALM_DB_HPP
  20. #include <realm/db_options.hpp>
  21. #include <realm/group.hpp>
  22. #include <realm/handover_defs.hpp>
  23. #include <realm/impl/changeset_input_stream.hpp>
  24. #include <realm/impl/transact_log.hpp>
  25. #include <realm/replication.hpp>
  26. #include <realm/util/checked_mutex.hpp>
  27. #include <realm/util/features.h>
  28. #include <realm/util/functional.hpp>
  29. #include <realm/util/interprocess_condvar.hpp>
  30. #include <realm/util/interprocess_mutex.hpp>
  31. #include <realm/util/encrypted_file_mapping.hpp>
  32. #include <realm/version_id.hpp>
  33. #include <functional>
  34. #include <cstdint>
  35. #include <limits>
  36. #include <condition_variable>
  37. namespace realm {
  38. class Transaction;
  39. using TransactionRef = std::shared_ptr<Transaction>;
  40. /// Thrown by DB::create() if the lock file is already open in another
  41. /// process which can't share mutexes with this process
  42. struct IncompatibleLockFile : FileAccessError {
  43. IncompatibleLockFile(const std::string& path, const std::string& msg)
  44. : FileAccessError(
  45. ErrorCodes::IncompatibleLockFile,
  46. util::format(
  47. "Realm file '%1' is currently open in another process which cannot share access with this process. "
  48. "This could either be due to the existing process being a different architecture or due to the "
  49. "existing process using an incompatible version of Realm. "
  50. "If the other process is Realm Studio, you may need to update it (or update Realm if your Studio "
  51. "version is too new), and if using an iOS simulator, make sure that you are using a 64-bit "
  52. "simulator. Underlying problem: %2",
  53. path, msg),
  54. path)
  55. {
  56. }
  57. };
  58. /// Thrown by DB::create() if the type of history
  59. /// (Replication::HistoryType) in the opened Realm file is incompatible with the
  60. /// mode in which the Realm file is opened. For example, if there is a mismatch
  61. /// between the history type in the file, and the history type associated with
  62. /// the replication plugin passed to DB::create().
  63. ///
  64. /// This exception will also be thrown if the history schema version is lower
  65. /// than required, and no migration is possible
  66. /// (Replication::is_upgradable_history_schema()).
  67. struct IncompatibleHistories : FileAccessError {
  68. IncompatibleHistories(const std::string& msg, const std::string& path)
  69. : FileAccessError(ErrorCodes::IncompatibleHistories,
  70. msg + " Synchronized Realms cannot be opened in non-sync mode, and vice versa.", path)
  71. {
  72. }
  73. };
  74. /// The FileFormatUpgradeRequired exception can be thrown by the DB
  75. /// constructor when opening a database that uses a deprecated file format
  76. /// and/or a deprecated history schema, and the user has indicated he does not
  77. /// want automatic upgrades to be performed. This exception indicates that until
  78. /// an upgrade of the file format is performed, the database will be unavailable
  79. /// for read or write operations.
  80. /// It will also be thrown if a realm which requires upgrade is opened in read-only
  81. /// mode (Group::open).
  82. struct FileFormatUpgradeRequired : FileAccessError {
  83. FileFormatUpgradeRequired(const std::string& path)
  84. : FileAccessError(ErrorCodes::FileFormatUpgradeRequired, "Database upgrade required but prohibited.", path, 0)
  85. {
  86. }
  87. };
  88. /// A DB facilitates transactions.
  89. ///
  90. /// Access to a database is done through transactions. Transactions
  91. /// are created by a DB object. No matter how many transactions you
  92. /// use, you only need a single DB object per file. Methods on the DB
  93. /// object are thread-safe.
  94. ///
  95. /// Realm has 3 types of Transactions:
  96. /// * A frozen transaction allows read only access
  97. /// * A read transaction allows read only access but can be promoted
  98. /// to a write transaction.
  99. /// * A write transaction allows write access. A write transaction can
  100. /// be demoted to a read transaction.
  101. ///
  102. /// Frozen transactions are thread safe. Read and write transactions are not.
  103. ///
  104. /// Two processes that want to share a database file must reside on
  105. /// the same host.
  106. ///
  107. class DB;
  108. using DBRef = std::shared_ptr<DB>;
  109. class DB : public std::enable_shared_from_this<DB> {
  110. struct ReadLockInfo;
  111. struct Private {};
  112. public:
  113. // Create a DB and associate it with a file. DB Objects can only be associated with one file,
  114. // the association determined on creation of the DB Object. The association can be broken by
  115. // calling DB::close(), but after that no new association can be established. To reopen the
  116. // file (or another file), a new DB object is needed. The specified Replication instance, if
  117. // any, must remain in existence for as long as the DB.
  118. static DBRef create(const std::string& file, bool no_create = false, const DBOptions& options = DBOptions());
  119. static DBRef create(Replication& repl, const std::string& file, const DBOptions& options = DBOptions());
  120. static DBRef create(std::unique_ptr<Replication> repl, const std::string& file,
  121. const DBOptions& options = DBOptions());
  122. static DBRef create(BinaryData, bool take_ownership = true);
  123. static DBRef create(std::unique_ptr<Replication> repl, const DBOptions& options = DBOptions());
  124. // file is used to set the `db_path` used to register and associate a users's SyncSession with the Realm path (see
  125. // SyncUser::register_session) SyncSession::path() relies on the registered `m_db->get_path`
  126. static DBRef create_in_memory(std::unique_ptr<Replication> repl, const std::string& file,
  127. const DBOptions& options = DBOptions());
  128. ~DB() noexcept;
  129. explicit DB(Private, const DBOptions& options);
  130. // Disable copying to prevent accessor errors. If you really want another
  131. // instance, open another DB object on the same file. But you don't.
  132. DB(const DB&) = delete;
  133. DB& operator=(const DB&) = delete;
  134. /// Close an open database. Calling close() is thread-safe with respect to
  135. /// other calls to close and with respect to deleting transactions.
  136. /// Calling close() while a write transaction is open is an error and close()
  137. /// will throw a LogicError::wrong_transact_state.
  138. /// Calling close() while a read transaction is open is by default treated
  139. /// in the same way, but close(true) will allow the error to be ignored and
  140. /// release resources despite open read transactions.
  141. /// As successfull call to close() leaves transactions (and any associated
  142. /// accessors) in a defunct state and the actual close() operation is not
  143. /// interlocked with access through those accessors, so any access through accessors
  144. /// may constitute a race with a call to close().
  145. /// Instead of using DB::close() to release resources, we recommend using transactions
  146. /// to control release as follows:
  147. /// * explicitly nullify TransactionRefs at earliest time possible and
  148. /// * for read or write transactions - but not frozen transactions, explicitly call
  149. /// close() at earliest time possible
  150. /// * explicitly nullify any DBRefs you may have.
  151. void close(bool allow_open_read_transactions = false) REQUIRES(!m_mutex);
  152. bool is_attached() const noexcept;
  153. Allocator& get_alloc()
  154. {
  155. return m_alloc;
  156. }
  157. Replication* get_replication() const
  158. {
  159. return m_replication;
  160. }
  161. void set_replication(Replication* repl) noexcept
  162. {
  163. m_replication = repl;
  164. }
  165. void set_logger(const std::shared_ptr<util::Logger>& logger) noexcept;
  166. util::Logger* get_logger() const noexcept
  167. {
  168. return m_logger.get();
  169. }
  170. void create_new_history(Replication& repl) REQUIRES(!m_mutex);
  171. void create_new_history(std::unique_ptr<Replication> repl) REQUIRES(!m_mutex);
  172. const std::string& get_path() const noexcept
  173. {
  174. return m_db_path;
  175. }
  176. const char* get_encryption_key() const noexcept
  177. {
  178. return m_alloc.m_file.get_encryption_key();
  179. }
  180. #ifdef REALM_DEBUG
  181. /// Deprecated method, only called from a unit test
  182. ///
  183. /// Reserve disk space now to avoid allocation errors at a later
  184. /// point in time, and to minimize on-disk fragmentation. In some
  185. /// cases, less fragmentation translates into improved
  186. /// performance.
  187. ///
  188. /// When supported by the system, a call to this function will
  189. /// make the database file at least as big as the specified size,
  190. /// and cause space on the target device to be allocated (note
  191. /// that on many systems on-disk allocation is done lazily by
  192. /// default). If the file is already bigger than the specified
  193. /// size, the size will be unchanged, and on-disk allocation will
  194. /// occur only for the initial section that corresponds to the
  195. /// specified size.
  196. ///
  197. /// It is an error to call this function on an unattached shared
  198. /// group. Doing so will result in undefined behavior.
  199. void reserve(size_t size_in_bytes);
  200. #endif
  201. /// Querying for changes:
  202. ///
  203. /// NOTE:
  204. /// "changed" means that one or more commits has been made to the database
  205. /// since the presented transaction was made.
  206. ///
  207. /// No distinction is made between changes done by another process
  208. /// and changes done by another thread in the same process as the caller.
  209. ///
  210. /// Has db been changed ?
  211. bool has_changed(TransactionRef&);
  212. /// The calling thread goes to sleep until the database is changed, or
  213. /// until wait_for_change_release() is called. After a call to
  214. /// wait_for_change_release() further calls to wait_for_change() will return
  215. /// immediately. To restore the ability to wait for a change, a call to
  216. /// enable_wait_for_change() is required. Return true if the database has
  217. /// changed, false if it might have.
  218. bool wait_for_change(TransactionRef&);
  219. /// release any thread waiting in wait_for_change().
  220. void wait_for_change_release();
  221. /// re-enable waiting for change
  222. void enable_wait_for_change();
  223. // Transactions:
  224. using version_type = _impl::History::version_type;
  225. using VersionID = realm::VersionID;
  226. /// Returns the version of the latest snapshot.
  227. version_type get_version_of_latest_snapshot();
  228. VersionID get_version_id_of_latest_snapshot();
  229. /// Thrown by start_read() if the specified version does not correspond to a
  230. /// bound (AKA tethered) snapshot.
  231. struct BadVersion;
  232. /// Transactions are obtained from one of the following 3 methods:
  233. TransactionRef start_read(VersionID = VersionID()) REQUIRES(!m_mutex);
  234. TransactionRef start_frozen(VersionID = VersionID()) REQUIRES(!m_mutex);
  235. // If nonblocking is true and a write transaction is already active,
  236. // an invalid TransactionRef is returned.
  237. TransactionRef start_write(bool nonblocking = false) REQUIRES(!m_mutex);
  238. // ask for write mutex. Callback takes place when mutex has been acquired.
  239. // callback may occur on ANOTHER THREAD. Must not be called if write mutex
  240. // has already been acquired.
  241. void async_request_write_mutex(TransactionRef& tr, util::UniqueFunction<void()>&& when_acquired);
  242. // report statistics of last commit done on THIS DB.
  243. // The free space reported is what can be expected to be freed
  244. // by compact(). This may not correspond to the space which is free
  245. // at the point where get_stats() is called, since that will include
  246. // memory required to hold older versions of data, which still
  247. // needs to be available. The locked space is the amount of memory
  248. // that is free in current version, but being used in still live versions.
  249. // Notice that we will always have two live versions - the current and the
  250. // previous.
  251. void get_stats(size_t& free_space, size_t& used_space, size_t* locked_space = nullptr) const REQUIRES(!m_mutex);
  252. //@}
  253. enum TransactStage {
  254. transact_Ready,
  255. transact_Reading,
  256. transact_Writing,
  257. transact_Frozen,
  258. };
  259. enum class EvacStage { idle, evacuating, waiting, blocked };
  260. EvacStage get_evacuation_stage() const
  261. {
  262. return m_evac_stage;
  263. }
  264. /// Report the number of distinct versions stored in the database at the time
  265. /// of latest commit.
  266. /// Note: the database only cleans up versions as part of commit, so ending
  267. /// a read transaction will not immediately release any versions.
  268. uint_fast64_t get_number_of_versions();
  269. /// Get the size of the currently allocated slab area
  270. size_t get_allocated_size() const;
  271. /// Compact the database file.
  272. /// - The method will throw if called inside a transaction.
  273. /// - The method will throw if called in unattached state.
  274. /// - The method will return false if other DBs are accessing the
  275. /// database in which case compaction is not done. This is not
  276. /// necessarily an error.
  277. /// It will return true following successful compaction.
  278. /// While compaction is in progress, attempts by other
  279. /// threads or processes to open the database will wait.
  280. /// Likewise, attempts to create new transactions will wait.
  281. /// Be warned that resource requirements for compaction is proportional to
  282. /// the amount of live data in the database.
  283. /// Compaction works by writing the database contents to a temporary
  284. /// database file and then replacing the database with the temporary one.
  285. /// The name of the temporary file is formed by appending
  286. /// ".tmp_compaction_space" to the name of the database
  287. ///
  288. /// If the output_encryption_key is `none` then the file's existing key will
  289. /// be used (if any). If the output_encryption_key is nullptr, the resulting
  290. /// file will be unencrypted. Any other value will change the encryption of
  291. /// the file to the new 64 byte key.
  292. ///
  293. /// WARNING: Compact() is not thread-safe with respect to a concurrent close()
  294. bool compact(bool bump_version_number = false, util::Optional<const char*> output_encryption_key = util::none)
  295. REQUIRES(!m_mutex);
  296. void write_copy(StringData path, const char* output_encryption_key) REQUIRES(!m_mutex);
  297. #ifdef REALM_DEBUG
  298. void test_ringbuf();
  299. #endif
  300. /// The relation between accessors, threads and the Transaction object.
  301. ///
  302. /// Once created, accessors belong to a transaction and can only be used for
  303. /// access as long as that transaction is still active. Copies of accessors
  304. /// can be created in association with another transaction, the importing transaction,
  305. /// using said transactions import_copy_of() method. This process is called
  306. /// accessor import. Prior to Core 6, the corresponding mechanism was known
  307. /// as "handover".
  308. ///
  309. /// For TableViews, there are 3 forms of import determined by the PayloadPolicy.
  310. ///
  311. /// - with payload move: the payload imported ends up as a payload
  312. /// held by the accessor at the importing side. The accessor on the
  313. /// exporting side will rerun its query and generate a new payload, if
  314. /// TableView::sync_if_needed() is called. If the original payload was in
  315. /// sync at the exporting side, it will also be in sync at the importing
  316. /// side. This policy is selected by PayloadPolicy::Move
  317. ///
  318. /// - with payload copy: a copy of the payload is imported, so both the
  319. /// accessors on the exporting side *and* the accessors created at the
  320. /// importing side has their own payload. This is policy is selected
  321. /// by PayloadPolicy::Copy
  322. ///
  323. /// - without payload: the payload stays with the accessor on the exporting
  324. /// side. On the importing side, the new accessor is created without
  325. /// payload. A call to TableView::sync_if_needed() will trigger generation
  326. /// of a new payload. This policy is selected by PayloadPolicy::Stay.
  327. ///
  328. /// For all other (non-TableView) accessors, importing is done with payload
  329. /// copy, since the payload is trivial.
  330. ///
  331. /// Importing *without* payload is useful when you want to ship a tableview
  332. /// with its query for execution in a background thread. Handover with
  333. /// *payload move* is useful when you want to transfer the result back.
  334. ///
  335. /// Importing *without* payload or with payload copy is guaranteed *not* to
  336. /// change the accessors on the exporting side.
  337. ///
  338. /// Importing is generally *not* thread safe and should be carried out
  339. /// by the thread that "owns" the involved accessors. However, importing
  340. /// *is* thread-safe when it occurs from a *frozen* accessor.
  341. ///
  342. /// Importing is transitive:
  343. /// If the object being imported depends on other views
  344. /// (table- or link- ), those objects will be imported as well. The mode
  345. /// (payload copy, payload move, without payload) is applied
  346. /// recursively. Note: If you are importing a tableview dependent upon
  347. /// another tableview and using MutableSourcePayload::Move,
  348. /// you are on thin ice!
  349. ///
  350. /// On the importing side, the top-level accessor being created during
  351. /// import takes ownership of all other accessors (if any) being created as
  352. /// part of the import.
  353. // Try to grab an exclusive lock of the given realm path's lock file. If the lock
  354. // can be acquired, the callback will be executed with the lock and then return true.
  355. // Otherwise false will be returned directly.
  356. // The lock taken precludes races with other threads or processes accessing the
  357. // files through a DB.
  358. // It is safe to delete/replace realm files inside the callback.
  359. // WARNING: It is not safe to delete the lock file in the callback.
  360. using CallbackWithLock = util::FunctionRef<void(const std::string& realm_path)>;
  361. static bool call_with_lock(const std::string& realm_path, CallbackWithLock&& callback);
  362. enum CoreFileType : uint8_t {
  363. Lock,
  364. Storage,
  365. Management,
  366. Note,
  367. Log,
  368. };
  369. /// Get the path for the given type of file for a base Realm file path.
  370. /// \param realm_path The path for the main Realm file.
  371. /// \param type The type of associated file to get the path for.
  372. /// \return The base path with the appropriate type-specific suffix appended to it.
  373. static std::string get_core_file(const std::string& realm_path, CoreFileType type);
  374. /// Delete a Realm file and all associated control files.
  375. ///
  376. /// This function does not perform any locking and requires external
  377. /// synchronization to ensure that it is safe to call. If called within
  378. /// call_with_lock(), \p delete_lockfile must be false as the lockfile is not
  379. /// safe to delete while it is in use.
  380. ///
  381. /// \param base_path The Realm file to delete, which auxiliary file paths will be derived from.
  382. /// \param[out] did_delete_realm If non-null, will be set to true if the Realm file was deleted (even if a
  383. /// subsequent deletion failed)
  384. /// \param delete_lockfile By default the lock file is not deleted as it is unsafe to
  385. /// do so. If this is true, the lock file is deleted along with the other files.
  386. static void delete_files(const std::string& base_path, bool* did_delete_realm = nullptr,
  387. bool delete_lockfile = false);
  388. /// Mark this DB as the sync agent for the file.
  389. /// \throw MultipleSyncAgents if another DB is already the sync agent.
  390. void claim_sync_agent();
  391. void release_sync_agent();
  392. /// Returns true if there are threads waiting to acquire the write lock, false otherwise.
  393. /// To be used only when already holding the lock.
  394. bool other_writers_waiting_for_lock() const;
  395. struct CommitListener {
  396. virtual ~CommitListener() = default;
  397. virtual void on_commit(version_type new_version) = 0;
  398. };
  399. void add_commit_listener(CommitListener*);
  400. void remove_commit_listener(CommitListener*);
  401. private:
  402. class AsyncCommitHelper;
  403. class VersionManager;
  404. class EncryptionMarkerObserver;
  405. class FileVersionManager;
  406. class InMemoryVersionManager;
  407. struct SharedInfo;
  408. struct ReadCount;
  409. struct ReadLockInfo {
  410. enum Type { Frozen, Live, Full };
  411. uint_fast64_t m_version = std::numeric_limits<version_type>::max();
  412. uint_fast32_t m_reader_idx = 0;
  413. ref_type m_top_ref = 0;
  414. size_t m_file_size = 0;
  415. Type m_type = Live;
  416. // a little helper
  417. static std::unique_ptr<ReadLockInfo> make_fake(ref_type top_ref, size_t file_size)
  418. {
  419. auto res = std::make_unique<ReadLockInfo>();
  420. res->m_top_ref = top_ref;
  421. res->m_file_size = file_size;
  422. res->m_version = 1;
  423. return res;
  424. }
  425. void check() const noexcept
  426. {
  427. REALM_ASSERT_RELEASE_EX((m_top_ref & 7) == 0 && m_top_ref < m_file_size, m_version, m_reader_idx,
  428. m_top_ref, m_file_size);
  429. }
  430. };
  431. class ReadLockGuard;
  432. // Member variables
  433. mutable util::CheckedMutex m_mutex;
  434. int m_transaction_count GUARDED_BY(m_mutex) = 0;
  435. SlabAlloc m_alloc;
  436. std::unique_ptr<Replication> m_history;
  437. std::unique_ptr<VersionManager> m_version_manager;
  438. std::unique_ptr<EncryptionMarkerObserver> m_marker_observer;
  439. Replication* m_replication = nullptr;
  440. size_t m_free_space GUARDED_BY(m_mutex) = 0;
  441. size_t m_locked_space GUARDED_BY(m_mutex) = 0;
  442. size_t m_used_space GUARDED_BY(m_mutex) = 0;
  443. std::vector<ReadLockInfo> m_local_locks_held GUARDED_BY(m_mutex); // tracks all read locks held by this DB
  444. std::atomic<EvacStage> m_evac_stage = EvacStage::idle;
  445. util::File m_file;
  446. util::File::Map<SharedInfo> m_file_map; // Never remapped, provides access to everything but the ringbuffer
  447. std::unique_ptr<SharedInfo> m_in_memory_info;
  448. SharedInfo* m_info = nullptr;
  449. bool m_wait_for_change_enabled = true; // Initially wait_for_change is enabled
  450. bool m_write_transaction_open GUARDED_BY(m_mutex) = false;
  451. std::string m_db_path;
  452. int m_file_format_version = 0;
  453. util::InterprocessMutex m_writemutex;
  454. std::unique_ptr<ReadLockInfo> m_fake_read_lock_if_immutable;
  455. util::InterprocessMutex m_controlmutex;
  456. util::InterprocessMutex m_versionlist_mutex;
  457. util::InterprocessCondVar m_new_commit_available;
  458. util::InterprocessCondVar m_pick_next_writer;
  459. std::function<void(int, int)> m_upgrade_callback;
  460. std::unique_ptr<AsyncCommitHelper> m_commit_helper;
  461. std::shared_ptr<util::Logger> m_logger;
  462. std::mutex m_commit_listener_mutex;
  463. std::vector<CommitListener*> m_commit_listeners;
  464. bool m_is_sync_agent = false;
  465. // Id for this DB to be used in logging. We will just use some bits from the pointer.
  466. // The path cannot be used as this would not allow us to distinguish between two DBs opening
  467. // the same realm.
  468. unsigned m_log_id;
  469. /// Attach this DB instance to the specified database file.
  470. ///
  471. /// While at least one instance of DB exists for a specific
  472. /// database file, a "lock" file will be present too. The lock file will be
  473. /// placed in the same directory as the database file, and its name will be
  474. /// derived by appending ".lock" to the name of the database file.
  475. ///
  476. /// When multiple DB instances refer to the same file, they must
  477. /// specify the same durability level, otherwise an exception will be
  478. /// thrown.
  479. ///
  480. /// \param file Filesystem path to a Realm database file.
  481. ///
  482. /// \param no_create If the database file does not already exist, it will be
  483. /// created (unless this is set to true.) When multiple threads are involved,
  484. /// it is safe to let the first thread, that gets to it, create the file.
  485. ///
  486. /// \param options See DBOptions for details of each option.
  487. /// Sensible defaults are provided if this parameter is left out.
  488. ///
  489. /// \throw FileAccessError If the file could not be opened. If the
  490. /// reason corresponds to one of the exception types that are derived from
  491. /// FileAccessError, the derived exception type is thrown. Note that
  492. /// InvalidDatabase is among these derived exception types.
  493. ///
  494. /// \throw FileFormatUpgradeRequired if \a DBOptions::allow_upgrade
  495. /// is `false` and an upgrade is required.
  496. ///
  497. /// \throw LogicError if both DBOptions::allow_upgrade and is_immutable is true.
  498. /// \throw UnsupportedFileFormatVersion if the file format version or
  499. /// history schema version is one which this version of Realm does not know
  500. /// how to migrate from.
  501. void open(const std::string& file, bool no_create = false, const DBOptions& options = DBOptions())
  502. REQUIRES(!m_mutex);
  503. void open(BinaryData, bool take_ownership = true) REQUIRES(!m_mutex);
  504. void open(Replication&, const std::string& file, const DBOptions& options = DBOptions()) REQUIRES(!m_mutex);
  505. void open(Replication& repl, const DBOptions options = DBOptions()) REQUIRES(!m_mutex);
  506. void do_open(const std::string& file, bool no_create, const DBOptions& options);
  507. Replication* const* get_repl() const noexcept
  508. {
  509. return &m_replication;
  510. }
  511. // Ring buffer management
  512. bool ringbuf_is_empty() const noexcept;
  513. size_t ringbuf_size() const noexcept;
  514. size_t ringbuf_capacity() const noexcept;
  515. bool ringbuf_is_first(size_t ndx) const noexcept;
  516. void ringbuf_remove_first() noexcept;
  517. size_t ringbuf_find(uint64_t version) const noexcept;
  518. ReadCount& ringbuf_get(size_t ndx) noexcept;
  519. ReadCount& ringbuf_get_first() noexcept;
  520. ReadCount& ringbuf_get_last() noexcept;
  521. void ringbuf_put(const ReadCount& v);
  522. void ringbuf_expand();
  523. /// Grab a read lock on the snapshot associated with the specified
  524. /// version. If `version_id == VersionID()`, a read lock will be grabbed on
  525. /// the latest available snapshot. Fails if the snapshot is no longer
  526. /// available.
  527. ///
  528. /// As a side effect update memory mapping to ensure that the ringbuffer
  529. /// entries referenced in the readlock info is accessible.
  530. ReadLockInfo grab_read_lock(ReadLockInfo::Type, VersionID) REQUIRES(!m_mutex);
  531. // Release a specific read lock. The read lock MUST have been obtained by a
  532. // call to grab_read_lock().
  533. void release_read_lock(ReadLockInfo&) noexcept REQUIRES(!m_mutex);
  534. void do_release_read_lock(ReadLockInfo&) noexcept REQUIRES(m_mutex);
  535. // Stop tracking a read lock without actually releasing it.
  536. void leak_read_lock(ReadLockInfo&) noexcept REQUIRES(!m_mutex);
  537. // Release all read locks held by this DB object. After release, further calls to
  538. // release_read_lock for locks already released must be avoided.
  539. void release_all_read_locks() noexcept REQUIRES(!m_mutex);
  540. /// return true if write transaction can commence, false otherwise.
  541. bool do_try_begin_write() REQUIRES(!m_mutex);
  542. void do_begin_write() REQUIRES(!m_mutex);
  543. void do_begin_possibly_async_write() REQUIRES(!m_mutex);
  544. version_type do_commit(Transaction&, bool commit_to_disk = true) REQUIRES(!m_mutex);
  545. void do_end_write() noexcept REQUIRES(!m_mutex);
  546. void end_write_on_correct_thread() noexcept REQUIRES(!m_mutex);
  547. // Must be called only by someone that has a lock on the write mutex.
  548. void low_level_commit(uint_fast64_t new_version, Transaction& transaction, bool commit_to_disk = true)
  549. REQUIRES(!m_mutex);
  550. void do_async_commits();
  551. /// Upgrade file format and/or history schema
  552. void upgrade_file_format(bool allow_file_format_upgrade, int target_file_format_version,
  553. int current_hist_schema_version, int target_hist_schema_version) REQUIRES(!m_mutex);
  554. int get_file_format_version() const noexcept;
  555. /// finish up the process of starting a write transaction. Internal use only.
  556. void finish_begin_write() REQUIRES(!m_mutex);
  557. void reset_free_space_tracking()
  558. {
  559. m_alloc.reset_free_space_tracking();
  560. }
  561. void close_internal(std::unique_lock<util::InterprocessMutex>, bool allow_open_read_transactions)
  562. REQUIRES(!m_mutex);
  563. void async_begin_write(util::UniqueFunction<void()> fn);
  564. void async_end_write();
  565. void async_sync_to_disk(util::UniqueFunction<void()> fn);
  566. friend class SlabAlloc;
  567. friend class Transaction;
  568. };
  569. inline void DB::get_stats(size_t& free_space, size_t& used_space, size_t* locked_space) const
  570. {
  571. util::CheckedLockGuard lock(m_mutex);
  572. free_space = m_free_space;
  573. used_space = m_used_space;
  574. if (locked_space) {
  575. *locked_space = m_locked_space;
  576. }
  577. }
  578. class DisableReplication {
  579. public:
  580. DisableReplication(Transaction& t);
  581. ~DisableReplication();
  582. private:
  583. Transaction& m_tr;
  584. DBRef m_owner;
  585. Replication* m_repl;
  586. DB::version_type m_version;
  587. };
  588. // Implementation:
  589. struct DB::BadVersion : Exception {
  590. BadVersion(version_type version)
  591. : Exception(ErrorCodes::BadVersion,
  592. util::format("Unable to lock version %1 as it does not exist or has been cleaned up.", version))
  593. {
  594. }
  595. };
  596. inline bool DB::is_attached() const noexcept
  597. {
  598. return bool(m_fake_read_lock_if_immutable) || m_info;
  599. }
  600. class DB::ReadLockGuard {
  601. public:
  602. ReadLockGuard(DB& shared_group, ReadLockInfo& read_lock) noexcept
  603. : m_db(shared_group)
  604. , m_read_lock(&read_lock)
  605. {
  606. }
  607. ~ReadLockGuard() noexcept
  608. {
  609. if (m_read_lock)
  610. m_db.release_read_lock(*m_read_lock);
  611. }
  612. void release() noexcept
  613. {
  614. m_read_lock = 0;
  615. }
  616. private:
  617. DB& m_db;
  618. ReadLockInfo* m_read_lock;
  619. };
  620. inline int DB::get_file_format_version() const noexcept
  621. {
  622. return m_file_format_version;
  623. }
  624. } // namespace realm
  625. #endif // REALM_DB_HPP