/* Copyright (C) 2003 MySQL AB This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef TSMAN_H #define TSMAN_H #include <SimulatedBlock.hpp> #include <SLList.hpp> #include <DLList.hpp> #include <NodeBitmask.hpp> #include <signaldata/GetTabInfo.hpp> #include "lgman.hpp" #include "pgman.hpp" class Tsman : public SimulatedBlock { public: Tsman(const Configuration & conf, class Pgman*, class Lgman*); virtual ~Tsman(); BLOCK_DEFINES(Tsman); protected: void execSTTOR(Signal* signal); void sendSTTORRY(Signal*); void execREAD_CONFIG_REQ(Signal* signal); void execDUMP_STATE_ORD(Signal* signal); void execCONTINUEB(Signal* signal); void execCREATE_FILE_REQ(Signal* signal); void execCREATE_FILEGROUP_REQ(Signal* signal); void execDROP_FILE_REQ(Signal* signal); void execDROP_FILEGROUP_REQ(Signal* signal); void execSTART_RECREQ(Signal*); void execFSWRITEREQ(Signal*); void execFSOPENREF(Signal*); void execFSOPENCONF(Signal*); void execFSREADREF(Signal*); void execFSREADCONF(Signal*); void execFSCLOSEREF(Signal*); void execFSCLOSECONF(Signal*); void execALLOC_EXTENT_REQ(Signal*); void execFREE_EXTENT_REQ(Signal*); void execALLOC_PAGE_REQ(Signal* signal); void execEND_LCP_REQ(Signal*); void end_lcp(Signal*, Uint32 tablespace, Uint32 list, Uint32 file); void execGET_TABINFOREQ(Signal*); void sendGET_TABINFOREF(Signal* signal, GetTabInfoReq * req, GetTabInfoRef::ErrorCode errorCode); public: struct Datafile { Datafile(){} Datafile(const struct CreateFileImplReq*); /** * m_file_no * - Unique among datafiles on this node * - Part of local key * - Set by pgman */ Uint32 m_file_no; Uint32 m_file_id; // Used when talking to DICT Uint32 m_fd; // NDBFS Uint32 m_tablespace_ptr_i; Uint32 m_extent_size; Uint32 m_state; enum FileState { FS_CREATING = 0x1, FS_ONLINE = 0x2, FS_DROPPING = 0x4 }; union { struct { Uint32 m_first_free_extent; Uint32 m_lcp_free_extent_head; // extents freed but not LCP Uint32 m_lcp_free_extent_tail; Uint32 m_offset_data_pages; // 1(zero) + extent header pages Uint32 m_data_pages; Uint32 m_used_extent_cnt; } m_online; struct { Uint32 m_senderData; Uint32 m_senderRef; Uint32 m_data_pages; Uint32 m_extent_pages; Uint32 m_requestInfo; union { Uint32 m_page_ptr_i; Uint32 m_loading_extent_page; }; } m_create; }; Uint32 nextHash; Uint32 prevHash; Uint32 nextList; union { Uint32 prevList; Uint32 nextPool; }; Uint32 hashValue() const { return m_file_no; } bool equal(const Datafile& rec) const { return m_file_no == rec.m_file_no; } }; struct Tablespace { Tablespace(){} Tablespace(Tsman*, Lgman*, const struct CreateFilegroupImplReq*); union { Uint32 key; Uint32 m_tablespace_id; }; Uint32 m_version; Uint32 m_state; enum TablespaceState { TS_CREATING = 0x1, TS_ONLINE = 0x2, TS_DROPPING = 0x4 }; Uint32 m_extent_size; // In pages DLList<Datafile>::Head m_free_files; // Files w/ free space Logfile_client m_logfile_client; DLList<Datafile>::Head m_full_files; // Files wo/ free space DLList<Datafile>::Head m_meta_files; // Files being created/dropped Uint32 nextHash; Uint32 prevHash; Uint32 nextList; union { Uint32 prevList; Uint32 nextPool; }; Uint32 hashValue() const { return key; } bool equal(const Tablespace& rec) const { return key == rec.key; } }; private: friend class Tablespace_client; ArrayPool<Datafile> m_file_pool; ArrayPool<Tablespace> m_tablespace_pool; DLHashTable<Datafile> m_file_hash; DLList<Tablespace> m_tablespace_list; KeyTable<Tablespace> m_tablespace_hash; Page_cache_client m_page_cache_client; Lgman * const m_lgman; int open_file(Signal*, Ptr<Tablespace>, Ptr<Datafile>, CreateFileImplReq*); void load_extent_pages(Signal* signal, Ptr<Datafile> ptr); void load_extent_page_callback(Signal*, Uint32, Uint32); void create_file_ref(Signal*, Ptr<Tablespace>, Ptr<Datafile>, Uint32,Uint32,Uint32); int update_page_free_bits(Signal*, Local_key*, unsigned committed_bits, Uint64 lsn); int get_page_free_bits(Signal*, Local_key*, unsigned*, unsigned*); int unmap_page(Signal*, Local_key*, unsigned uncommitted_bits); int restart_undo_page_free_bits(Signal*, Uint32, Uint32, Local_key*, unsigned committed_bits, Uint64 lsn); int alloc_extent(Signal* signal, Uint32 tablespace, Local_key* key); int alloc_page_from_extent(Signal*, Uint32, Local_key*, Uint32 bits); void scan_tablespace(Signal*, Uint32 ptrI); void scan_datafile(Signal*, Uint32, Uint32); void scan_extent_headers(Signal*, Ptr<Datafile>); bool find_file_by_id(Ptr<Datafile>&, DLList<Datafile>::Head&, Uint32 id); void create_file_abort(Signal* signal, Ptr<Datafile>); void release_extent_pages(Signal* signal, Ptr<Datafile> ptr); void release_extent_pages_callback(Signal*, Uint32, Uint32); }; class Tablespace_client { Tsman * m_tsman; Signal* m_signal; Uint32 m_table_id; Uint32 m_fragment_id; Uint32 m_tablespace_id; public: Tablespace_client(Signal* signal, Tsman* tsman, Uint32 table, Uint32 fragment, Uint32 tablespaceId) { m_tsman= tsman; m_signal= signal; m_table_id= table; m_fragment_id= fragment; m_tablespace_id= tablespaceId; } /** * Return >0 if success, no of pages in extent, sets key * <0 if failure, -error code */ int alloc_extent(Local_key* key); /** * Allocated a page from an extent * performs linear search in extent free bits until it find * page that has atleast <em>bits</em> bits free * * Start search from key->m_page_no * and return found page in key->m_page_no * this make sequential calls find sequential pages * * If page is found, then the _unlogged_ "page allocated bit" is set * so that page can't be allocated twice unless freed first * * Note: user of allocated page should use update_page_free_bits * to undo log changes in free space on page * * Return <0 if none found * >=0 if found, then free bits of page found is returned */ int alloc_page_from_extent(Local_key* key, unsigned bits); /** * Free extent */ int free_extent(Local_key* key); /** * Update page free bits */ int update_page_free_bits(Local_key*, unsigned bits, Uint64 lsn); /** * Get page free bits */ int get_page_free_bits(Local_key*, unsigned* uncommitted, unsigned* committed); /** * Update unlogged page free bit */ int unmap_page(Local_key*, Uint32 bits); /** * Undo handling of page bits */ int restart_undo_page_free_bits(Local_key*, unsigned bits, Uint64 lsn); /** * Get tablespace info * * Store result in <em>rep</em> * * Return 0 - on sucess * <0 - on error */ int get_tablespace_info(CreateFilegroupImplReq* rep); }; #include <signaldata/Extent.hpp> inline int Tablespace_client::alloc_extent(Local_key* key) { AllocExtentReq* req = (AllocExtentReq*)m_signal->theData; req->request.table_id = m_table_id; req->request.fragment_id = m_fragment_id; req->request.tablespace_id = m_tablespace_id; m_tsman->execALLOC_EXTENT_REQ(m_signal); if(req->reply.errorCode == 0){ * key = req->reply.page_id; return req->reply.page_count; } else { return -req->reply.errorCode; } } inline int Tablespace_client::alloc_page_from_extent(Local_key* key, Uint32 bits) { AllocPageReq* req = (AllocPageReq*)m_signal->theData; req->key= *key; req->bits= bits; req->request.table_id = m_table_id; req->request.fragment_id = m_fragment_id; req->request.tablespace_id = m_tablespace_id; m_tsman->execALLOC_PAGE_REQ(m_signal); if(req->reply.errorCode == 0){ *key = req->key; return req->bits; } else { return -req->reply.errorCode; } } inline int Tablespace_client::free_extent(Local_key* key) { FreeExtentReq* req = (FreeExtentReq*)m_signal->theData; req->request.key = *key; req->request.table_id = m_table_id; req->request.tablespace_id = m_tablespace_id; m_tsman->execFREE_EXTENT_REQ(m_signal); if(req->reply.errorCode == 0){ return 0; } else { return -req->reply.errorCode; } } inline int Tablespace_client::update_page_free_bits(Local_key *key, unsigned committed_bits, Uint64 lsn) { return m_tsman->update_page_free_bits(m_signal, key, committed_bits, lsn); } inline int Tablespace_client::get_page_free_bits(Local_key *key, unsigned* uncommited, unsigned* commited) { return m_tsman->get_page_free_bits(m_signal, key, uncommited, commited); } inline int Tablespace_client::unmap_page(Local_key *key, unsigned uncommitted_bits) { return m_tsman->unmap_page(m_signal, key, uncommitted_bits); } inline int Tablespace_client::restart_undo_page_free_bits(Local_key* key, unsigned committed_bits, Uint64 lsn) { return m_tsman->restart_undo_page_free_bits(m_signal, m_table_id, m_fragment_id, key, committed_bits, lsn); } #endif