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