X-Git-Url: https://git.mdrn.pl/wl-app.git/blobdiff_plain/53b27422d140022594fc241cca91c3183be57bca..48b2fe9f7c2dc3d9aeaaa6dbfb27c7da4f3235ff:/iOS/Pods/Realm/include/shared_realm.hpp diff --git a/iOS/Pods/Realm/include/shared_realm.hpp b/iOS/Pods/Realm/include/shared_realm.hpp new file mode 100644 index 0000000..67a0d59 --- /dev/null +++ b/iOS/Pods/Realm/include/shared_realm.hpp @@ -0,0 +1,479 @@ +//////////////////////////////////////////////////////////////////////////// +// +// Copyright 2015 Realm Inc. +// +// 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 REALM_REALM_HPP +#define REALM_REALM_HPP + +#include "execution_context_id.hpp" +#include "schema.hpp" + +#include +#include + +#if REALM_ENABLE_SYNC +#include +#endif + +#include + +namespace realm { +class BindingContext; +class Group; +class Realm; +class Replication; +class SharedGroup; +class StringData; +class Table; +struct SyncConfig; +class ThreadSafeReferenceBase; +template class ThreadSafeReference; +struct VersionID; +template class BasicRow; +typedef BasicRow Row; +typedef std::shared_ptr SharedRealm; +typedef std::weak_ptr WeakRealm; + +namespace _impl { + class AnyHandover; + class CollectionNotifier; + class RealmCoordinator; + class RealmFriend; +} + +// How to handle update_schema() being called on a file which has +// already been initialized with a different schema +enum class SchemaMode : uint8_t { + // If the schema version has increased, automatically apply all + // changes, then call the migration function. + // + // If the schema version has not changed, verify that the only + // changes are to add new tables and add or remove indexes, and then + // apply them if so. Does not call the migration function. + // + // This mode does not automatically remove tables which are not + // present in the schema that must be manually done in the migration + // function, to support sharing a Realm file between processes using + // different class subsets. + // + // This mode allows using schemata with different subsets of tables + // on different threads, but the tables which are shared must be + // identical. + Automatic, + + // Open the file in immutable mode. Schema version must match the + // version in the file, and all tables present in the file must + // exactly match the specified schema, except for indexes. Tables + // are allowed to be missing from the file. + // WARNING: This is the original ReadOnly mode. + Immutable, + + // Open the Realm in read-only mode, transactions are not allowed to + // be performed on the Realm instance. The schema of the existing Realm + // file won't be changed through this Realm instance. Extra tables and + // extra properties are allowed in the existing Realm schema. The + // difference of indexes is allowed as well. Other schema differences + // than those will cause an exception. This is different from Immutable + // mode, sync Realm can be opened with ReadOnly mode. Changes + // can be made to the Realm file through another writable Realm instance. + // Thus, notifications are also allowed in this mode. + // FIXME: Rename this to ReadOnly + // WARNING: This is not the original ReadOnly mode. The original ReadOnly + // has been renamed to Immutable. + ReadOnlyAlternative, + + // If the schema version matches and the only schema changes are new + // tables and indexes being added or removed, apply the changes to + // the existing file. + // Otherwise delete the file and recreate it from scratch. + // The migration function is not used. + // + // This mode allows using schemata with different subsets of tables + // on different threads, but the tables which are shared must be + // identical. + ResetFile, + + // The only changes allowed are to add new tables, add columns to + // existing tables, and to add or remove indexes from existing + // columns. Extra tables not present in the schema are ignored. + // Indexes are only added to or removed from existing columns if the + // schema version is greater than the existing one (and unlike other + // modes, the schema version is allowed to be less than the existing + // one). + // The migration function is not used. + // + // This mode allows updating the schema with additive changes even + // if the Realm is already open on another thread. + Additive, + + // Verify that the schema version has increased, call the migraiton + // function, and then verify that the schema now matches. + // The migration function is mandatory for this mode. + // + // This mode requires that all threads and processes which open a + // file use identical schemata. + Manual +}; + +class Realm : public std::enable_shared_from_this { +public: + // A callback function to be called during a migration for Automatic and + // Manual schema modes. It is passed a SharedRealm at the version before + // the migration, the SharedRealm in the migration, and a mutable reference + // to the realm's Schema. Updating the schema with changes made within the + // migration function is only required if you wish to use the ObjectStore + // functions which take a Schema from within the migration function. + using MigrationFunction = std::function; + + // A callback function to be called the first time when a schema is created. + // It is passed a SharedRealm which is in a write transaction with the schema + // initialized. So it is possible to create some initial objects inside the callback + // with the given SharedRealm. Those changes will be committed together with the + // schema creation in a single transaction. + using DataInitializationFunction = std::function; + + // A callback function called when opening a SharedRealm when no cached + // version of this Realm exists. It is passed the total bytes allocated for + // the file (file size) and the total bytes used by data in the file. + // Return `true` to indicate that an attempt to compact the file should be made + // if it is possible to do so. + // Won't compact the file if another process is accessing it. + // + // WARNING / FIXME: compact() should NOT be exposed publicly on Windows + // because it's not crash safe! It may corrupt your database if something fails + using ShouldCompactOnLaunchFunction = std::function; + + struct Config { + // Path and binary data are mutually exclusive + std::string path; + BinaryData realm_data; + // User-supplied encryption key. Must be either empty or 64 bytes. + std::vector encryption_key; + + bool in_memory = false; + SchemaMode schema_mode = SchemaMode::Automatic; + + // Optional schema for the file. + // If the schema and schema version are supplied, update_schema() is + // called with the supplied schema, version and migration function when + // the Realm is actually opened and not just retrieved from the cache + util::Optional schema; + uint64_t schema_version = -1; + MigrationFunction migration_function; + + DataInitializationFunction initialization_function; + + // A callback function called when opening a SharedRealm when no cached + // version of this Realm exists. It is passed the total bytes allocated for + // the file (file size) and the total bytes used by data in the file. + // Return `true` to indicate that an attempt to compact the file should be made + // if it is possible to do so. + // Won't compact the file if another process is accessing it. + // + // WARNING / FIXME: compact() should NOT be exposed publicly on Windows + // because it's not crash safe! It may corrupt your database if something fails + ShouldCompactOnLaunchFunction should_compact_on_launch_function; + + // WARNING: The original read_only() has been renamed to immutable(). + bool immutable() const { return schema_mode == SchemaMode::Immutable; } + // FIXME: Rename this to read_only(). + bool read_only_alternative() const { return schema_mode == SchemaMode::ReadOnlyAlternative; } + + // The following are intended for internal/testing purposes and + // should not be publicly exposed in binding APIs + + // If false, always return a new Realm instance, and don't return + // that Realm instance for other requests for a cached Realm. Useful + // for dynamic Realms and for tests that need multiple instances on + // one thread + bool cache = true; + // Throw an exception rather than automatically upgrading the file + // format. Used by the browser to warn the user that it'll modify + // the file. + bool disable_format_upgrade = false; + // Disable the background worker thread for producing change + // notifications. Useful for tests for those notifications so that + // everything can be done deterministically on one thread, and + // speeds up tests that don't need notifications. + bool automatic_change_notifications = true; + + // The identifier of the abstract execution context in which this Realm will be used. + // If unset, the current thread's identifier will be used to identify the execution context. + util::Optional execution_context; + + /// A data structure storing data used to configure the Realm for sync support. + std::shared_ptr sync_config; + + // FIXME: Realm Java manages sync at the Java level, so it needs to create Realms using the sync history + // format. + bool force_sync_history = false; + }; + + // Get a cached Realm or create a new one if no cached copies exists + // Caching is done by path - mismatches for in_memory, schema mode or + // encryption key will raise an exception. + static SharedRealm get_shared_realm(Config config); + + // Updates a Realm to a given schema, using the Realm's pre-set schema mode. + void update_schema(Schema schema, uint64_t version=0, + MigrationFunction migration_function=nullptr, + DataInitializationFunction initialization_function=nullptr, + bool in_transaction=false); + + // Set the schema used for this Realm, but do not update the file's schema + // if it is not compatible (and instead throw an error). + // Cannot be called multiple times on a single Realm instance or an instance + // which has already had update_schema() called on it. + void set_schema_subset(Schema schema); + + // Read the schema version from the file specified by the given config, or + // ObjectStore::NotVersioned if it does not exist + static uint64_t get_schema_version(Config const& config); + + Config const& config() const { return m_config; } + Schema const& schema() const { return m_schema; } + uint64_t schema_version() const { return m_schema_version; } + + void begin_transaction(); + void commit_transaction(); + void cancel_transaction(); + bool is_in_transaction() const noexcept; + bool is_in_read_transaction() const { return !!m_group; } + + bool is_in_migration() const noexcept { return m_in_migration; } + + bool refresh(); + void set_auto_refresh(bool auto_refresh) { m_auto_refresh = auto_refresh; } + bool auto_refresh() const { return m_auto_refresh; } + void notify(); + + void invalidate(); + + // WARNING / FIXME: compact() should NOT be exposed publicly on Windows + // because it's not crash safe! It may corrupt your database if something fails + bool compact(); + void write_copy(StringData path, BinaryData encryption_key); + OwnedBinaryData write_copy(); + + void verify_thread() const; + void verify_in_write() const; + void verify_open() const; + + bool can_deliver_notifications() const noexcept; + + // Close this Realm and remove it from the cache. Continuing to use a + // Realm after closing it will throw ClosedRealmException + void close(); + bool is_closed() const { return !m_read_only_group && !m_shared_group; } + + // returns the file format version upgraded from if an upgrade took place + util::Optional file_format_upgraded_from_version() const; + + Realm(const Realm&) = delete; + Realm& operator=(const Realm&) = delete; + Realm(Realm&&) = delete; + Realm& operator=(Realm&&) = delete; + ~Realm(); + + // Construct a thread safe reference, pinning the version in the process. + template + ThreadSafeReference obtain_thread_safe_reference(T const& value); + + // Advances the read transaction to the latest version, resolving the thread safe reference and unpinning the + // version in the process. + template + T resolve_thread_safe_reference(ThreadSafeReference reference); + + static SharedRealm make_shared_realm(Config config, std::shared_ptr<_impl::RealmCoordinator> coordinator = nullptr) { + struct make_shared_enabler : public Realm { + make_shared_enabler(Config config, std::shared_ptr<_impl::RealmCoordinator> coordinator) + : Realm(std::move(config), std::move(coordinator)) { } + }; + return std::make_shared(std::move(config), std::move(coordinator)); + } + + // Expose some internal functionality to other parts of the ObjectStore + // without making it public to everyone + class Internal { + friend class _impl::CollectionNotifier; + friend class _impl::RealmCoordinator; + friend class ThreadSafeReferenceBase; + friend class GlobalNotifier; + friend class TestHelper; + + // ResultsNotifier and ListNotifier need access to the SharedGroup + // to be able to call the handover functions, which are not very wrappable + static const std::unique_ptr& get_shared_group(Realm& realm) { return realm.m_shared_group; } + + // CollectionNotifier needs to be able to access the owning + // coordinator to wake up the worker thread when a callback is + // added, and coordinators need to be able to get themselves from a Realm + static _impl::RealmCoordinator& get_coordinator(Realm& realm) { return *realm.m_coordinator; } + + static void begin_read(Realm&, VersionID); + }; + + static void open_with_config(const Config& config, + std::unique_ptr& history, + std::unique_ptr& shared_group, + std::unique_ptr& read_only_group, + Realm* realm); + +private: + // `enable_shared_from_this` is unsafe with public constructors; use `make_shared_realm` instead + Realm(Config config, std::shared_ptr<_impl::RealmCoordinator> coordinator); + + Config m_config; + AnyExecutionContextID m_execution_context; + bool m_auto_refresh = true; + + std::unique_ptr m_history; + std::unique_ptr m_shared_group; + std::unique_ptr m_read_only_group; + + Group *m_group = nullptr; + + uint64_t m_schema_version; + Schema m_schema; + util::Optional m_new_schema; + uint64_t m_schema_transaction_version = -1; + + // FIXME: this should be a Dynamic schema mode instead, but only once + // that's actually fully working + bool m_dynamic_schema = true; + + std::shared_ptr<_impl::RealmCoordinator> m_coordinator; + + // File format versions populated when a file format upgrade takes place during realm opening + int upgrade_initial_version = 0, upgrade_final_version = 0; + + // True while sending the notifications caused by advancing the read + // transaction version, to avoid recursive notifications where possible + bool m_is_sending_notifications = false; + + // True while we're performing a schema migration via this Realm instance + // to allow for different behavior (such as allowing modifications to + // primary key values) + bool m_in_migration = false; + + void begin_read(VersionID); + + void set_schema(Schema const& reference, Schema schema); + bool reset_file(Schema& schema, std::vector& changes_required); + bool schema_change_needs_write_transaction(Schema& schema, std::vector& changes, uint64_t version); + Schema get_full_schema(); + + // Ensure that m_schema and m_schema_version match that of the current + // version of the file + void read_schema_from_group_if_needed(); + + void add_schema_change_handler(); + void cache_new_schema(); + void notify_schema_changed(); + +public: + std::unique_ptr m_binding_context; + + // FIXME private + Group& read_group(); + + Replication *history() { return m_history.get(); } + + friend class _impl::RealmFriend; +}; + +class RealmFileException : public std::runtime_error { +public: + enum class Kind { + /** Thrown for any I/O related exception scenarios when a realm is opened. */ + AccessError, + /** Thrown if the history type of the on-disk Realm is unexpected or incompatible. */ + BadHistoryError, + /** Thrown if the user does not have permission to open or create + the specified file in the specified access mode when the realm is opened. */ + PermissionDenied, + /** Thrown if create_Always was specified and the file did already exist when the realm is opened. */ + Exists, + /** Thrown if no_create was specified and the file was not found when the realm is opened. */ + NotFound, + /** Thrown if the database file is currently open in another + process which cannot share with the current process due to an + architecture mismatch. */ + IncompatibleLockFile, + /** Thrown if the file needs to be upgraded to a new format, but upgrades have been explicitly disabled. */ + FormatUpgradeRequired, + /** Thrown if the local copy of a synced Realm file was created using an incompatible version of Realm. + The specified path is where the local file was moved for recovery. */ + IncompatibleSyncedRealm, + }; + RealmFileException(Kind kind, std::string path, std::string message, std::string underlying) + : std::runtime_error(std::move(message)), m_kind(kind), m_path(std::move(path)), m_underlying(std::move(underlying)) {} + Kind kind() const { return m_kind; } + const std::string& path() const { return m_path; } + const std::string& underlying() const { return m_underlying; } + +private: + Kind m_kind; + std::string m_path; + std::string m_underlying; +}; + +class MismatchedConfigException : public std::logic_error { +public: + MismatchedConfigException(StringData message, StringData path); +}; + +class MismatchedRealmException : public std::logic_error { +public: + MismatchedRealmException(StringData message); +}; + +class InvalidTransactionException : public std::logic_error { +public: + InvalidTransactionException(std::string message) : std::logic_error(message) {} +}; + +class IncorrectThreadException : public std::logic_error { +public: + IncorrectThreadException() : std::logic_error("Realm accessed from incorrect thread.") {} +}; + +class ClosedRealmException : public std::logic_error { +public: + ClosedRealmException() : std::logic_error("Cannot access realm that has been closed.") {} +}; + +class UninitializedRealmException : public std::runtime_error { +public: + UninitializedRealmException(std::string message) : std::runtime_error(message) {} +}; + +class InvalidEncryptionKeyException : public std::logic_error { +public: + InvalidEncryptionKeyException() : std::logic_error("Encryption key must be 64 bytes.") {} +}; + +// FIXME Those are exposed for Java async queries, mainly because of handover related methods. +class _impl::RealmFriend { +public: + static SharedGroup& get_shared_group(Realm& realm); + static Group& read_group_to(Realm& realm, VersionID version); +}; + +} // namespace realm + +#endif /* defined(REALM_REALM_HPP) */