1 /*
2    Copyright (c) 2005, 2021, Oracle and/or its affiliates.
3 
4    This program is free software; you can redistribute it and/or modify
5    it under the terms of the GNU General Public License, version 2.0,
6    as published by the Free Software Foundation.
7 
8    This program is also distributed with certain software (including
9    but not limited to OpenSSL) that is licensed under separate terms,
10    as designated in a particular file or component or in included license
11    documentation.  The authors of MySQL hereby grant you an additional
12    permission to link the program and your derivative works with the
13    separately licensed software that they have included with MySQL.
14 
15    This program is distributed in the hope that it will be useful,
16    but WITHOUT ANY WARRANTY; without even the implied warranty of
17    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18    GNU General Public License, version 2.0, for more details.
19 
20    You should have received a copy of the GNU General Public License
21    along with this program; if not, write to the Free Software
22    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA
23 */
24 
25 #ifndef LGMAN_H
26 #define LGMAN_H
27 
28 #include <SimulatedBlock.hpp>
29 
30 #include <IntrusiveList.hpp>
31 #include <KeyTable.hpp>
32 #include <DLHashTable.hpp>
33 #include <NodeBitmask.hpp>
34 #include "diskpage.hpp"
35 #include <signaldata/GetTabInfo.hpp>
36 
37 #include <WOPool.hpp>
38 #include <SafeMutex.hpp>
39 
40 #define JAM_FILE_ID 339
41 
42 
43 class Lgman : public SimulatedBlock
44 {
45 public:
46   Lgman(Block_context& ctx);
47   virtual ~Lgman();
48   BLOCK_DEFINES(Lgman);
49 
50 protected:
51 
52   void execSTTOR(Signal* signal);
53   void sendSTTORRY(Signal*);
54   void execREAD_CONFIG_REQ(Signal* signal);
55   void execDUMP_STATE_ORD(Signal* signal);
56   void execDBINFO_SCANREQ(Signal* signal);
57   void execCONTINUEB(Signal* signal);
58   void execNODE_FAILREP(Signal* signal);
59 
60   void execCREATE_FILE_IMPL_REQ(Signal* signal);
61   void execCREATE_FILEGROUP_IMPL_REQ(Signal* signal);
62   void execDROP_FILE_IMPL_REQ(Signal* signal);
63   void execDROP_FILEGROUP_IMPL_REQ(Signal* signal);
64 
65   void execFSWRITEREQ(Signal*);
66   void execFSWRITEREF(Signal*);
67   void execFSWRITECONF(Signal*);
68 
69   void execFSOPENREF(Signal*);
70   void execFSOPENCONF(Signal*);
71 
72   void execFSCLOSEREF(Signal*);
73   void execFSCLOSECONF(Signal*);
74 
75   void execFSREADREF(Signal*);
76   void execFSREADCONF(Signal*);
77 
78   void execEND_LCPREQ(Signal*);
79   void execSUB_GCP_COMPLETE_REP(Signal*);
80 
81   void execSTART_RECREQ(Signal*);
82   void execEND_LCPCONF(Signal*);
83 
84   void execGET_TABINFOREQ(Signal*);
85   void execCALLBACK_ACK(Signal*);
86 
87   void sendGET_TABINFOREF(Signal* signal,
88 			  GetTabInfoReq * req,
89 			  GetTabInfoRef::ErrorCode errorCode);
90 
91   void exec_lcp_frag_ord(Signal*, SimulatedBlock* client_block);
92 
93 public:
94   struct Log_waiter
95   {
96     CallbackPtr m_callback;
97     union {
98       Uint32 m_size;
99       Uint64 m_sync_lsn;
100     };
101     Uint32 m_block; // includes instance
102     Uint32 nextList;
103     Uint32 m_magic;
104   };
105 
106   typedef RecordPool<Log_waiter, WOPool> Log_waiter_pool;
107   typedef SLFifoListImpl<Log_waiter_pool, Log_waiter> Log_waiter_list;
108   typedef LocalSLFifoListImpl<Log_waiter_pool, Log_waiter> Local_log_waiter_list;
109 
110   struct Undofile
111   {
UndofileLgman::Undofile112     Undofile(){}
113     Undofile(const struct CreateFileImplReq*, Uint32 lg_ptr_i);
114 
115     Uint32 m_magic;
116     Uint32 m_file_id; // Dict obj id
117     Uint32 m_logfile_group_ptr_i;
118 
119     Uint32 m_file_size;
120     Uint32 m_state;
121     Uint32 m_fd; // When speaking to NDBFS
122     Uint64 m_start_lsn;
123 
124     enum FileState
125     {
126       FS_CREATING     = 0x1   // File is being created
127       ,FS_DROPPING    = 0x2   // File is being dropped
128       ,FS_ONLINE      = 0x4   // File is online
129       ,FS_OPENING     = 0x8   // File is being opened during SR
130       ,FS_SORTING     = 0x10  // Files in group are being sorted
131       ,FS_SEARCHING   = 0x20  // File is being binary searched for end of log
132       ,FS_EXECUTING   = 0x40  // File is used for executing UNDO log
133       ,FS_EMPTY       = 0x80  // File is empty (used when online)
134       ,FS_OUTSTANDING = 0x100 // File has outstanding request
135       ,FS_MOVE_NEXT   = 0x200 // When receiving reply move to next file
136       ,FS_SEARCHING_END   = 0x400  // Searched for end of log, scan
137       ,FS_SEARCHING_FINAL_READ   = 0x800 //Searched for log end, read last page
138     };
139 
140     union {
141       struct {
142 	Uint32 m_outstanding; // Outstanding pages
143         Uint32 m_current_scan_index;
144         Uint32 m_current_scanned_pages;
145         bool m_binary_search_end;
146 	Uint64 m_lsn;         // Used when finding log head
147       } m_online;
148       struct {
149 	Uint32 m_senderData;
150 	Uint32 m_senderRef;
151 	Uint32 m_logfile_group_id;
152 	Uint32 m_logfile_group_version;
153       } m_create;
154     };
155 
156     Uint32 nextList;
157     union {
158       Uint32 prevList;
159       Uint32 nextPool;
160     };
161   };
162 
163   typedef RecordPool<Undofile, RWPool> Undofile_pool;
164   typedef DLFifoListImpl<Undofile_pool, Undofile> Undofile_list;
165   typedef LocalDLFifoListImpl<Undofile_pool, Undofile> Local_undofile_list;
166   typedef LocalDataBuffer<15> Page_map;
167 
168   struct Buffer_idx
169   {
170     Uint32 m_ptr_i;
171     Uint32 m_idx;
operator ==Lgman::Buffer_idx172     bool operator== (const Buffer_idx& bi) const {
173       return (m_ptr_i == bi.m_ptr_i && m_idx == bi.m_idx);
174     }
175   };
176 
177   struct Logfile_group
178   {
Logfile_groupLgman::Logfile_group179     Logfile_group(){}
180     Logfile_group(const struct CreateFilegroupImplReq*);
181 
182     Uint32 m_magic;
183     union {
184       Uint32 key;
185       Uint32 m_logfile_group_id;
186     };
187     Uint32 m_version;
188     Uint16 m_state;
189     Uint16 m_outstanding_fs;
190     Uint32 m_next_reply_ptr_i;
191 
192     enum Logfile_group_state
193     {
194       LG_ONLINE               = 0x001
195       ,LG_SORTING             = 0x002  // Sorting files
196       ,LG_SEARCHING           = 0x004  // Searching in last file
197       ,LG_EXEC_THREAD         = 0x008  // Execute thread is running
198       ,LG_READ_THREAD         = 0x010  // Read thread is running
199       ,LG_FORCE_SYNC_THREAD   = 0x020
200       ,LG_SYNC_WAITERS_THREAD = 0x040
201       ,LG_CUT_LOG_THREAD      = 0x080
202       ,LG_WAITERS_THREAD      = 0x100
203       ,LG_FLUSH_THREAD        = 0x200
204       ,LG_DROPPING            = 0x400
205       ,LG_STARTING            = 0x800
206     };
207 
208     static const Uint32 LG_THREAD_MASK = Logfile_group::LG_FORCE_SYNC_THREAD |
209                                   Logfile_group::LG_SYNC_WAITERS_THREAD |
210                                   Logfile_group::LG_CUT_LOG_THREAD |
211                                   Logfile_group::LG_WAITERS_THREAD |
212                                   Logfile_group::LG_FLUSH_THREAD;
213 
214     Uint32 m_applied;
215 
216     Uint64 m_next_lsn;
217     Uint64 m_last_sync_req_lsn; // Outstanding
218     Uint64 m_last_synced_lsn;   //
219     Uint64 m_max_sync_req_lsn;  // User requested lsn
220     union {
221       Uint64 m_last_read_lsn;
222       Uint64 m_last_lcp_lsn;
223     };
224     Log_waiter_list::Head m_log_sync_waiters;
225 
226     Buffer_idx m_tail_pos[3]; // 0 is cut, 1 is saved, 2 is current
227     Buffer_idx m_file_pos[2]; // 0 tail, 1 head = { file_ptr_i, page_no }
228     Buffer_idx m_consumer_file_pos;
229     Uint64 m_free_file_words; // Free words in logfile group
230 
231     Undofile_list::Head m_files;     // Files in log
232     Undofile_list::Head m_meta_files;// Files being created or dropped
233 
234     Uint32 m_total_buffer_words;    // Total buffer page words
235     Uint32 m_free_buffer_words;     // Free buffer page words
236     Uint32 m_callback_buffer_words; // buffer words that has been
237                                     // returned to user, but not yet consumed
238     Log_waiter_list::Head m_log_buffer_waiters;
239     Page_map::Head m_buffer_pages; // Pairs of { ptr.i, count }
240     struct Position {
241       Buffer_idx m_current_page;   // { m_buffer_pages.i, left in range }
242       Buffer_idx m_current_pos;    // { page ptr.i, m_words_used }
243     } m_pos[2]; // 0 is reader (lgman) 1 is writer (tup)
244 
245     Uint32 nextHash;
246     Uint32 prevHash;
247     Uint32 nextList;
248     union {
249       Uint32 prevList;
250       Uint32 nextPool;
251     };
hashValueLgman::Logfile_group252     Uint32 hashValue() const {
253       return key;
254     }
equalLgman::Logfile_group255     bool equal(const Logfile_group& rec) const {
256       return key == rec.key;
257     }
258   };
259 
260   typedef RecordPool<Logfile_group, RWPool> Logfile_group_pool;
261   typedef DLFifoListImpl<Logfile_group_pool, Logfile_group> Logfile_group_list;
262   typedef LocalDLFifoListImpl<Logfile_group_pool, Logfile_group> Local_logfile_group_list;
263   typedef KeyTableImpl<Logfile_group_pool, Logfile_group> Logfile_group_hash;
264   typedef KeyTableImpl<Logfile_group_pool, Logfile_group>::Iterator Logfile_group_hash_iterator;
265   enum CallbackIndex {
266     // lgman
267     ENDLCP_CALLBACK = 1,
268     COUNT_CALLBACKS = 2
269   };
270   CallbackEntry m_callbackEntry[COUNT_CALLBACKS];
271   CallbackTable m_callbackTable;
272 
273 private:
274   friend class Logfile_client;
275   SimulatedBlock* m_tup;
276 
277   /**
278    * Alloc/free space in log
279    *   Allocation will be removed at either/or
280    *   1) Logfile_client::add_entry
281    *   2) free_log_space
282    */
283   int alloc_log_space(Uint32 logfile_ref,
284                       Uint32 words,
285                       EmulatedJamBuffer *jamBuf);
286   int free_log_space(Uint32 logfile_ref,
287                       Uint32 words,
288                       EmulatedJamBuffer *jamBuf);
289 
290   Undofile_pool m_file_pool;
291   Logfile_group_pool m_logfile_group_pool;
292   Log_waiter_pool m_log_waiter_pool;
293 
294   Page_map::DataBufferPool m_data_buffer_pool;
295 
296   Uint64 m_next_lsn;
297   Uint32 m_latest_lcp;
298   Logfile_group_list m_logfile_group_list;
299   Logfile_group_hash m_logfile_group_hash;
300   Uint32 m_end_lcp_senderdata;
301 
302   SafeMutex m_client_mutex;
303   void client_lock(BlockNumber block, int line);
304   void client_unlock(BlockNumber block, int line);
305 
306   bool alloc_logbuffer_memory(Ptr<Logfile_group>, Uint32 pages);
307   void init_logbuffer_pointers(Ptr<Logfile_group>);
308   void free_logbuffer_memory(Ptr<Logfile_group>);
309   Uint32 compute_free_file_pages(Ptr<Logfile_group>,
310                                  EmulatedJamBuffer *jamBuf);
311   Uint32* get_log_buffer(Ptr<Logfile_group>,
312                          Uint32 sz,
313                          EmulatedJamBuffer *jamBuf);
314   void process_log_buffer_waiters(Signal* signal, Ptr<Logfile_group>);
315   Uint32 next_page(Logfile_group* ptrP, Uint32 i, EmulatedJamBuffer *jamBuf);
316 
317   void force_log_sync(Signal*, Ptr<Logfile_group>, Uint32 lsnhi, Uint32 lnslo);
318   void process_log_sync_waiters(Signal* signal, Ptr<Logfile_group>);
319 
320   void cut_log_tail(Signal*, Ptr<Logfile_group> ptr);
321   void endlcp_callback(Signal*, Uint32, Uint32);
322   void open_file(Signal*, Ptr<Undofile>, Uint32, SectionHandle*);
323 
324   void flush_log(Signal*, Ptr<Logfile_group>, Uint32 force);
325   Uint32 write_log_pages(Signal*, Ptr<Logfile_group>,
326 			 Uint32 pageId, Uint32 pages);
327 
328   void find_log_head(Signal* signal, Ptr<Logfile_group> ptr);
329   void find_log_head_in_file(Signal*, Ptr<Logfile_group>,Ptr<Undofile>,Uint64);
330   void find_log_head_end_check(Signal*,
331                                Ptr<Logfile_group>,
332                                Ptr<Undofile>,
333                                Uint64);
334   void find_log_head_complete(Signal*, Ptr<Logfile_group>,Ptr<Undofile>);
335 
336   void init_run_undo_log(Signal*);
337   void read_undo_log(Signal*, Ptr<Logfile_group> ptr);
338   Uint32 read_undo_pages(Signal*, Ptr<Logfile_group>,
339 			 Uint32 pageId, Uint32 pages);
340 
341   void execute_undo_record(Signal*);
342   const Uint32* get_next_undo_record(Uint64* lsn);
343   void update_consumer_file_pos(Ptr<Logfile_group> ptr);
344   void stop_run_undo_log(Signal* signal);
345   void init_tail_ptr(Signal* signal, Ptr<Logfile_group> ptr);
346 
347   bool find_file_by_id(Ptr<Undofile>&, Undofile_list::Head&, Uint32 id);
348   void create_file_commit(Signal* signal, Ptr<Logfile_group>, Ptr<Undofile>);
349   void create_file_abort(Signal* signal, Ptr<Logfile_group>, Ptr<Undofile>);
350 
351 #ifdef VM_TRACE
352   void validate_logfile_group(Ptr<Logfile_group> ptr,
353                               const char*,
354                               EmulatedJamBuffer *jamBuf);
355 #else
validate_logfile_group(Ptr<Logfile_group> ptr,const char * =0,EmulatedJamBuffer * jamBuf=0)356   void validate_logfile_group(Ptr<Logfile_group> ptr,
357                               const char * = 0,
358                               EmulatedJamBuffer *jamBuf = 0)
359   {}
360 #endif
361 
362   void drop_filegroup_drop_files(Signal*, Ptr<Logfile_group>,
363 				 Uint32 ref, Uint32 data);
364 };
365 
366 class Logfile_client {
367   SimulatedBlock *m_client_block;
368   Uint32 m_block; // includes instance
369   Lgman * m_lgman;
370   bool m_lock;
371   DEBUG_OUT_DEFINES(LGMAN);
372 public:
373   Uint32 m_logfile_group_id;
374 
375   Logfile_client(SimulatedBlock* block, Lgman*, Uint32 logfile_group_id,
376                  bool lock = true);
377   ~Logfile_client();
378 
379   struct Request
380   {
381     SimulatedBlock::CallbackPtr m_callback;
382   };
383 
384   /**
385    * Request flags
386    */
387   enum RequestFlags
388   {
389   };
390 
391   /**
392    * Make sure a lsn is stored
393    * @return -1, on error
394    *          0, request in queued
395    *         >0, done
396    */
397   int sync_lsn(Signal*,
398                Uint64,
399                Request*,
400                Uint32 flags);
401 
402   /**
403    * Undolog entries
404    */
405   struct Change
406   {
407     const void * ptr;
408     Uint32 len;
409   };
410 
411   Uint64 add_entry(const Change*,
412                    Uint32 cnt);
413 
414   /**
415    * Check for space in log buffer
416    *
417    *   return >0 if available
418    *           0 on time slice
419    *          -1 on error
420    */
421   int get_log_buffer(Signal*, Uint32 sz, SimulatedBlock::CallbackPtr*);
422 
alloc_log_space(Uint32 words,EmulatedJamBuffer * jamBuf)423   int alloc_log_space(Uint32 words,
424                       EmulatedJamBuffer *jamBuf)
425   {
426     return m_lgman->alloc_log_space(m_logfile_group_id,
427                                     words,
428                                     jamBuf);
429   }
430 
free_log_space(Uint32 words,EmulatedJamBuffer * jamBuf)431   int free_log_space(Uint32 words,
432                      EmulatedJamBuffer *jamBuf)
433   {
434     return m_lgman->free_log_space(m_logfile_group_id, words, jamBuf);
435   }
436 
exec_lcp_frag_ord(Signal * signal)437   void exec_lcp_frag_ord(Signal* signal)
438   {
439     m_lgman->exec_lcp_frag_ord(signal,
440                                m_client_block);
441   }
442 
443 private:
444   Uint32* get_log_buffer(Uint32 sz);
445 };
446 
447 
448 
449 #undef JAM_FILE_ID
450 
451 #endif
452