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