1 /*************************************************************************
3 * Copyright 2017 Realm Inc.
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
9 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 **************************************************************************/
19 #ifndef REALM_SYNC_IMPL_INSTRUCTION_REPLICATION_HPP
20 #define REALM_SYNC_IMPL_INSTRUCTION_REPLICATION_HPP
22 #include <realm/replication.hpp>
23 #include <realm/sync/instructions.hpp>
24 #include <realm/sync/object.hpp>
25 #include <realm/sync/changeset_encoder.hpp>
31 class InstructionReplication: public TrivialReplication, public ObjectIDProvider {
33 explicit InstructionReplication(const std::string& realm_path);
34 void set_short_circuit(bool) noexcept;
35 bool is_short_circuited() const noexcept;
37 // reset() resets the encoder, the selected tables and the cache. It is
38 // called by do_initiate_transact(), but can be called at the other times
42 ChangesetEncoder& get_instruction_encoder() noexcept;
45 /// Generate instructions for Object Store tables. These must be called
46 /// prior to calling the equivalent functions in Core's API. When creating a
47 /// class-like table, `add_class()` must be called prior to
48 /// `Group::insert_group_level_table()`. Similarly, `create_object()` or
49 /// `create_object_with_primary_key()` must be called prior to
50 /// `Table::insert_empty_row()` and/or `Table::set_int_unique()` or
51 /// `Table::set_string_unique()` or `Table::set_null_unique()`.
53 /// If a class-like table is added, or an object-like row is inserted,
54 /// without calling these methods first, an exception will be thrown.
56 /// A "class-like table" is defined as a table whose name begins with
57 /// "class_" (this is the convention used by Object Store). Non-class-like
58 /// tables can be created and modified using Core's API without calling
59 /// these functions, because they do not result in instructions being
61 void add_class(StringData table_name);
62 void add_class_with_primary_key(StringData table_name, DataType pk_type, StringData pk_field, bool nullable);
63 void create_object(const Table*, ObjectID);
64 void create_object_with_primary_key(const Table*, ObjectID, StringData);
65 void create_object_with_primary_key(const Table*, ObjectID, int_fast64_t);
66 void create_object_with_primary_key(const Table*, ObjectID, realm::util::None);
69 // TrivialReplication interface:
70 void initialize(SharedGroup&) override;
72 // TransactLogConvenientEncoder interface:
73 void insert_group_level_table(size_t table_ndx, size_t num_tables, StringData name) override;
74 void erase_group_level_table(size_t table_ndx, size_t num_tables) override;
75 void rename_group_level_table(size_t table_ndx, StringData new_name) override;
76 void insert_column(const Descriptor&, size_t col_ndx, DataType type, StringData name, LinkTargetInfo& link,
77 bool nullable = false) override;
78 void erase_column(const Descriptor&, size_t col_ndx) override;
79 void rename_column(const Descriptor&, size_t col_ndx, StringData name) override;
81 void set_int(const Table*, size_t col_ndx, size_t ndx, int_fast64_t value, _impl::Instruction variant) override;
82 void add_int(const Table*, size_t col_ndx, size_t ndx, int_fast64_t value) override;
83 void set_bool(const Table*, size_t col_ndx, size_t ndx, bool value, _impl::Instruction variant) override;
84 void set_float(const Table*, size_t col_ndx, size_t ndx, float value, _impl::Instruction variant) override;
85 void set_double(const Table*, size_t col_ndx, size_t ndx, double value, _impl::Instruction variant) override;
86 void set_string(const Table*, size_t col_ndx, size_t ndx, StringData value, _impl::Instruction variant) override;
87 void set_binary(const Table*, size_t col_ndx, size_t ndx, BinaryData value, _impl::Instruction variant) override;
88 void set_olddatetime(const Table*, size_t col_ndx, size_t ndx, OldDateTime value,
89 _impl::Instruction variant) override;
90 void set_timestamp(const Table*, size_t col_ndx, size_t ndx, Timestamp value, _impl::Instruction variant) override;
91 void set_table(const Table*, size_t col_ndx, size_t ndx, _impl::Instruction variant) override;
92 void set_mixed(const Table*, size_t col_ndx, size_t ndx, const Mixed& value, _impl::Instruction variant) override;
93 void set_link(const Table*, size_t col_ndx, size_t ndx, size_t value, _impl::Instruction variant) override;
94 void set_null(const Table*, size_t col_ndx, size_t ndx, _impl::Instruction variant) override;
95 void set_link_list(const LinkView&, const IntegerColumn& values) override;
96 void insert_substring(const Table*, size_t col_ndx, size_t row_ndx, size_t pos, StringData) override;
97 void erase_substring(const Table*, size_t col_ndx, size_t row_ndx, size_t pos, size_t size) override;
98 void insert_empty_rows(const Table*, size_t row_ndx, size_t num_rows_to_insert, size_t prior_num_rows) override;
99 void add_row_with_key(const Table*, size_t row_ndx, size_t prior_num_rows, size_t key_col_ndx, int64_t key) override;
100 void erase_rows(const Table*, size_t row_ndx, size_t num_rows_to_erase, size_t prior_num_rowsp,
101 bool is_move_last_over) override;
102 void swap_rows(const Table*, size_t row_ndx_1, size_t row_ndx_2) override;
103 void move_row(const Table*, size_t row_ndx_1, size_t row_ndx_2) override;
104 void merge_rows(const Table*, size_t row_ndx, size_t new_row_ndx) override;
105 void add_search_index(const Descriptor&, size_t col_ndx) override;
106 void remove_search_index(const Descriptor&, size_t col_ndx) override;
107 void set_link_type(const Table*, size_t col_ndx, LinkType) override;
108 void clear_table(const Table*, size_t prior_num_rows) override;
109 void optimize_table(const Table*) override;
110 void link_list_set(const LinkView&, size_t ndx, size_t value) override;
111 void link_list_insert(const LinkView&, size_t ndx, size_t value) override;
112 void link_list_move(const LinkView&, size_t from_ndx, size_t to_ndx) override;
113 void link_list_swap(const LinkView&, size_t ndx_1, size_t ndx_2) override;
114 void link_list_erase(const LinkView&, size_t ndx) override;
115 void link_list_clear(const LinkView&) override;
116 void nullify_link(const Table*, size_t col_ndx, size_t ndx) override;
117 void link_list_nullify(const LinkView&, size_t ndx) override;
120 // Replication interface:
121 void do_initiate_transact(version_type current_version, bool history_updated) override;
123 bool m_short_circuit = false;
125 ChangesetEncoder m_encoder;
126 SharedGroup* m_sg = nullptr;
127 std::unique_ptr<TableInfoCache> m_cache;
129 enum class TableBehavior {
135 // FIXME: The base class already caches this.
136 const Table* m_selected_table = nullptr;
137 TableBehavior m_selected_table_behavior; // cache
138 const LinkView* m_selected_link_list = nullptr;
140 // Consistency checks:
141 std::string m_table_being_created;
142 std::string m_table_being_created_primary_key;
143 util::Optional<ObjectID> m_object_being_created;
145 void unsupported_instruction(); // Throws TransformError
146 TableBehavior select_table(const Table*);
147 TableBehavior select_table(const Descriptor&);
148 bool select_link_list(const LinkView&); // returns true if table behavior != ignored
150 TableBehavior get_table_behavior(const Table*) const;
153 void set(const Table*, size_t row_ndx, size_t col_ndx, T payload,
154 _impl::Instruction variant);
156 void set_pk(const Table*, size_t row_ndx, size_t col_ndx, T payload,
157 _impl::Instruction variant);
159 auto as_payload(T value);
161 void emit(T instruction);
164 inline void InstructionReplication::set_short_circuit(bool b) noexcept
169 inline bool InstructionReplication::is_short_circuited() const noexcept
171 return m_short_circuit;
174 inline ChangesetEncoder& InstructionReplication::get_instruction_encoder() noexcept
179 // Temporarily short-circuit replication
180 class TempShortCircuitReplication {
182 TempShortCircuitReplication(InstructionReplication& bridge): m_bridge(bridge)
184 m_was_short_circuited = bridge.is_short_circuited();
185 bridge.set_short_circuit(true);
188 ~TempShortCircuitReplication() {
189 m_bridge.set_short_circuit(m_was_short_circuited);
192 InstructionReplication& m_bridge;
193 bool m_was_short_circuited;
199 #endif // REALM_SYNC_IMPL_INSTRUCTION_REPLICATION_HPP