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 TSMAN_H
26 #define TSMAN_H
27 
28 #include <SimulatedBlock.hpp>
29 
30 #include <IntrusiveList.hpp>
31 #include <NodeBitmask.hpp>
32 #include <signaldata/GetTabInfo.hpp>
33 #include <signaldata/Extent.hpp>
34 #include <SafeMutex.hpp>
35 
36 #include "lgman.hpp"
37 #include "pgman.hpp"
38 
39 #define JAM_FILE_ID 456
40 
41 
42 class Tsman : public SimulatedBlock
43 {
44 public:
45   Tsman(Block_context&);
46   virtual ~Tsman();
47   BLOCK_DEFINES(Tsman);
48 
49 protected:
50 
51   void execSTTOR(Signal* signal);
52   void sendSTTORRY(Signal*);
53   void execREAD_CONFIG_REQ(Signal* signal);
54   void execDUMP_STATE_ORD(Signal* signal);
55   void execCONTINUEB(Signal* signal);
56   void execNODE_FAILREP(Signal* signal);
57 
58   void execCREATE_FILE_IMPL_REQ(Signal* signal);
59   void execCREATE_FILEGROUP_IMPL_REQ(Signal* signal);
60   void execDROP_FILE_IMPL_REQ(Signal* signal);
61   void execDROP_FILEGROUP_IMPL_REQ(Signal* signal);
62 
63   void execSTART_RECREQ(Signal*);
64 
65   void execFSWRITEREQ(Signal*);
66   void execFSOPENREF(Signal*);
67   void execFSOPENCONF(Signal*);
68   void execFSREADREF(Signal*);
69   void execFSREADCONF(Signal*);
70 
71   void execFSCLOSEREF(Signal*);
72   void execFSCLOSECONF(Signal*);
73 
74   void execALLOC_EXTENT_REQ(Signal*);
75   void execFREE_EXTENT_REQ(Signal*);
76 
77   void execALLOC_PAGE_REQ(Signal* signal);
78 
79   void execLCP_FRAG_ORD(Signal*);
80   void execEND_LCPREQ(Signal*);
81   void end_lcp(Signal*, Uint32 tablespace, Uint32 list, Uint32 file);
82 
83   void execGET_TABINFOREQ(Signal*);
84 
85   void sendGET_TABINFOREF(Signal* signal,
86 			  GetTabInfoReq * req,
87 			  GetTabInfoRef::ErrorCode errorCode);
88 
89 public:
90   struct Datafile
91   {
DatafileTsman::Datafile92     Datafile(){}
93     Datafile(const struct CreateFileImplReq*);
94 
95     /**
96      * m_file_no
97      * - Unique among datafiles on this node
98      * - Part of local key
99      * - Set by pgman
100      */
101     Uint32 m_magic;
102     Uint32 m_file_no;
103     Uint32 m_file_id;        // Used when talking to DICT
104     Uint32 m_fd; // NDBFS
105 
106     Uint32 m_tablespace_ptr_i;
107     Uint32 m_extent_size;
108     Uint16 m_state;
109     Uint16 m_ref_count;
110 
111     enum FileState
112     {
113       FS_CREATING = 0x1,
114       FS_ONLINE   = 0x2,
115       FS_DROPPING = 0x4
116     };
117 
118     union {
119       struct {
120 	Uint32 m_first_free_extent;
121 	Uint32 m_lcp_free_extent_head; // extents freed but not LCP
122 	Uint32 m_lcp_free_extent_tail;
123 	Uint32 m_offset_data_pages;    // 1(zero) + extent header pages
124 	Uint32 m_data_pages;
125 	Uint32 m_used_extent_cnt;
126 	Uint32 m_extent_headers_per_extent_page;
127       } m_online;
128       struct {
129 	Uint32 m_senderData;
130 	Uint32 m_senderRef;
131 	Uint32 m_data_pages;
132 	Uint32 m_extent_pages;
133 	Uint32 m_requestInfo;
134 	union {
135 	  Uint32 m_page_ptr_i;
136 	  Uint32 m_loading_extent_page;
137 	};
138       } m_create;
139     };
140 
141     Uint32 nextHash;
142     Uint32 prevHash;
143     Uint32 nextList;
144     union {
145       Uint32 prevList;
146       Uint32 nextPool;
147     };
148 
hashValueTsman::Datafile149     Uint32 hashValue() const {
150       return m_file_no;
151     }
equalTsman::Datafile152     bool equal(const Datafile& rec) const {
153       return m_file_no == rec.m_file_no;
154     }
155   };
156 
157   typedef RecordPool<Datafile, RWPool> Datafile_pool;
158   typedef DLListImpl<Datafile_pool, Datafile> Datafile_list;
159   typedef LocalDLListImpl<Datafile_pool, Datafile> Local_datafile_list;
160   typedef DLHashTableImpl<Datafile_pool, Datafile> Datafile_hash;
161 
162   struct Tablespace
163   {
TablespaceTsman::Tablespace164     Tablespace(){}
165     Tablespace(Tsman*, const struct CreateFilegroupImplReq*);
166 
167     Uint32 m_magic;
168     union {
169       Uint32 key;
170       Uint32 m_tablespace_id;
171     };
172     Uint32 m_version;
173     Uint16 m_state;
174     Uint16 m_ref_count; // Can't release when m_ref_count > 0
175 
176     enum TablespaceState
177     {
178       TS_CREATING = 0x1,
179       TS_ONLINE = 0x2,
180       TS_DROPPING = 0x4
181     };
182 
183     Uint32 m_extent_size;       // In pages
184     Datafile_list::Head m_free_files; // Files w/ free space
185     Tsman* m_tsman;
186     Uint32 m_logfile_group_id;
187 
188     Datafile_list::Head m_full_files; // Files wo/ free space
189     Datafile_list::Head m_meta_files; // Files being created/dropped
190 
191     Uint32 nextHash;
192     Uint32 prevHash;
193     Uint32 nextList;
194     union {
195       Uint32 prevList;
196       Uint32 nextPool;
197     };
198 
hashValueTsman::Tablespace199     Uint32 hashValue() const {
200       return key;
201     }
equalTsman::Tablespace202     bool equal(const Tablespace& rec) const {
203       return key == rec.key;
204     }
205   };
206 
207   typedef RecordPool<Tablespace, RWPool> Tablespace_pool;
208   typedef DLListImpl<Tablespace_pool, Tablespace> Tablespace_list;
209   typedef LocalDLListImpl<Tablespace_pool, Tablespace> Local_tablespace_list;
210   typedef KeyTableImpl<Tablespace_pool, Tablespace> Tablespace_hash;
211 
212 private:
213   friend class Tablespace_client;
214   Datafile_pool m_file_pool;
215   Tablespace_pool m_tablespace_pool;
216 
217   bool m_lcp_ongoing;
218   Datafile_hash m_file_hash;
219   Tablespace_list m_tablespace_list;
220   Tablespace_hash m_tablespace_hash;
221   SimulatedBlock * m_pgman;
222   Lgman * m_lgman;
223   SimulatedBlock * m_tup;
224 
225   SafeMutex m_client_mutex;
226   void client_lock(BlockNumber block, int line);
227   void client_unlock(BlockNumber block, int line);
228 
229   int open_file(Signal*, Ptr<Tablespace>, Ptr<Datafile>, CreateFileImplReq*,
230 		SectionHandle* handle);
231   void load_extent_pages(Signal* signal, Ptr<Datafile> ptr);
232   void load_extent_page_callback(Signal*, Uint32, Uint32);
233   void create_file_ref(Signal*, Ptr<Tablespace>, Ptr<Datafile>,
234 		       Uint32,Uint32,Uint32);
235   int update_page_free_bits(Signal*, Local_key*, unsigned committed_bits);
236 
237   int get_page_free_bits(Signal*, Local_key*, unsigned*, unsigned*);
238   int unmap_page(Signal*, Local_key*, unsigned uncommitted_bits);
239   int restart_undo_page_free_bits(Signal*, Uint32, Uint32, Local_key*,
240 				  unsigned committed_bits);
241 
242   int alloc_extent(Signal* signal, Uint32 tablespace, Local_key* key);
243   int alloc_page_from_extent(Signal*, Uint32, Local_key*, Uint32 bits);
244 
245   void scan_tablespace(Signal*, Uint32 ptrI);
246   void scan_datafile(Signal*, Uint32, Uint32);
247   void scan_extent_headers(Signal*, Ptr<Datafile>);
248 
249   bool find_file_by_id(Ptr<Datafile>&, Datafile_list::Head&, Uint32 id);
250   void create_file_abort(Signal* signal, Ptr<Datafile>);
251 
252   void release_extent_pages(Signal* signal, Ptr<Datafile> ptr);
253   void release_extent_pages_callback(Signal*, Uint32, Uint32);
254 
255   struct req
256   {
257     Uint32 m_extent_pages;
258     Uint32 m_extent_size;
259     Uint32 m_extent_no;      // on extent page
260     Uint32 m_extent_page_no;
261   };
262 
263   struct req lookup_extent(Uint32 page_no, const Datafile*) const;
264   Uint32 calc_page_no_in_extent(Uint32 page_no, const struct req* val) const;
265 };
266 
267 inline
268 Tsman::req
lookup_extent(Uint32 page_no,const Datafile * filePtrP) const269 Tsman::lookup_extent(Uint32 page_no, const Datafile * filePtrP) const
270 {
271   struct req val;
272   val.m_extent_size = filePtrP->m_extent_size;
273   val.m_extent_pages = filePtrP->m_online.m_offset_data_pages;
274   Uint32 per_page = filePtrP->m_online.m_extent_headers_per_extent_page;
275 
276   Uint32 extent =
277     (page_no - val.m_extent_pages) / val.m_extent_size + per_page;
278 
279   val.m_extent_page_no = extent / per_page;
280   val.m_extent_no = extent % per_page;
281   return val;
282 }
283 
284 inline
285 Uint32
calc_page_no_in_extent(Uint32 page_no,const Tsman::req * val) const286 Tsman::calc_page_no_in_extent(Uint32 page_no, const Tsman::req* val) const
287 {
288   return (page_no - val->m_extent_pages) % val->m_extent_size;
289 }
290 
291 class Tablespace_client
292 {
293 public:
294   Uint32 m_block;
295   Tsman * m_tsman;
296   Signal* m_signal;
297   Uint32 m_table_id;
298   Uint32 m_fragment_id;
299   Uint32 m_tablespace_id;
300   bool m_lock;
301   DEBUG_OUT_DEFINES(TSMAN);
302 
303 public:
Tablespace_client(Signal * signal,SimulatedBlock * block,Tsman * tsman,Uint32 table,Uint32 fragment,Uint32 tablespaceId,bool lock=true)304   Tablespace_client(Signal* signal, SimulatedBlock* block, Tsman* tsman,
305 		    Uint32 table, Uint32 fragment, Uint32 tablespaceId,
306                     bool lock = true) {
307     Uint32 bno = block->number();
308     Uint32 ino = block->instance();
309     m_block= numberToBlock(bno, ino);
310     m_tsman= tsman;
311     m_signal= signal;
312     m_table_id= table;
313     m_fragment_id= fragment;
314     m_tablespace_id= tablespaceId;
315     m_lock = lock;
316 
317     D("client ctor " << bno << "/" << ino
318       << V(m_table_id) << V(m_fragment_id) << V(m_tablespace_id));
319     if (m_lock)
320       m_tsman->client_lock(m_block, 0);
321   }
322 
323   Tablespace_client(Signal* signal, Tsman* tsman, Local_key* key);//undef
324 
~Tablespace_client()325   ~Tablespace_client() {
326 #ifdef VM_TRACE
327     Uint32 bno = blockToMain(m_block);
328     Uint32 ino = blockToInstance(m_block);
329 #endif
330     D("client dtor " << bno << "/" << ino);
331     if (m_lock)
332       m_tsman->client_unlock(m_block, 0);
333   }
334 
335   /**
336    * Return >0 if success, no of pages in extent, sets key
337    *        <0 if failure, -error code
338    */
339   int alloc_extent(Local_key* key);
340 
341   /**
342    * Allocated a page from an extent
343    *   performs linear search in extent free bits until it find
344    *   page that has atleast <em>bits</em> bits free
345    *
346    * Start search from key->m_page_no
347    *   and return found page in key->m_page_no
348    *   this make sequential calls find sequential pages
349    *
350    * If page is found, then the _unlogged_ "page allocated bit" is set
351    *   so that page can't be allocated twice unless freed first
352    *
353    * Note: user of allocated page should use update_page_free_bits
354    *       to undo log changes in free space on page
355    *
356    * Return <0 if none found
357    *       >=0 if found, then free bits of page found is returned
358    */
359   int alloc_page_from_extent(Local_key* key, unsigned bits);
360 
361   /**
362    * Free extent
363    */
364   int free_extent(Local_key* key, Uint64 lsn);
365 
366   /**
367    * Update page free bits
368    */
369   int update_page_free_bits(Local_key*, unsigned bits);
370 
371   /**
372    * Get page free bits
373    */
374   int get_page_free_bits(Local_key*,
375 			 unsigned* uncommitted, unsigned* committed);
376 
377   /**
378    * Update unlogged page free bit
379    */
380   int unmap_page(Local_key*, Uint32 bits);
381 
382   /**
383    * Undo handling of page bits
384    */
385   int restart_undo_page_free_bits(Local_key*, unsigned bits);
386 
387   /**
388    * Get tablespace info
389    *
390    * Store result in <em>rep</em>
391    *
392    * Return  0 - on sucess
393    *        <0 - on error
394    */
395   int get_tablespace_info(CreateFilegroupImplReq* rep);
396 
397   /**
398    * Update lsn of page corresponing to key
399    */
400   int update_lsn(Local_key* key, Uint64 lsn);
401 };
402 
403 inline
404 int
alloc_extent(Local_key * key)405 Tablespace_client::alloc_extent(Local_key* key)
406 {
407   AllocExtentReq* req = (AllocExtentReq*)m_signal->theData;
408   req->request.table_id = m_table_id;
409   req->request.fragment_id = m_fragment_id;
410   req->request.tablespace_id = m_tablespace_id;
411   m_tsman->execALLOC_EXTENT_REQ(m_signal);
412 
413   if(req->reply.errorCode == 0){
414     * key = req->reply.page_id;
415     D("alloc_extent" << V(*key) << V(req->reply.page_count));
416     return req->reply.page_count;
417   } else {
418     return -(int)req->reply.errorCode;
419   }
420 }
421 
422 inline
423 int
alloc_page_from_extent(Local_key * key,Uint32 bits)424 Tablespace_client::alloc_page_from_extent(Local_key* key, Uint32 bits)
425 {
426   AllocPageReq* req = (AllocPageReq*)m_signal->theData;
427   req->key= *key;
428   req->bits= bits;
429   req->request.table_id = m_table_id;
430   req->request.fragment_id = m_fragment_id;
431   req->request.tablespace_id = m_tablespace_id;
432   m_tsman->execALLOC_PAGE_REQ(m_signal);
433 
434   if(req->reply.errorCode == 0){
435     *key = req->key;
436     D("alloc_page_from_extent" << V(*key) << V(bits) << V(req->bits));
437     return req->bits;
438   } else {
439     return -(int)req->reply.errorCode;
440   }
441 }
442 
443 inline
444 int
free_extent(Local_key * key,Uint64 lsn)445 Tablespace_client::free_extent(Local_key* key, Uint64 lsn)
446 {
447   FreeExtentReq* req = (FreeExtentReq*)m_signal->theData;
448   req->request.key = *key;
449   req->request.table_id = m_table_id;
450   req->request.tablespace_id = m_tablespace_id;
451   req->request.lsn_hi = (Uint32)(lsn >> 32);
452   req->request.lsn_lo = (Uint32)(lsn & 0xFFFFFFFF);
453   m_tsman->execFREE_EXTENT_REQ(m_signal);
454 
455   if(req->reply.errorCode == 0){
456     D("free_extent" << V(*key) << V(lsn));
457     return 0;
458   } else {
459     return -(int)req->reply.errorCode;
460   }
461 }
462 
463 inline
464 int
update_page_free_bits(Local_key * key,unsigned committed_bits)465 Tablespace_client::update_page_free_bits(Local_key *key,
466 					 unsigned committed_bits)
467 {
468   D("update_page_free_bits" << V(*key) << V(committed_bits));
469   return m_tsman->update_page_free_bits(m_signal, key, committed_bits);
470 }
471 
472 inline
473 int
get_page_free_bits(Local_key * key,unsigned * uncommited,unsigned * commited)474 Tablespace_client::get_page_free_bits(Local_key *key,
475 				      unsigned* uncommited,
476 				      unsigned* commited)
477 {
478   return m_tsman->get_page_free_bits(m_signal, key, uncommited, commited);
479 }
480 
481 inline
482 int
unmap_page(Local_key * key,unsigned uncommitted_bits)483 Tablespace_client::unmap_page(Local_key *key, unsigned uncommitted_bits)
484 {
485   return m_tsman->unmap_page(m_signal, key, uncommitted_bits);
486 }
487 
488 inline
489 int
restart_undo_page_free_bits(Local_key * key,unsigned committed_bits)490 Tablespace_client::restart_undo_page_free_bits(Local_key* key,
491 					       unsigned committed_bits)
492 {
493   return m_tsman->restart_undo_page_free_bits(m_signal,
494 					      m_table_id,
495 					      m_fragment_id,
496 					      key,
497 					      committed_bits);
498 }
499 
500 
501 #undef JAM_FILE_ID
502 
503 #endif
504