/************************************************************************* * * Copyright 2016 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_IMPL_CONT_TRANSACT_HIST_HPP #define REALM_IMPL_CONT_TRANSACT_HIST_HPP #include <cstdint> #include <memory> #include <realm/column_binary.hpp> #include <realm/version_id.hpp> namespace realm { class Group; class BinaryIterator; namespace _impl { /// Read-only access to history of changesets as needed to enable continuous /// transactions. class History { public: using version_type = VersionID::version_type; virtual ~History() noexcept {} /// May be called during any transaction /// /// It is a precondition for calls to this function that the reader view is /// updated - that is, the mapping is updated to provide full visibility to /// the file. /// virtual void update_from_ref_and_version(ref_type, version_type) = 0; virtual void update_from_parent(version_type version) = 0; /// Get all changesets between the specified versions. References to those /// changesets will be made available in successive entries of `buffer`. The /// number of retrieved changesets is exactly `end_version - /// begin_version`. If this number is greater than zero, the changeset made /// available in `buffer[0]` is the one that brought the database from /// `begin_version` to `begin_version + 1`. /// /// It is an error to specify a version (for \a begin_version or \a /// end_version) that is outside the range [V,W] where V is the version that /// immediately precedes the first changeset available in the history as the /// history appears in the **latest** available snapshot, and W is the /// version that immediately succeeds the last changeset available in the /// history as the history appears in the snapshot bound to the **current** /// transaction. This restriction is necessary to allow for different kinds /// of implementations of the history (separate standalone history or /// history as part of versioned Realm state). /// /// The callee retains ownership of the memory referenced by those entries, /// i.e., the memory referenced by `buffer[i].changeset` is **not** handed /// over to the caller. /// /// This function may be called only during a transaction (prior to /// initiation of commit operation), and only after a successful invocation /// of update_early_from_top_ref(). In that case, the caller may assume that /// the memory references stay valid for the remainder of the transaction /// (up until initiation of the commit operation). virtual void get_changesets(version_type begin_version, version_type end_version, BinaryIterator* buffer) const noexcept = 0; /// \brief Specify the version of the oldest bound snapshot. /// /// This function must be called by the associated SharedGroup object during /// each successfully committed write transaction. It must be called before /// the transaction is finalized (Replication::finalize_commit()) or aborted /// (Replication::abort_transact()), but after the initiation of the commit /// operation (Replication::prepare_commit()). This allows history /// implementations to add new history entries before trimming off old ones, /// and this, in turn, guarantees that the history never becomes empty, /// except in the initial empty Realm state. /// /// The caller must pass the version (\a version) of the oldest snapshot /// that is currently (or was recently) bound via a transaction of the /// current session. This gives the history implementation an opportunity to /// trim off leading (early) history entries. /// /// Since this function must be called during a write transaction, there /// will always be at least one snapshot that is currently bound via a /// transaction. /// /// The caller must guarantee that the passed version (\a version) is less /// than or equal to `begin_version` in all future invocations of /// get_changesets(). /// /// The caller is allowed to pass a version that is less than the version /// passed in a preceding invocation. /// /// This function should be called as late as possible, to maximize the /// trimming opportunity, but at a time where the write transaction is still /// open for additional modifications. This is necessary because some types /// of histories are stored inside the Realm file. virtual void set_oldest_bound_version(version_type version) = 0; virtual void verify() const = 0; /// Returns true if all local changes has been integrated on the server. /// The history is effectively clean virtual bool no_pending_local_changes(version_type) const { return true; } virtual void set_group(Group* group, bool updated = false) { m_group = group; m_updated = updated; } void ensure_updated(version_type version) const { if (!m_updated) { const_cast<History*>(this)->update_from_parent(version); m_updated = true; } } protected: Group* m_group = nullptr; private: mutable bool m_updated = false; }; } // namespace _impl } // namespace realm #endif // REALM_IMPL_CONTINUOUS_TRANSACTIONS_HISTORY_HPP