X-Git-Url: https://git.mdrn.pl/wl-app.git/blobdiff_plain/53b27422d140022594fc241cca91c3183be57bca..48b2fe9f7c2dc3d9aeaaa6dbfb27c7da4f3235ff:/iOS/Pods/Realm/include/core/realm/sync/transform.hpp diff --git a/iOS/Pods/Realm/include/core/realm/sync/transform.hpp b/iOS/Pods/Realm/include/core/realm/sync/transform.hpp new file mode 100644 index 0000000..33c6624 --- /dev/null +++ b/iOS/Pods/Realm/include/core/realm/sync/transform.hpp @@ -0,0 +1,315 @@ +/************************************************************************* + * + * REALM CONFIDENTIAL + * __________________ + * + * [2011] - [2015] Realm Inc + * All Rights Reserved. + * + * NOTICE: All information contained herein is, and remains + * the property of Realm Incorporated and its suppliers, + * if any. The intellectual and technical concepts contained + * herein are proprietary to Realm Incorporated + * and its suppliers and may be covered by U.S. and Foreign Patents, + * patents in process, and are protected by trade secret or copyright law. + * Dissemination of this information or reproduction of this material + * is strictly forbidden unless prior written permission is obtained + * from Realm Incorporated. + * + **************************************************************************/ + +#ifndef REALM_SYNC_TRANSFORM_HPP +#define REALM_SYNC_TRANSFORM_HPP + +#include + +#include +#include +#include +#include + +namespace realm { +namespace sync { + +struct Changeset; + +/// Represents an entry in the history of changes in a sync-enabled Realm +/// file. Server and client use different history formats, but this class is +/// used both on the server and the client side. Each history entry corresponds +/// to a version of the Realm state. For server and client-side histories, these +/// versions are referred to as *server versions* and *client versions* +/// respectively. These versions may, or may not correspond to Realm snapshot +/// numbers (on the server-side they currently do not). +/// +/// FIXME: Move this class into a separate header +/// (``). +class HistoryEntry { +public: + using timestamp_type = uint_fast64_t; + using file_ident_type = uint_fast64_t; + using version_type = _impl::History::version_type; + + /// The time of origination of the changes referenced by this history entry, + /// meassured as the number of milliseconds since 2015-01-01T00:00:00Z, not + /// including leap seconds. For changes of local origin, this is the local + /// time at the point when the local transaction was committed. For changes + /// of remote origin, it is the remote time of origin at the client + /// identified by `origin_client_file_ident`. + timestamp_type origin_timestamp; + + /// For changes of local origin, this is the identifier of the local + /// file. On the client side, the special value, zero, is used as a stand-in + /// for the actual file identifier. This is necessary because changes may + /// occur on the client-side before it obtains the the actual identifier + /// from the server. Depending on context, the special value, zero, will, or + /// will not have been replaced by the actual local file identifier. + /// + /// For changes of remote origin, this is the identifier of the file in the + /// context of which this change originated. This may be a client, or a + /// server-side file. For example, when a change "travels" from client file + /// A with identifier 2, through the server, to client file B with + /// identifier 3, then `origin_client_file_ident` will be 2 on the server + /// and in client file A. On the other hand, if the change originates on the + /// server, and the server-side file identifier is 1, then + /// `origin_client_file_ident` will be 1 in both client files. + /// + /// FIXME: Rename this member to `origin_file_ident`. It is no longer + /// necessarily a client-side file. + file_ident_type origin_client_file_ident; + + /// For changes of local origin on the client side, this is the last server + /// version integrated locally prior to this history entry. In other words, + /// it is a copy of `remote_version` of the last preceding history entry + /// that carries changes of remote origin, or zero if there is no such + /// preceding history entry. + /// + /// For changes of local origin on the server-side, this is always zero. + /// + /// For changes of remote origin, this is the version produced within the + /// remote-side Realm file by the change that gave rise to this history + /// entry. The remote-side Realm file is not always the same Realm file from + /// which the change originated. On the client side, the remote side is + /// always the server side, and `remote_version` is always a server version + /// (since clients do not speak directly to each other). On the server side, + /// the remote side is always a client side, and `remote_version` is always + /// a client version. + version_type remote_version; + + /// Referenced memory is not owned by this class. + ChunkedBinaryData changeset; +}; + + +/// The interface between the sync history and the operational transformer +/// (Transformer). +class TransformHistory { +public: + using timestamp_type = HistoryEntry::timestamp_type; + using file_ident_type = HistoryEntry::file_ident_type; + using version_type = HistoryEntry::version_type; + + /// Get the first history entry where the produced version is greater than + /// `begin_version` and less than or equal to `end_version`, and whose + /// changeset is neither empty, nor produced by integration of a changeset + /// received from the specified remote peer. + /// + /// If \a buffer is non-null, memory will be allocated and transferred to + /// \a buffer. The changeset will be copied into the newly allocated memory. + /// + /// If \a buffer is null, the changeset is not copied out of the Realm, + /// and entry.changeset.data() does not point to the changeset. + /// The changeset in the Realm could be chunked, hence it is not possible + /// to point to it with BinaryData. entry.changeset.size() always gives the + /// size of the changeset. + /// + /// \param begin_version, end_version The range of versions to consider. If + /// `begin_version` is equal to `end_version`, this is the empty range. If + /// `begin_version` is zero, it means that everything preceeding + /// `end_version` is to be considered, which is again the empty range if + /// `end_version` is also zero. Zero is is special value in that no + /// changeset produces that version. It is an error if `end_version` + /// preceeds `begin_version`, or if `end_version` is zero and + /// `begin_version` is not. + /// + /// \param not_from_remote_client_file_ident Skip entries whose changeset is + /// produced by integration of changesets received from this remote + /// peer. Zero if the remote peer is the server, otherwise the peer + /// identifier of a client. + /// + /// \param only_nonempty Skip entries with empty changesets. + /// + /// \return The version produced by the changeset of the located history + /// entry, or zero if no history entry exists matching the specified + /// criteria. + virtual version_type find_history_entry(version_type begin_version, version_type end_version, + file_ident_type not_from_remote_client_file_ident, + bool only_nonempty, HistoryEntry& entry) const noexcept = 0; + + /// Get the specified reciprocal changeset. The targeted history entry is + /// the one whose untransformed changeset produced the specified version. + /// + /// \param remote_client_file_ident Zero if the remote peer is the server, + /// otherwise the peer identifier of a client. + virtual ChunkedBinaryData get_reciprocal_transform(version_type version, + file_ident_type remote_client_file_ident) const = 0; + + /// Replace the specified reciprocally transformed changeset. The targeted + /// history entry is the one whose untransformed changeset produced the + /// specified version. + /// + /// \param remote_client_file_ident See get_reciprocal_transform(). + /// + /// \param encoded_changeset The new reciprocally transformed changeset. + virtual void set_reciprocal_transform(version_type version, + file_ident_type remote_client_file_ident, + BinaryData encoded_changeset) = 0; + + virtual ~TransformHistory() noexcept {} +}; + + +class TransformError; // Exception + +class Transformer { +public: + using timestamp_type = HistoryEntry::timestamp_type; + using file_ident_type = HistoryEntry::file_ident_type; + using version_type = HistoryEntry::version_type; + + class RemoteChangeset; + class Reporter; + + /// Produce an operationally transformed version of the specified changesets, + /// which are assumed to be of remote origin, and received from remote peer + /// P. Note that P is not necessarily the peer from which the changes + /// originated. + /// + /// Operational transformation is carried out between the specified + /// changesets and all causally unrelated changesets in the local history. A + /// changeset in the local history is causally unrelated if, and only if it + /// occurs after the local changeset that produced + /// `remote_changeset.last_integrated_local_version` and is not a produced + /// by integration of a changeset received from P. This assumes that + /// `remote_changeset.last_integrated_local_version` is set to the local + /// version produced by the last local changeset, that was integrated by P + /// before P produced the specified changeset. + /// + /// The operational transformation is reciprocal (two-way), so it also + /// transforms the causally unrelated local changesets. This process does + /// not modify the history itself (the changesets available through + /// TransformHistory::get_history_entry()), instead the reciprocally + /// transformed changesets are stored separately, and individually for each + /// remote peer, such that they can participate in transformation of the + /// next incoming changeset from P. Note that the peer identifier of P can + /// be derived from `origin_client_file_ident` and information about whether + /// the local peer is a server or a client. + /// + /// In general, if A and B are two causally unrelated (alternative) + /// changesets based on the same version V, then the operational + /// transformation between A and B produces changesets A' and B' such that + /// both of the concatenated changesets A + B' and B + A' produce the same + /// final state when applied to V. Operational transformation is meaningful + /// only when carried out between alternative changesets based on the same + /// version. + /// + /// \return The size of the transformed version of the specified + /// changesets. Upon return, the transformed changesets are concatenated + /// and placed in \a output_buffer. + /// + /// \throw TransformError Thrown if operational transformation fails due to + /// a problem with the specified changeset. + virtual void transform_remote_changesets(TransformHistory&, + version_type current_local_version, + Changeset* changesets, + std::size_t num_changesets, + Reporter* = nullptr) = 0; + + virtual ~Transformer() noexcept {} +}; + +/// \param local_client_file_ident The server assigned local client file +/// identifier. This must be zero on the server-side, and only on the +/// server-side. +std::unique_ptr make_transformer(Transformer::file_ident_type local_client_file_ident); + +class Transformer::RemoteChangeset { +public: + /// The version produced on the remote peer by this changeset. + /// + /// On the server, the remote peer is the client from which the changeset + /// originated, and `remote_version` is the client version produced by the + /// changeset on that client. + /// + /// On a client, the remote peer is the server, and `remote_version` is the + /// server version produced by this changeset on the server. Since the + /// server is never the originator of changes, this changeset must in turn + /// have been produced on the server by integration of a changeset uploaded + /// by some other client. + version_type remote_version = 0; + + /// The last local version that has been integrated into `remote_version`. + /// + /// A local version, L, has been integrated into a remote version, R, when, + /// and only when L is the latest local version such that all preceeding + /// changesets in the local history have been integrated by the remote peer + /// prior to R. + /// + /// On the server, this is the last server version integrated into the + /// client version `remote_version`. On a client, it is the last client + /// version integrated into the server version `remote_version`. + version_type last_integrated_local_version = 0; + + /// The changeset itself. + ChunkedBinaryData data; + + /// Same meaning as `HistoryEntry::origin_timestamp`. + timestamp_type origin_timestamp = 0; + + /// Same meaning as `HistoryEntry::origin_client_file_ident`. + file_ident_type origin_client_file_ident = 0; + + /// If the changeset was compacted during download, the size of the original + /// changeset. + size_t original_changeset_size = 0; + + RemoteChangeset() {} + RemoteChangeset(version_type rv, version_type lv, ChunkedBinaryData d, timestamp_type ot, + file_ident_type fi); +}; + +class Transformer::Reporter { +public: + virtual void report_merges(long num_merges) = 0; +}; + + +void parse_remote_changeset(const Transformer::RemoteChangeset&, Changeset&); + + + + +// Implementation + +class TransformError: public std::runtime_error { +public: + TransformError(const std::string& message): + std::runtime_error(message) + { + } +}; + +inline Transformer::RemoteChangeset::RemoteChangeset(version_type rv, version_type lv, + ChunkedBinaryData d, timestamp_type ot, + file_ident_type fi): + remote_version(rv), + last_integrated_local_version(lv), + data(d), + origin_timestamp(ot), + origin_client_file_ident(fi) +{ +} + +} // namespace sync +} // namespace realm + +#endif // REALM_SYNC_TRANSFORM_HPP