1 /* Copyright (c) 2014, 2021, Oracle and/or its affiliates.
2 
3    This program is free software; you can redistribute it and/or modify
4    it under the terms of the GNU General Public License, version 2.0,
5    as published by the Free Software Foundation.
6 
7    This program is also distributed with certain software (including
8    but not limited to OpenSSL) that is licensed under separate terms,
9    as designated in a particular file or component or in included license
10    documentation.  The authors of MySQL hereby grant you an additional
11    permission to link the program and your derivative works with the
12    separately licensed software that they have included with MySQL.
13 
14    This program is distributed in the hope that it will be useful,
15    but WITHOUT ANY WARRANTY; without even the implied warranty of
16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17    GNU General Public License, version 2.0, for more details.
18 
19    You should have received a copy of the GNU General Public License
20    along with this program; if not, write to the Free Software
21    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA */
22 
23 #ifndef RPL_TRANSACTION_WRITE_SET_CTX_H
24 #define RPL_TRANSACTION_WRITE_SET_CTX_H
25 
26 #include "my_global.h"
27 #include <vector>
28 #include <map>
29 #include <list>
30 #include <set>
31 #include <string>
32 
33 /**
34   Thread class responsible for the collection of write sets associated
35   to a transaction.
36 
37   It also includes suport for save points where information will be discarded
38   on rollbacks to a savepoint.
39 
40   Write set and flags are reset on
41     Rpl_transaction_write_set_ctx::reset_state().
42 
43   The write set collection by an executing transaction is capped to a limit.
44   The limit can be "soft" or "hard":
45   - when a writeset grows above a "soft" limit, the transaction is allowed to
46   execute and commit, but the write set is discarded, and the transaction
47   declared to not have a usable write set.
48   - when a write set grows above a "hard" limit, the transaction is forced
49   to abort and rollback.
50 
51   We cannot use a soft limit for transactions that will be certified in GR,
52   since a writeset is required for correct certification. But when GR is
53   disabled, we can use a soft limit, because the writeset is only used to
54   compute transaction dependencies, and we can pessimistically mark the
55   transaction as conflicting with all other transcations when the writeset
56   is discarded.
57   A soft limit can also be used for transactions executed by the GR recovery
58   channel, since they will not be certified, and the GR applier channel,
59   since those transactions have already passed the certification stage.
60 
61   For the soft limit, we use
62     - binlog_transaction_dependency_history_size.
63   Transactions bigger than that cannot be added to the writeset history
64   since they do not fit, and therefore are marked as conflicting with all
65   *subsequent* transactions anyways.
66   Therefore much of the parallelization for the transaction is already
67   destroyed, and it is unlikely that also marking it as conflicting with
68   *previous* transactions makes a significant difference.
69 
70   For the hard limit, when using Group Replication, we use
71     - group_replication_transaction_size_limit.
72   Since the writeset is a subset of the transaction, and the transaction
73   is limited to this size anyways, a transaction whose writeset exceeds
74   this limit will fail anyways.
75   So failing it when generating the writeset is merely a fail-fast mechanism,
76   and it is not a restriction to apply this limit to the writeset of all
77   transactions for which the full transaction data is also subject to the limit.
78   The transactions that are subject to this limit are exactly those executed
79   when GR is enabled, except by the GR applier channel and GR recovery channel.
80 
81   We expose the following interfaces so that components such as GR
82   can control the limit.
83   There is an interface to *globally*
84    disable/enable the soft limit:
85      static void set_global_require_full_write_set(bool requires_ws);
86    set/alter/remove a hard limit:
87      static void set_global_write_set_memory_size_limit(uint64 limit)
88      static void update_global_write_set_memory_size_limit(uint64 limit);
89 
90   There is another interface to override the global limits for a thread:
91     void set_local_ignore_write_set_memory_limit(bool ignore_limit);
92     void set_local_allow_drop_write_set(bool allow_drop_write_set);
93 
94   The local methods are used for example for Group Replication applier and
95   recovery threads as group_replication_transaction_size_limit only applies
96   to client sessions and non group replication replica threads.
97 */
98 class Rpl_transaction_write_set_ctx
99 {
100 public:
101   Rpl_transaction_write_set_ctx();
~Rpl_transaction_write_set_ctx()102   virtual ~Rpl_transaction_write_set_ctx() {}
103 
104   /**
105     Function to add the write set of the hash of the PKE in the std::vector
106     in the transaction_ctx object.
107 
108     @param[in] hash - the uint64 type hash value of the PKE.
109   */
110   bool add_write_set(uint64 hash);
111 
112   /*
113     Function to get the pointer of the write set in the
114     transaction_ctx object.
115   */
116   std::set<uint64> *get_write_set();
117 
118   /**
119     Reset the object so it can be used for a new transaction.
120   */
121   void reset_state();
122 
123   /*
124     mark transactions that include tables with no pk
125   */
126   void set_has_missing_keys();
127 
128   /*
129     check if the transaction was marked as having missing keys.
130 
131     @retval true  The transaction accesses tables with no PK.
132     @retval false All tables referenced in transaction have PK.
133    */
134   bool get_has_missing_keys();
135 
136   /*
137     mark transactions that include tables referenced by foreign keys
138   */
139   void set_has_related_foreign_keys();
140 
141   /*
142     function to check if the transaction was marked as having missing keys.
143 
144     @retval true  If the transaction was marked as being referenced by a foreign key
145   */
146   bool get_has_related_foreign_keys();
147 
148   /**
149     Identifies situations where the limit for number of write set entries
150     already exceeded the configure limit.
151 
152     @retval true if too many write set entries exist, false otherwise
153   */
154   bool was_write_set_limit_reached();
155 
156   /**
157     @returns the size of the write_set field in bytes
158   */
159   size_t write_set_memory_size();
160 
161   /**
162     Function to add a new SAVEPOINT identifier in the savepoint map in the
163     transaction_ctx object.
164 
165     @param[in] name - the identifier name of the SAVEPOINT.
166   */
167   void add_savepoint(char* name);
168 
169   /**
170     Function to delete a SAVEPOINT identifier in the savepoint map in the
171     transaction_ctx object.
172 
173     @param[in] name - the identifier name of the SAVEPOINT.
174   */
175   void del_savepoint(char* name);
176 
177   /**
178     Function to delete all data added to write set and savepoint since
179     SAVEPOINT identifier was added to savepoinbt in the transaction_ctx object.
180 
181     @param[in] name - the identifier name of the SAVEPOINT.
182   */
183   void rollback_to_savepoint(char* name);
184 
185   /**
186     Function to push savepoint data to a list and clear the savepoint map in
187     order to create another identifier context, needed on functions ant trigger.
188   */
189   void reset_savepoint_list();
190 
191   /**
192     Restore previous savepoint map context, called after executed trigger or
193     function.
194   */
195   void restore_savepoint_list();
196 
197   /**
198     Adds a memory limit for write sets.
199 
200     @note currently only one component can set this limit a time.
201 
202     @param limit the limit to be added
203   */
204   static void set_global_write_set_memory_size_limit(int64 limit);
205 
206   /**
207     Updates the memory limit for write sets.
208 
209     @note Using the value 0 disables the limit
210 
211     @param limit the limit to be added
212   */
213   static void update_global_write_set_memory_size_limit(int64 limit);
214 
215   /**
216     Prevent or allow this class to discard writesets exceeding a size limit
217     If true, a transaction will never discard its write sets
218 
219     @param requires_ws if who invoked the method needs or not write sets
220   */
221   static void set_global_require_full_write_set(bool requires_ws);
222 
223   /**
224     Set if the thread shall ignore any configured memory limit
225     for write set collection
226 
227     @param ignore_limit if the limit should be ignored
228   */
229   void set_local_ignore_write_set_memory_limit(bool ignore_limit);
230 
231   /**
232     Set if the thread shall if needed discard write sets
233 
234     @param allow_drop_write_set if full write sets are not critical
235   */
236   void set_local_allow_drop_write_set(bool allow_drop_write_set);
237 
238 private:
239   /*
240     Clear the vector that stores the PKEs, and clear the savepoints, but do not
241     restore all the flags. Outside transaction cleanup, this is used when
242     discarding a writeset of excessive size, without aborting the transaction.
243   */
244   void clear_write_set();
245 
246   std::vector<uint64> write_set;
247   std::set<uint64> write_set_unique;
248 
249   bool m_has_missing_keys;
250   bool m_has_related_foreign_keys;
251 
252   /**
253     Contains information related to SAVEPOINTs. The key on map is the
254     identifier and the value is the size of write set when command was
255     executed.
256   */
257   std::map<std::string, size_t> savepoint;
258 
259   /**
260     Create a savepoint context hierarchy to support encapsulation of
261     identifier name when function or trigger are executed.
262   */
263   std::list<std::map<std::string, size_t> > savepoint_list;
264 
265   // Write set restriction variables
266 
267   /** There is a component requiring write sets on transactions */
268   static int32 m_global_component_requires_write_sets;
269   /** Memory size limit enforced for write set collection */
270   static int64 m_global_write_set_memory_size_limit;
271 
272   /**
273     If the thread should or not ignore the set limit for
274     write set collection
275   */
276   bool m_ignore_write_set_memory_limit;
277   /**
278     Even if a component says all transactions require write sets,
279     this variable says this thread should discard them when they are
280     bigger than m_opt_max_history_size
281   */
282   bool m_local_allow_drop_write_set;
283 
284   /** True if the write set size is over the configure limit */
285   bool m_local_has_reached_write_set_limit;
286 };
287 
288 #endif	/* RPL_TRANSACTION_WRITE_SET_CTX_H */
289