The world's most popular open source database
00001 /* Copyright (C) 2003 MySQL AB 00002 00003 This program is free software; you can redistribute it and/or modify 00004 it under the terms of the GNU General Public License as published by 00005 the Free Software Foundation; either version 2 of the License, or 00006 (at your option) any later version. 00007 00008 This program is distributed in the hope that it will be useful, 00009 but WITHOUT ANY WARRANTY; without even the implied warranty of 00010 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00011 GNU General Public License for more details. 00012 00013 You should have received a copy of the GNU General Public License 00014 along with this program; if not, write to the Free Software 00015 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ 00016 00017 #ifndef PGMAN_H 00018 #define PGMAN_H 00019 00020 #include <SimulatedBlock.hpp> 00021 00022 #include <DLCHashTable.hpp> 00023 #include <DLCFifoList.hpp> 00024 #include <NodeBitmask.hpp> 00025 #include <signaldata/LCP.hpp> 00026 #include "lgman.hpp" 00027 00028 #include <NdbOut.hpp> 00029 #include <OutputStream.hpp> 00030 00031 /* 00032 * PGMAN 00033 * 00034 * PAGE ENTRIES AND REQUESTS 00035 * 00036 * Central structure is "page entry". It corresponds to a disk page 00037 * identified by file and page number (file_no, page_no). 00038 * 00039 * A page entry is created by first request for the disk page. 00040 * Subsequent requests are queued under the same page entry. 00041 * 00042 * There is a limited number of in-memory "cache pages", also called 00043 * "buffer pages" or "real pages". These are used by the more numerous 00044 * page entries to buffer the disk pages. 00045 * 00046 * A new or non-resident page entry must first be "bound" to an 00047 * available cache page. Next the disk page must be "mapped" to the 00048 * cache page. If the page is empty (never written) it is considered 00049 * mapped trivially. Otherwise the cache page must be updated via 00050 * "pagein" from disk. A bound and mapped page is called "resident". 00051 * 00052 * Updating a resident cache page makes it "dirty". A background 00053 * clean-up process makes dirty pages "clean" via "pageout" to disk. 00054 * Write ahead logging (WAL) of the page is done first i.e. UNDO log is 00055 * flushed up to the page log sequence number (LSN) by calling a TSMAN 00056 * method. The reason for this is obvious but not relevant to PGMAN. 00057 * 00058 * A local check point (LCP) periodically performs a complete pageout of 00059 * dirty pages. It must iterate over a list which will cover all pages 00060 * which had been dirty since LCP start. 00061 * 00062 * A clean page is a candidate ("victim") for being "unmapped" and 00063 * "evicted" from the cache, to allow another page to become resident. 00064 * This process is called "page replacement". 00065 * 00066 * PAGE REPLACEMENT 00067 * 00068 * Page replacement uses the LIRS algorithm (Jiang-Zhang). 00069 * 00070 * The "recency" of a page is the time between now and the last request 00071 * for the page. The "inter-reference recency" (IRR) of a page is the 00072 * time between the last 2 requests for the page. "Time" is advanced by 00073 * request for any page. 00074 * 00075 * Page entries are divided into "hot" ("lir") and "cold" ("hir"). Here 00076 * lir/hir refers to low/high IRR. Hot pages are always resident but 00077 * cold pages need not be. 00078 * 00079 * Number of hot pages is limited to slightly less than number of cache 00080 * pages. Until this number is reached, all used cache pages are hot. 00081 * Then the algorithm described next is applied. The algorithm avoids 00082 * storing any of the actual recency values. 00083 * 00084 * Primary data structure is the "stack". It contains all hot entries 00085 * and recently referenced cold entries (resident or not). The stack is 00086 * in recency order with most recent (lowest recency) entry on top. 00087 * Entries which are less recent than the least recent hot page are 00088 * removed ("stack pruning"). So the bottom page is always hot. 00089 * 00090 * The cold entries on the stack are undergoing a "trial period". If 00091 * they are referenced soon again (see IRR), they become hot. Otherwise 00092 * they fall off the bottom of the stack. 00093 * 00094 * Secondary data structure is the "queue". It contains all resident 00095 * cold pages (on stack or not). When a hot page is removed from the 00096 * stack it is added to the end of the queue. When page replacement 00097 * needs a page it removes it from the front of the queue. 00098 * 00099 * Page requests cause the input entry to be inserted and updated in 00100 * LIRS lists. Remember that an entry can be present on both stack and 00101 * queue. The rules per type of input entry are: 00102 * 00103 * 1. Hot. Move input entry to stack top. If input entry was at stack 00104 * bottom, do stack pruning. 00105 * 00106 * 2. Cold resident. Move input entry to stack top. Then: 00107 * 00108 * 2a. If input entry was on stack, change it to hot, remove it from 00109 * queue, change stack bottom entry to cold and move the bottom entry to 00110 * queue end, and do stack pruning. 00111 * 00112 * 2b. If input entry was on queue only, leave it cold but move it to 00113 * end of queue. 00114 * 00115 * 3. Cold non-resident. Remove entry at queue front and evict it from 00116 * the cache. If the evicted entry was on stack, it remains as unbound 00117 * entry on stack, to continue its trial period. Map input entry to the 00118 * freed cache page. Move input entry to stack top. Then: 00119 * 00120 * 3a. If input entry was on stack, change it to hot, change stack 00121 * bottom entry to cold and move the bottom entry to queue end, and do 00122 * stack pruning. 00123 * 00124 * 3b. If input entry was new, leave it cold but move it to end of 00125 * queue. 00126 * 00127 * LIRS CHANGES 00128 * 00129 * In LIRS the 'resident' requirement is changed as follows: 00130 * 00131 * Stack entries, including hot ones, can have any state. Unbound stack 00132 * entries are created by new requests and by pages evicted from queue 00133 * front which are still on stack. 00134 * 00135 * Queue entries must be bound. They become resident and evictable 00136 * within a finite time. A page is "evictable" if it is mapped, clean, 00137 * and has no requests. 00138 * 00139 * An unbound entry which should be on queue is added there at bind 00140 * time. Such entries are created when an unbound entry with open 00141 * requests is popped (hot) or pruned (cold) from the stack. This can 00142 * happen if the cache is too small. 00143 * 00144 * CLEANUP PROCESS 00145 * 00146 * LIRS (and related algorithms) do not address dirty pages. From above 00147 * it is obvious that the clean-up process should process dirty queue 00148 * entries proceeding from front to end. This also favors pages with 00149 * lower LSN numbers which minimizes amount of WAL to write. 00150 * 00151 * In fact the clean-up process holds a permanent pointer into the queue 00152 * where all entries strictly towards the front are clean. For such an 00153 * entry to become dirty it must be referenced again which moves it to 00154 * queue end and past the clean-up pointer. (In practice, until this 00155 * works, cleanup recycles back to queue front). 00156 * 00157 * PAGE LISTS 00158 * 00159 * Page entries are put on a number of lists. 00160 * 00161 * 1. Hash table on (file_no, page_no). Used for fast lookup and for 00162 * LCP to iterate over. 00163 * 00164 * The other lists are doubly-linked FIFOs. In general entries are 00165 * added to the end (last entry) and processed from the front (first 00166 * entry). When used as stack, end is top and front is bottom. 00167 * 00168 * 2. The LIRS stack and queue. These control page replacement. 00169 * 00170 * 3. Page entries are divided into disjoint "sublists" based on page 00171 * "state" i.e. the set of page properties. Some sublists drive page 00172 * processing and have next entry to process at the front. 00173 * 00174 * Current sublists are as follows. Those that drive processing are 00175 * marked with a plus (+). 00176 * 00177 * SL_BIND + waiting for available buffer page 00178 * SL_MAP + waiting to start pagein from disk 00179 * SL_MAP_IO - above in i/o wait (the pagein) 00180 * SL_CALLBACK + request done, waiting to invoke callbacks 00181 * SL_CALLBACK_IO - above in i/o wait (pageout by cleanup) 00182 * SL_BUSY - being written to by PGMAN client 00183 * SL_LOCKED - permanently locked to cache 00184 * SL_OTHER - default sublist 00185 * 00186 * PAGE PROCESSING 00187 * 00188 * Page processing uses a number independent continueB loops. 00189 * 00190 * 1. The "stats loop". Started at node start. Checks lists in debug 00191 * mode. In the future could gather statistics and adjust parameters 00192 * based on load. Continues via delay signal. 00193 * 00194 * 2. The "busy loop". Started by page request. Each loop does bind, 00195 * map, and callback of a number of entries. Continues via no-delay 00196 * signal until nothing to do. 00197 * 00198 * 3. The "cleanup loop". Started at node start. Each loop starts 00199 * pageout of a number of dirty queue entries. Continues via delay 00200 * signal. 00201 * 00202 * 4. The "LCP loop". Started periodically by NDB. Each loop starts 00203 * pageout of a number of hash list entries. Continues via delay signal 00204 * until done. 00205 * 00206 * SPECIAL CASES 00207 * 00208 * LOCKED pages are not put on stack or queue. They are flushed to disk 00209 * by LCP but not by clean-up. 00210 * 00211 * A TUP scan is likely to access a page repeatedly within a short time. 00212 * This can make the page hot when it should not be. Such "correlated 00213 * requests" are handled by a request flag which modifies default LIRS 00214 * processing. [fill in details later] 00215 * 00216 * Also PK operations make 2 rapid page references. The 2nd one is for 00217 * commit. This too should be handled as a correlated request. 00218 * 00219 * CLIENT TSMAN 00220 * 00221 * TSMAN reads "meta" pages such as extent headers. There are currently 00222 * "locked" forever in PGMAN cache. 00223 * 00224 * CLIENT DBTUP 00225 * 00226 * DBTUP works with copy pages (or UNDO buffers) in memory. The real 00227 * page is updated only between page request with COMMIT_REQ flag and 00228 * a subsequent LSN update. These need not occur in same timeslice 00229 * since DBTUP may need to flush UNDO log in-between. 00230 * 00231 * The page is "busy" if any transaction is between COMMIT_REQ and LSN 00232 * update. A busy page must be locked in buffer cache. No pageout of 00233 * a busy page can be started by clean-up or LCP. 00234 */ 00235 00236 class Pgman : public SimulatedBlock 00237 { 00238 public: 00239 Pgman(Block_context& ctx); 00240 virtual ~Pgman(); 00241 BLOCK_DEFINES(Pgman); 00242 00243 private: 00244 friend class Page_cache_client; 00245 00246 struct Page_entry; // CC 00247 friend struct Page_entry; 00248 00249 struct Page_request { 00250 enum Flags { 00251 OP_MASK = 0x000F // 4 bits for TUP operation 00252 ,LOCK_PAGE = 0x0020 // lock page in memory 00253 ,EMPTY_PAGE = 0x0040 // empty (new) page 00254 ,ALLOC_REQ = 0x0080 // part of alloc 00255 ,COMMIT_REQ = 0x0100 // part of commit 00256 ,DIRTY_REQ = 0x0200 // make page dirty wo/ update_lsn 00257 ,UNLOCK_PAGE = 0x0400 00258 ,CORR_REQ = 0x0800 // correlated request (no LIRS update) 00259 #ifdef ERROR_INSERT 00260 ,DELAY_REQ = 0x1000 // Force request to be delayed 00261 #endif 00262 }; 00263 00264 Uint16 m_block; 00265 Uint16 m_flags; 00266 SimulatedBlock::Callback m_callback; 00267 00268 #ifdef ERROR_INSERT 00269 Uint64 m_delay_until_time; 00270 #endif 00271 Uint32 nextList; 00272 Uint32 m_magic; 00273 }; 00274 00275 typedef RecordPool<Page_request, WOPool> Page_request_pool; 00276 typedef SLFifoListImpl<Page_request_pool, Page_request> Page_request_list; 00277 typedef LocalSLFifoListImpl<Page_request_pool, Page_request> Local_page_request_list; 00278 00279 struct Page_entry_stack_ptr { 00280 Uint32 nextList; 00281 Uint32 prevList; 00282 }; 00283 00284 struct Page_entry_queue_ptr { 00285 Uint32 nextList; 00286 Uint32 prevList; 00287 }; 00288 00289 struct Page_entry_sublist_ptr { 00290 Uint32 nextList; 00291 Uint32 prevList; 00292 }; 00293 00294 typedef Uint16 Page_state; 00295 00296 struct Page_entry : Page_entry_stack_ptr, 00297 Page_entry_queue_ptr, 00298 Page_entry_sublist_ptr { 00299 Page_entry() {} 00300 Page_entry(Uint32 file_no, Uint32 page_no); 00301 00302 enum State { 00303 NO_STATE = 0x0000 00304 ,REQUEST = 0x0001 // has outstanding request 00305 ,EMPTY = 0x0002 // empty (never written) page 00306 ,BOUND = 0x0004 // m_real_page_ptr assigned 00307 ,MAPPED = 0x0008 // bound, and empty or paged in 00308 ,DIRTY = 0x0010 // page is modified 00309 ,USED = 0x0020 // used by some tx (not set currently) 00310 ,BUSY = 0x0040 // page is being written to 00311 ,LOCKED = 0x0080 // locked in cache (forever) 00312 ,PAGEIN = 0x0100 // paging in 00313 ,PAGEOUT = 0x0200 // paging out 00314 ,LOGSYNC = 0x0400 // undo WAL as part of pageout 00315 ,LCP = 0x1000 // page is LCP flushed 00316 ,HOT = 0x2000 // page is hot 00317 ,ONSTACK = 0x4000 // page is on LIRS stack 00318 ,ONQUEUE = 0x8000 // page is on LIRS queue 00319 }; 00320 00321 enum Sublist { 00322 SL_BIND = 0 00323 ,SL_MAP = 1 00324 ,SL_MAP_IO = 2 00325 ,SL_CALLBACK = 3 00326 ,SL_CALLBACK_IO = 4 00327 ,SL_BUSY = 5 00328 ,SL_LOCKED = 6 00329 ,SL_OTHER = 7 00330 ,SUBLIST_COUNT = 8 00331 }; 00332 00333 Uint16 m_file_no; // disk page address set at seize 00334 Page_state m_state; // flags (0 for new entry) 00335 00336 Uint32 m_page_no; 00337 Uint32 m_real_page_i; 00338 Uint64 m_lsn; 00339 00340 Uint32 m_last_lcp; 00341 Uint32 m_dirty_count; 00342 Uint32 m_copy_page_i; 00343 union { 00344 Uint32 m_busy_count; // non-zero means BUSY 00345 Uint32 nextPool; 00346 }; 00347 00348 Page_request_list::Head m_requests; 00349 00350 Uint32 nextHash; 00351 Uint32 prevHash; 00352 00353 Uint32 hashValue() const { return m_file_no << 16 | m_page_no; } 00354 bool equal(const Page_entry& obj) const { 00355 return 00356 m_file_no == obj.m_file_no && m_page_no == obj.m_page_no; 00357 } 00358 00359 #ifdef VM_TRACE 00360 Pgman* m_this; 00361 #endif 00362 }; 00363 00364 typedef DLCHashTable<Page_entry> Page_hashlist; 00365 typedef DLCFifoList<Page_entry, Page_entry_stack_ptr> Page_stack; 00366 typedef DLCFifoList<Page_entry, Page_entry_queue_ptr> Page_queue; 00367 typedef DLCFifoList<Page_entry, Page_entry_sublist_ptr> Page_sublist; 00368 00369 class Dbtup *c_tup; 00370 Logfile_client m_lgman; 00371 00372 // loop status 00373 bool m_stats_loop_on; 00374 bool m_busy_loop_on; 00375 bool m_cleanup_loop_on; 00376 bool m_lcp_loop_on; 00377 00378 // LCP variables 00379 Uint32 m_last_lcp; 00380 Uint32 m_last_lcp_complete; 00381 Uint32 m_lcp_curr_bucket; 00382 Uint32 m_lcp_outstanding; // remaining i/o waits 00383 EndLcpReq m_end_lcp_req; 00384 00385 // clean-up variables 00386 Ptr<Page_entry> m_cleanup_ptr; 00387 00388 // file map 00389 typedef DataBuffer<15> File_map; 00390 File_map m_file_map; 00391 File_map::DataBufferPool m_data_buffer_pool; 00392 00393 // page entries and requests 00394 Page_request_pool m_page_request_pool; 00395 ArrayPool<Page_entry> m_page_entry_pool; 00396 Page_hashlist m_page_hashlist; 00397 Page_stack m_page_stack; 00398 Page_queue m_page_queue; 00399 Page_sublist* m_page_sublist[Page_entry::SUBLIST_COUNT]; 00400 00401 // configuration 00402 struct Param { 00403 Param(); 00404 Uint32 m_max_pages; // max number of cache pages 00405 Uint32 m_max_hot_pages; // max hot cache pages (up to 99%) 00406 Uint32 m_max_loop_count; // limit purely local loops 00407 Uint32 m_max_io_waits; 00408 Uint32 m_stats_loop_delay; 00409 Uint32 m_cleanup_loop_delay; 00410 Uint32 m_lcp_loop_delay; 00411 } m_param; 00412 00413 // runtime sizes and statistics 00414 struct Stats { 00415 Stats(); 00416 Uint32 m_num_pages; // current number of cache pages 00417 Uint32 m_page_hits; 00418 Uint32 m_page_faults; 00419 Uint32 m_current_io_waits; 00420 } m_stats; 00421 00422 protected: 00423 void execSTTOR(Signal* signal); 00424 void sendSTTORRY(Signal*); 00425 void execREAD_CONFIG_REQ(Signal* signal); 00426 void execCONTINUEB(Signal* signal); 00427 00428 void execLCP_FRAG_ORD(Signal*); 00429 void execEND_LCP_REQ(Signal*); 00430 00431 void execFSREADCONF(Signal*); 00432 void execFSREADREF(Signal*); 00433 void execFSWRITECONF(Signal*); 00434 void execFSWRITEREF(Signal*); 00435 00436 void execDUMP_STATE_ORD(Signal* signal); 00437 00438 private: 00439 static Uint32 get_sublist_no(Page_state state); 00440 void set_page_state(Ptr<Page_entry> ptr, Page_state new_state); 00441 00442 bool seize_cache_page(Ptr<GlobalPage>& gptr); 00443 void release_cache_page(Uint32 i); 00444 00445 bool find_page_entry(Ptr<Page_entry>&, Uint32 file_no, Uint32 page_no); 00446 Uint32 seize_page_entry(Ptr<Page_entry>&, Uint32 file_no, Uint32 page_no); 00447 bool get_page_entry(Ptr<Page_entry>&, Uint32 file_no, Uint32 page_no); 00448 void release_page_entry(Ptr<Page_entry>&); 00449 00450 void lirs_stack_prune(); 00451 void lirs_stack_pop(); 00452 void lirs_reference(Ptr<Page_entry> ptr); 00453 00454 void do_stats_loop(Signal*); 00455 void do_busy_loop(Signal*, bool direct = false); 00456 void do_cleanup_loop(Signal*); 00457 void do_lcp_loop(Signal*, bool direct = false); 00458 00459 bool process_bind(Signal*); 00460 bool process_bind(Signal*, Ptr<Page_entry> ptr); 00461 bool process_map(Signal*); 00462 bool process_map(Signal*, Ptr<Page_entry> ptr); 00463 bool process_callback(Signal*); 00464 bool process_callback(Signal*, Ptr<Page_entry> ptr); 00465 00466 bool process_cleanup(Signal*); 00467 void move_cleanup_ptr(Ptr<Page_entry> ptr); 00468 00469 bool process_lcp(Signal*); 00470 void process_lcp_locked(Signal* signal, Ptr<Page_entry> ptr); 00471 void process_lcp_locked_fswriteconf(Signal* signal, Ptr<Page_entry> ptr); 00472 00473 void pagein(Signal*, Ptr<Page_entry>); 00474 void fsreadreq(Signal*, Ptr<Page_entry>); 00475 void fsreadconf(Signal*, Ptr<Page_entry>); 00476 void pageout(Signal*, Ptr<Page_entry>); 00477 void logsync_callback(Signal*, Uint32 ptrI, Uint32 res); 00478 void fswritereq(Signal*, Ptr<Page_entry>); 00479 void fswriteconf(Signal*, Ptr<Page_entry>); 00480 00481 int get_page(Signal*, Ptr<Page_entry>, Page_request page_req); 00482 void update_lsn(Ptr<Page_entry>, Uint32 block, Uint64 lsn); 00483 Uint32 create_data_file(); 00484 Uint32 alloc_data_file(Uint32 file_no); 00485 void map_file_no(Uint32 file_no, Uint32 fd); 00486 void free_data_file(Uint32 file_no, Uint32 fd = RNIL); 00487 int drop_page(Ptr<Page_entry>); 00488 00489 #ifdef VM_TRACE 00490 NdbOut debugOut; 00491 bool debugFlag; 00492 void verify_page_entry(Ptr<Page_entry> ptr); 00493 void verify_page_lists(); 00494 void verify_all(); 00495 bool dump_page_lists(Uint32 ptrI = RNIL); 00496 void open_debug_file(Uint32 flag); 00497 #endif 00498 static const char* get_sublist_name(Uint32 list_no); 00499 friend class NdbOut& operator<<(NdbOut&, Ptr<Page_request>); 00500 friend class NdbOut& operator<<(NdbOut&, Ptr<Page_entry>); 00501 }; 00502 00503 class NdbOut& operator<<(NdbOut&, Ptr<Pgman::Page_request>); 00504 class NdbOut& operator<<(NdbOut&, Ptr<Pgman::Page_entry>); 00505 00506 class Page_cache_client 00507 { 00508 Uint32 m_block; 00509 Pgman* m_pgman; 00510 00511 public: 00512 Page_cache_client(SimulatedBlock* block, Pgman*); 00513 00514 struct Request { 00515 Local_key m_page; 00516 SimulatedBlock::Callback m_callback; 00517 00518 #ifdef ERROR_INSERT 00519 Uint64 m_delay_until_time; 00520 #endif 00521 }; 00522 00523 Ptr<GlobalPage> m_ptr; // TODO remove 00524 00525 enum RequestFlags { 00526 LOCK_PAGE = Pgman::Page_request::LOCK_PAGE 00527 ,EMPTY_PAGE = Pgman::Page_request::EMPTY_PAGE 00528 ,ALLOC_REQ = Pgman::Page_request::ALLOC_REQ 00529 ,COMMIT_REQ = Pgman::Page_request::COMMIT_REQ 00530 ,DIRTY_REQ = Pgman::Page_request::DIRTY_REQ 00531 ,UNLOCK_PAGE = Pgman::Page_request::UNLOCK_PAGE 00532 ,CORR_REQ = Pgman::Page_request::CORR_REQ 00533 #ifdef ERROR_INSERT 00534 ,DELAY_REQ = Pgman::Page_request::DELAY_REQ 00535 #endif 00536 }; 00537 00546 int get_page(Signal*, Request&, Uint32 flags); 00547 00548 void update_lsn(Local_key, Uint64 lsn); 00549 00557 int drop_page(Local_key, Uint32 page_id); 00558 00562 Uint32 create_data_file(); 00563 00567 Uint32 alloc_data_file(Uint32 file_no); 00568 00572 void map_file_no(Uint32 m_file_no, Uint32 m_fd); 00573 00577 void free_data_file(Uint32 file_no, Uint32 fd = RNIL); 00578 }; 00579 00580 inline int 00581 Page_cache_client::get_page(Signal* signal, Request& req, Uint32 flags) 00582 { 00583 Ptr<Pgman::Page_entry> entry_ptr; 00584 Uint32 file_no = req.m_page.m_file_no; 00585 Uint32 page_no = req.m_page.m_page_no; 00586 00587 #ifdef VM_TRACE 00588 m_pgman->debugOut 00589 << "PGCLI: get_page " << file_no << "," << page_no 00590 << " flags=" << hex << flags << endl; 00591 #endif 00592 00593 // find or seize 00594 bool ok = m_pgman->get_page_entry(entry_ptr, file_no, page_no); 00595 if (! ok) 00596 { 00597 return -1; 00598 } 00599 00600 Pgman::Page_request page_req; 00601 page_req.m_block = m_block; 00602 page_req.m_flags = flags; 00603 page_req.m_callback = req.m_callback; 00604 #ifdef ERROR_INSERT 00605 page_req.m_delay_until_time = req.m_delay_until_time; 00606 #endif 00607 00608 int i = m_pgman->get_page(signal, entry_ptr, page_req); 00609 if (i > 0) 00610 { 00611 // TODO remove 00612 m_pgman->m_global_page_pool.getPtr(m_ptr, (Uint32)i); 00613 } 00614 return i; 00615 } 00616 00617 inline void 00618 Page_cache_client::update_lsn(Local_key key, Uint64 lsn) 00619 { 00620 Ptr<Pgman::Page_entry> entry_ptr; 00621 Uint32 file_no = key.m_file_no; 00622 Uint32 page_no = key.m_page_no; 00623 00624 #ifdef VM_TRACE 00625 m_pgman->debugOut 00626 << "PGCLI: update_lsn " << file_no << "," << page_no 00627 << " lsn=" << lsn << endl; 00628 #endif 00629 00630 bool found = m_pgman->find_page_entry(entry_ptr, file_no, page_no); 00631 assert(found); 00632 00633 m_pgman->update_lsn(entry_ptr, m_block, lsn); 00634 } 00635 00636 inline 00637 int 00638 Page_cache_client::drop_page(Local_key key, Uint32 page_id) 00639 { 00640 Ptr<Pgman::Page_entry> entry_ptr; 00641 Uint32 file_no = key.m_file_no; 00642 Uint32 page_no = key.m_page_no; 00643 00644 #ifdef VM_TRACE 00645 m_pgman->debugOut 00646 << "PGCLI: drop_page " << file_no << "," << page_no << endl; 00647 #endif 00648 00649 bool found = m_pgman->find_page_entry(entry_ptr, file_no, page_no); 00650 assert(found); 00651 assert(entry_ptr.p->m_real_page_i == page_id); 00652 00653 return m_pgman->drop_page(entry_ptr); 00654 } 00655 00656 inline Uint32 00657 Page_cache_client::create_data_file() 00658 { 00659 return m_pgman->create_data_file(); 00660 } 00661 00662 inline Uint32 00663 Page_cache_client::alloc_data_file(Uint32 file_no) 00664 { 00665 return m_pgman->alloc_data_file(file_no); 00666 } 00667 00668 inline void 00669 Page_cache_client::map_file_no(Uint32 file_no, Uint32 fd) 00670 { 00671 m_pgman->map_file_no(file_no, fd); 00672 } 00673 00674 inline void 00675 Page_cache_client::free_data_file(Uint32 file_no, Uint32 fd) 00676 { 00677 m_pgman->free_data_file(file_no, fd); 00678 } 00679 00680 #endif
1.4.7

