1
/* Copyright (C) 2003 MySQL AB
3
This program is free software; you can redistribute it and/or modify
4
it under the terms of the GNU General Public License as published by
5
the Free Software Foundation; version 2 of the License.
7
This program is distributed in the hope that it will be useful,
8
but WITHOUT ANY WARRANTY; without even the implied warranty of
9
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10
GNU General Public License for more details.
12
You should have received a copy of the GNU General Public License
13
along with this program; if not, write to the Free Software
14
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
17
#include <signaldata/FsRef.hpp>
18
#include <signaldata/FsConf.hpp>
19
#include <signaldata/FsReadWriteReq.hpp>
20
#include <signaldata/PgmanContinueB.hpp>
21
#include <signaldata/LCP.hpp>
23
#include <dbtup/Dbtup.hpp>
25
#include <DebuggerNames.hpp>
28
* Requests that make page dirty
30
#define DIRTY_FLAGS (Page_request::COMMIT_REQ | \
31
Page_request::DIRTY_REQ | \
32
Page_request::ALLOC_REQ)
37
do { if (! debugFlag) break; debugOut << "PGMAN: " << x << endl; } while (0)
42
static bool g_dbg_lcp = false;
46
#define DBG_LCP(x) if(g_dbg_lcp) ndbout << x
49
Pgman::Pgman(Block_context& ctx) :
50
SimulatedBlock(PGMAN, ctx),
51
m_file_map(m_data_buffer_pool),
52
m_page_hashlist(m_page_entry_pool),
53
m_page_stack(m_page_entry_pool),
54
m_page_queue(m_page_entry_pool)
56
,debugOut(* new NullOutputStream())
60
BLOCK_CONSTRUCTOR(Pgman);
62
// Add received signals
63
addRecSignal(GSN_STTOR, &Pgman::execSTTOR);
64
addRecSignal(GSN_READ_CONFIG_REQ, &Pgman::execREAD_CONFIG_REQ);
65
addRecSignal(GSN_DUMP_STATE_ORD, &Pgman::execDUMP_STATE_ORD);
66
addRecSignal(GSN_CONTINUEB, &Pgman::execCONTINUEB);
67
addRecSignal(GSN_FSREADREF, &Pgman::execFSREADREF, true);
68
addRecSignal(GSN_FSREADCONF, &Pgman::execFSREADCONF);
69
addRecSignal(GSN_FSWRITEREF, &Pgman::execFSWRITEREF, true);
70
addRecSignal(GSN_FSWRITECONF, &Pgman::execFSWRITECONF);
72
addRecSignal(GSN_LCP_FRAG_ORD, &Pgman::execLCP_FRAG_ORD);
73
addRecSignal(GSN_END_LCP_REQ, &Pgman::execEND_LCP_REQ);
76
m_stats_loop_on = false;
77
m_busy_loop_on = false;
78
m_cleanup_loop_on = false;
79
m_lcp_loop_on = false;
83
m_last_lcp_complete = 0;
84
m_lcp_curr_bucket = ~(Uint32)0;
85
m_lcp_outstanding = 0;
88
m_cleanup_ptr.i = RNIL;
90
// should be a factor larger than number of pool pages
91
m_data_buffer_pool.setSize(16);
92
m_page_hashlist.setSize(512);
94
for (Uint32 k = 0; k < Page_entry::SUBLIST_COUNT; k++)
95
m_page_sublist[k] = new Page_sublist(m_page_entry_pool);
100
for (Uint32 k = 0; k < Page_entry::SUBLIST_COUNT; k++)
101
delete m_page_sublist[k];
104
BLOCK_FUNCTIONS(Pgman)
107
Pgman::execREAD_CONFIG_REQ(Signal* signal)
111
const ReadConfigReq * req = (ReadConfigReq*)signal->getDataPtr();
113
Uint32 ref = req->senderRef;
114
Uint32 senderData = req->senderData;
116
const ndb_mgm_configuration_iterator * p =
117
m_ctx.m_config.getOwnConfigIterator();
120
Uint64 page_buffer = 64*1024*1024;
121
ndb_mgm_get_int64_parameter(p, CFG_DB_DISK_PAGE_BUFFER_MEMORY, &page_buffer);
125
page_buffer = (page_buffer + GLOBAL_PAGE_SIZE - 1) / GLOBAL_PAGE_SIZE; // in pages
126
m_param.m_max_pages = page_buffer;
127
m_page_entry_pool.setSize(m_param.m_lirs_stack_mult * page_buffer);
128
m_param.m_max_hot_pages = (page_buffer * 9) / 10;
133
m_page_request_pool.wo_pool_init(RT_PGMAN_PAGE_REQUEST, pc);
135
ReadConfigConf * conf = (ReadConfigConf*)signal->getDataPtrSend();
136
conf->senderRef = reference();
137
conf->senderData = senderData;
138
sendSignal(ref, GSN_READ_CONFIG_CONF, signal,
139
ReadConfigConf::SignalLength, JBB);
142
Pgman::Param::Param() :
143
m_max_pages(64), // smallish for testing
144
m_lirs_stack_mult(10),
146
m_max_loop_count(256),
148
m_stats_loop_delay(1000),
149
m_cleanup_loop_delay(200),
154
Pgman::Stats::Stats() :
158
m_current_io_waits(0)
163
Pgman::execSTTOR(Signal* signal)
167
const Uint32 startPhase = signal->theData[1];
169
switch (startPhase) {
172
Lgman* lgman = (Lgman*)globalData.getBlock(LGMAN);
173
new (&m_lgman) Logfile_client(this, lgman, 0);
174
c_tup = (Dbtup*)globalData.getBlock(DBTUP);
179
// start forever loops
180
do_stats_loop(signal);
181
do_cleanup_loop(signal);
182
m_stats_loop_on = true;
183
m_cleanup_loop_on = true;
196
Pgman::sendSTTORRY(Signal* signal)
198
signal->theData[0] = 0;
199
signal->theData[3] = 1;
200
signal->theData[4] = 3;
201
signal->theData[5] = 7;
202
signal->theData[6] = 255; // No more start phases from missra
203
sendSignal(NDBCNTR_REF, GSN_STTORRY, signal, 7, JBB);
207
Pgman::execCONTINUEB(Signal* signal)
210
Uint32 data1 = signal->theData[1];
212
switch (signal->theData[0]) {
213
case PgmanContinueB::STATS_LOOP:
215
do_stats_loop(signal);
217
case PgmanContinueB::BUSY_LOOP:
219
do_busy_loop(signal);
221
case PgmanContinueB::CLEANUP_LOOP:
223
do_cleanup_loop(signal);
225
case PgmanContinueB::LCP_LOOP:
229
case PgmanContinueB::LCP_LOCKED:
233
Page_sublist& pl = *m_page_sublist[Page_entry::SL_LOCKED];
236
pl.getPtr(ptr, data1);
237
process_lcp_locked(signal, ptr);
241
if (ERROR_INSERTED(11007))
243
ndbout << "No more writes..." << endl;
244
SET_ERROR_INSERT_VALUE(11008);
245
signal->theData[0] = 9999;
246
sendSignalWithDelay(CMVMI_REF, GSN_NDB_TAMPER, signal, 10000, 1);
248
signal->theData[0] = m_end_lcp_req.senderData;
249
sendSignal(m_end_lcp_req.senderRef, GSN_END_LCP_CONF, signal, 1, JBB);
261
Pgman::Page_entry::Page_entry(Uint32 file_no, Uint32 page_no) :
278
Pgman::get_sublist_no(Page_state state)
284
if (state & Page_entry::REQUEST)
286
if (! (state & Page_entry::BOUND))
288
return Page_entry::SL_BIND;
290
if (! (state & Page_entry::MAPPED))
292
if (! (state & Page_entry::PAGEIN))
294
return Page_entry::SL_MAP;
296
return Page_entry::SL_MAP_IO;
298
if (! (state & Page_entry::PAGEOUT))
300
return Page_entry::SL_CALLBACK;
302
return Page_entry::SL_CALLBACK_IO;
304
if (state & Page_entry::BUSY)
306
return Page_entry::SL_BUSY;
308
if (state & Page_entry::LOCKED)
310
return Page_entry::SL_LOCKED;
312
if (state == Page_entry::ONSTACK) {
313
return Page_entry::SL_IDLE;
315
return Page_entry::SL_OTHER;
319
Pgman::set_page_state(Ptr<Page_entry> ptr, Page_state new_state)
322
debugOut << "PGMAN: >set_page_state: state=" << hex << new_state << endl;
323
debugOut << "PGMAN: " << ptr << ": before" << endl;
326
Page_state old_state = ptr.p->m_state;
327
if (old_state != new_state)
329
Uint32 old_list_no = get_sublist_no(old_state);
330
Uint32 new_list_no = get_sublist_no(new_state);
333
ndbrequire(old_list_no != ZNIL);
334
if (old_list_no != new_list_no)
336
Page_sublist& old_list = *m_page_sublist[old_list_no];
337
old_list.remove(ptr);
342
ndbrequire(new_list_no != ZNIL);
343
if (old_list_no != new_list_no)
345
Page_sublist& new_list = *m_page_sublist[new_list_no];
349
ptr.p->m_state = new_state;
353
debugOut << "PGMAN: " << ptr << ": after" << endl;
354
debugOut << "PGMAN: <set_page_state" << endl;
358
// seize/release pages and entries
361
Pgman::seize_cache_page(Ptr<GlobalPage>& gptr)
363
// page cache has no own pool yet
364
bool ok = m_global_page_pool.seize(gptr);
366
// zero is reserved as return value for queued request
367
if (ok && gptr.i == 0)
368
ok = m_global_page_pool.seize(gptr);
372
ndbrequire(m_stats.m_num_pages < m_param.m_max_pages);
373
m_stats.m_num_pages++;
379
Pgman::release_cache_page(Uint32 i)
381
m_global_page_pool.release(i);
383
ndbrequire(m_stats.m_num_pages != 0);
384
m_stats.m_num_pages--;
388
Pgman::find_page_entry(Ptr<Page_entry>& ptr, Uint32 file_no, Uint32 page_no)
391
key.m_file_no = file_no;
392
key.m_page_no = page_no;
394
if (m_page_hashlist.find(ptr, key))
397
debugOut << "PGMAN: find_page_entry" << endl;
398
debugOut << "PGMAN: " << ptr << endl;
406
Pgman::seize_page_entry(Ptr<Page_entry>& ptr, Uint32 file_no, Uint32 page_no)
408
if (m_page_entry_pool.seize(ptr))
410
new (ptr.p) Page_entry(file_no, page_no);
411
m_page_hashlist.add(ptr);
414
ptr.p->m_this = this;
415
debugOut << "PGMAN: seize_page_entry" << endl;
416
debugOut << "PGMAN: " << ptr << endl;
425
Pgman::get_page_entry(Ptr<Page_entry>& ptr, Uint32 file_no, Uint32 page_no)
427
if (find_page_entry(ptr, file_no, page_no))
430
ndbrequire(ptr.p->m_state != 0);
431
m_stats.m_page_hits++;
434
debugOut << "PGMAN: get_page_entry: found" << endl;
435
debugOut << "PGMAN: " << ptr << endl;
440
if (m_page_entry_pool.getNoOfFree() == 0)
443
Page_sublist& pl_idle = *m_page_sublist[Page_entry::SL_IDLE];
444
Ptr<Page_entry> idle_ptr;
445
if (pl_idle.first(idle_ptr))
450
debugOut << "PGMAN: get_page_entry: re-use idle entry" << endl;
451
debugOut << "PGMAN: " << idle_ptr << endl;
454
Page_state state = idle_ptr.p->m_state;
455
ndbrequire(state == Page_entry::ONSTACK);
457
Page_stack& pl_stack = m_page_stack;
458
ndbrequire(pl_stack.hasPrev(idle_ptr));
459
pl_stack.remove(idle_ptr);
460
state &= ~ Page_entry::ONSTACK;
461
set_page_state(idle_ptr, state);
462
ndbrequire(idle_ptr.p->m_state == 0);
464
release_page_entry(idle_ptr);
468
if (seize_page_entry(ptr, file_no, page_no))
471
ndbrequire(ptr.p->m_state == 0);
472
m_stats.m_page_faults++;
475
debugOut << "PGMAN: get_page_entry: seize" << endl;
476
debugOut << "PGMAN: " << ptr << endl;
487
Pgman::release_page_entry(Ptr<Page_entry>& ptr)
490
debugOut << "PGMAN: release_page_entry" << endl;
491
debugOut << "PGMAN: " << ptr << endl;
493
Page_state state = ptr.p->m_state;
495
ndbrequire(ptr.p->m_requests.isEmpty());
497
ndbrequire(! (state & Page_entry::ONSTACK));
498
ndbrequire(! (state & Page_entry::ONQUEUE));
499
ndbrequire(ptr.p->m_real_page_i == RNIL);
501
if (! (state & Page_entry::LOCKED))
502
ndbrequire(! (state & Page_entry::REQUEST));
504
if (ptr.p->m_copy_page_i != RNIL)
506
m_global_page_pool.release(ptr.p->m_copy_page_i);
509
set_page_state(ptr, 0);
510
m_page_hashlist.remove(ptr);
511
m_page_entry_pool.release(ptr);
517
* After the hot entry at stack bottom is removed, additional entries
518
* are removed until next hot entry is found. There are 3 cases for the
519
* removed entry: 1) a bound entry is already on queue 2) an unbound
520
* entry with open requests enters queue at bind time 3) an unbound
521
* entry without requests is returned to entry pool.
524
Pgman::lirs_stack_prune()
527
debugOut << "PGMAN: >lirs_stack_prune" << endl;
529
Page_stack& pl_stack = m_page_stack;
532
while (pl_stack.first(ptr)) // first is stack bottom
534
Page_state state = ptr.p->m_state;
535
if (state & Page_entry::HOT)
542
debugOut << "PGMAN: " << ptr << ": prune from stack" << endl;
545
pl_stack.remove(ptr);
546
state &= ~ Page_entry::ONSTACK;
547
set_page_state(ptr, state);
549
if (state & Page_entry::BOUND)
552
ndbrequire(state & Page_entry::ONQUEUE);
554
else if (state & Page_entry::REQUEST)
556
// enters queue at bind
558
ndbrequire(! (state & Page_entry::ONQUEUE));
563
release_page_entry(ptr);
567
debugOut << "PGMAN: <lirs_stack_prune" << endl;
572
* Remove the hot entry at stack bottom and make it cold and do stack
573
* pruning. There are 2 cases for the removed entry: 1) a bound entry
574
* is moved to queue 2) an unbound entry must have requests and enters
575
* queue at bind time.
578
Pgman::lirs_stack_pop()
581
debugOut << "PGMAN: lirs_stack_pop" << endl;
583
Page_stack& pl_stack = m_page_stack;
584
Page_queue& pl_queue = m_page_queue;
587
bool ok = pl_stack.first(ptr);
589
Page_state state = ptr.p->m_state;
592
debugOut << "PGMAN: " << ptr << ": pop from stack" << endl;
595
ndbrequire(state & Page_entry::HOT);
596
ndbrequire(state & Page_entry::ONSTACK);
597
pl_stack.remove(ptr);
598
state &= ~ Page_entry::HOT;
599
state &= ~ Page_entry::ONSTACK;
600
ndbrequire(! (state & Page_entry::ONQUEUE));
602
if (state & Page_entry::BOUND)
606
state |= Page_entry::ONQUEUE;
610
// enters queue at bind
612
ndbrequire(state & Page_entry::REQUEST);
615
set_page_state(ptr, state);
620
* Update LIRS lists when page is referenced.
623
Pgman::lirs_reference(Ptr<Page_entry> ptr)
626
debugOut << "PGMAN: >lirs_reference" << endl;
627
debugOut << "PGMAN: " << ptr << endl;
629
Page_stack& pl_stack = m_page_stack;
630
Page_queue& pl_queue = m_page_queue;
632
Page_state state = ptr.p->m_state;
633
ndbrequire(! (state & Page_entry::LOCKED));
635
// even non-LIRS cache pages are counted on l.h.s.
636
if (m_stats.m_num_pages >= m_param.m_max_hot_pages)
638
if (state & Page_entry::HOT)
642
ndbrequire(state & Page_entry::ONSTACK);
643
bool at_bottom = ! pl_stack.hasPrev(ptr);
644
pl_stack.remove(ptr);
652
else if (state & Page_entry::ONSTACK)
656
pl_stack.remove(ptr);
657
if (! pl_stack.isEmpty())
663
state |= Page_entry::HOT;
664
if (state & Page_entry::ONQUEUE)
667
move_cleanup_ptr(ptr);
668
pl_queue.remove(ptr);
669
state &= ~ Page_entry::ONQUEUE;
677
state |= Page_entry::ONSTACK;
678
if (state & Page_entry::ONQUEUE)
681
move_cleanup_ptr(ptr);
682
pl_queue.remove(ptr);
683
state &= ~ Page_entry::ONQUEUE;
685
if (state & Page_entry::BOUND)
689
state |= Page_entry::ONQUEUE;
693
// enters queue at bind
701
debugOut << "PGMAN: filling up initial hot pages: "
702
<< m_stats.m_num_pages << " of "
703
<< m_param.m_max_hot_pages << endl;
706
if (state & Page_entry::ONSTACK)
709
bool at_bottom = ! pl_stack.hasPrev(ptr);
710
pl_stack.remove(ptr);
714
ndbassert(state & Page_entry::HOT);
719
state |= Page_entry::ONSTACK;
720
state |= Page_entry::HOT;
721
// it could be on queue already
722
if (state & Page_entry::ONQUEUE) {
724
pl_queue.remove(ptr);
725
state &= ~Page_entry::ONQUEUE;
729
set_page_state(ptr, state);
731
debugOut << "PGMAN: <lirs_reference" << endl;
738
Pgman::do_stats_loop(Signal* signal)
741
debugOut << "PGMAN: do_stats_loop" << endl;
744
Uint32 delay = m_param.m_stats_loop_delay;
745
signal->theData[0] = PgmanContinueB::STATS_LOOP;
746
sendSignalWithDelay(PGMAN_REF, GSN_CONTINUEB, signal, delay, 1);
750
Pgman::do_busy_loop(Signal* signal, bool direct)
753
debugOut << "PGMAN: >do_busy_loop on=" << m_busy_loop_on
754
<< " direct=" << direct << endl;
756
Uint32 restart = false;
759
// may not cover the calling entry
760
(void)process_bind(signal);
761
(void)process_map(signal);
762
// callback must be queued
763
if (! m_busy_loop_on)
766
m_busy_loop_on = true;
771
ndbrequire(m_busy_loop_on);
772
restart += process_bind(signal);
773
restart += process_map(signal);
774
restart += process_callback(signal);
777
m_busy_loop_on = false;
782
signal->theData[0] = PgmanContinueB::BUSY_LOOP;
783
sendSignal(PGMAN_REF, GSN_CONTINUEB, signal, 1, JBB);
786
debugOut << "PGMAN: <do_busy_loop on=" << m_busy_loop_on
787
<< " restart=" << restart << endl;
792
Pgman::do_cleanup_loop(Signal* signal)
795
debugOut << "PGMAN: do_cleanup_loop" << endl;
797
process_cleanup(signal);
799
Uint32 delay = m_param.m_cleanup_loop_delay;
800
signal->theData[0] = PgmanContinueB::CLEANUP_LOOP;
801
sendSignalWithDelay(PGMAN_REF, GSN_CONTINUEB, signal, delay, 1);
805
Pgman::do_lcp_loop(Signal* signal, bool direct)
808
debugOut << "PGMAN: >do_lcp_loop on=" << m_lcp_loop_on
809
<< " direct=" << direct << endl;
811
Uint32 restart = false;
814
ndbrequire(! m_lcp_loop_on);
816
m_lcp_loop_on = true;
820
ndbrequire(m_lcp_loop_on);
821
restart += process_lcp(signal);
824
m_lcp_loop_on = false;
829
Uint32 delay = m_param.m_lcp_loop_delay;
830
signal->theData[0] = PgmanContinueB::LCP_LOOP;
832
sendSignalWithDelay(PGMAN_REF, GSN_CONTINUEB, signal, delay, 1);
834
sendSignal(PGMAN_REF, GSN_CONTINUEB, signal, 1, JBB);
837
debugOut << "PGMAN: <do_lcp_loop on=" << m_lcp_loop_on
838
<< " restart=" << restart << endl;
845
Pgman::process_bind(Signal* signal)
848
debugOut << "PGMAN: >process_bind" << endl;
851
Page_sublist& pl_bind = *m_page_sublist[Page_entry::SL_BIND];
853
while (! pl_bind.isEmpty() && --max_count >= 0)
858
if (! process_bind(signal, ptr))
865
debugOut << "PGMAN: <process_bind" << endl;
867
return ! pl_bind.isEmpty();
871
Pgman::process_bind(Signal* signal, Ptr<Page_entry> ptr)
874
debugOut << "PGMAN: " << ptr << " : process_bind" << endl;
876
Page_queue& pl_queue = m_page_queue;
877
Ptr<GlobalPage> gptr;
879
if (m_stats.m_num_pages < m_param.m_max_pages)
882
bool ok = seize_cache_page(gptr);
883
// to handle failure requires some changes in LIRS
889
Ptr<Page_entry> clean_ptr;
890
if (! pl_queue.first(clean_ptr))
894
debugOut << "PGMAN: bind failed: queue empty" << endl;
899
Page_state clean_state = clean_ptr.p->m_state;
900
// under unusual circumstances it could still be paging in
901
if (! (clean_state & Page_entry::MAPPED) ||
902
clean_state & Page_entry::DIRTY ||
903
clean_state & Page_entry::REQUEST)
907
debugOut << "PGMAN: bind failed: queue front not evictable" << endl;
908
debugOut << "PGMAN: " << clean_ptr << endl;
915
debugOut << "PGMAN: " << clean_ptr << " : evict" << endl;
918
ndbassert(clean_ptr.p->m_dirty_count == 0);
919
ndbrequire(clean_state & Page_entry::ONQUEUE);
920
ndbrequire(clean_state & Page_entry::BOUND);
921
ndbrequire(clean_state & Page_entry::MAPPED);
923
move_cleanup_ptr(clean_ptr);
924
pl_queue.remove(clean_ptr);
925
clean_state &= ~ Page_entry::ONQUEUE;
927
gptr.i = clean_ptr.p->m_real_page_i;
929
clean_ptr.p->m_real_page_i = RNIL;
930
clean_state &= ~ Page_entry::BOUND;
931
clean_state &= ~ Page_entry::MAPPED;
933
set_page_state(clean_ptr, clean_state);
935
if (! (clean_state & Page_entry::ONSTACK))
936
release_page_entry(clean_ptr);
938
m_global_page_pool.getPtr(gptr);
941
Page_state state = ptr.p->m_state;
943
ptr.p->m_real_page_i = gptr.i;
944
state |= Page_entry::BOUND;
945
if (state & Page_entry::EMPTY)
948
state |= Page_entry::MAPPED;
951
if (! (state & Page_entry::LOCKED) &&
952
! (state & Page_entry::ONQUEUE) &&
953
! (state & Page_entry::HOT))
958
debugOut << "PGMAN: " << ptr << " : add to queue at bind" << endl;
962
state |= Page_entry::ONQUEUE;
965
set_page_state(ptr, state);
970
Pgman::process_map(Signal* signal)
973
debugOut << "PGMAN: >process_map" << endl;
976
if (m_param.m_max_io_waits > m_stats.m_current_io_waits) {
977
max_count = m_param.m_max_io_waits - m_stats.m_current_io_waits;
978
max_count = max_count / 2 + 1;
980
Page_sublist& pl_map = *m_page_sublist[Page_entry::SL_MAP];
982
while (! pl_map.isEmpty() && --max_count >= 0)
987
if (! process_map(signal, ptr))
994
debugOut << "PGMAN: <process_map" << endl;
996
return ! pl_map.isEmpty();
1000
Pgman::process_map(Signal* signal, Ptr<Page_entry> ptr)
1003
debugOut << "PGMAN: " << ptr << " : process_map" << endl;
1005
pagein(signal, ptr);
1010
Pgman::process_callback(Signal* signal)
1013
debugOut << "PGMAN: >process_callback" << endl;
1016
Page_sublist& pl_callback = *m_page_sublist[Page_entry::SL_CALLBACK];
1018
Ptr<Page_entry> ptr;
1019
pl_callback.first(ptr);
1021
while (! ptr.isNull() && --max_count >= 0)
1024
Ptr<Page_entry> curr = ptr;
1025
pl_callback.next(ptr);
1027
if (! process_callback(signal, curr))
1034
debugOut << "PGMAN: <process_callback" << endl;
1036
return ! pl_callback.isEmpty();
1040
Pgman::process_callback(Signal* signal, Ptr<Page_entry> ptr)
1043
debugOut << "PGMAN: " << ptr << " : process_callback" << endl;
1046
Page_state state = ptr.p->m_state;
1048
while (! ptr.p->m_requests.isEmpty() && --max_count >= 0)
1055
* Make sure list is in own scope if callback will access this
1056
* list again (destructor restores list head).
1058
Local_page_request_list req_list(m_page_request_pool, ptr.p->m_requests);
1059
Ptr<Page_request> req_ptr;
1061
req_list.first(req_ptr);
1063
debugOut << "PGMAN: " << req_ptr << " : process_callback" << endl;
1067
if (req_ptr.p->m_flags & Page_request::DELAY_REQ)
1069
Uint64 now = NdbTick_CurrentMillisecond();
1070
if (now < req_ptr.p->m_delay_until_time)
1077
b = globalData.getBlock(req_ptr.p->m_block);
1078
callback = req_ptr.p->m_callback;
1080
if (req_ptr.p->m_flags & DIRTY_FLAGS)
1083
state |= Page_entry::DIRTY;
1084
ndbassert(ptr.p->m_dirty_count);
1085
ptr.p->m_dirty_count --;
1088
req_list.releaseFirst(req_ptr);
1090
ndbrequire(state & Page_entry::BOUND);
1091
ndbrequire(state & Page_entry::MAPPED);
1093
// callback may re-enter PGMAN and change page state
1094
set_page_state(ptr, state);
1095
b->execute(signal, callback, ptr.p->m_real_page_i);
1096
state = ptr.p->m_state;
1099
if (ptr.p->m_requests.isEmpty())
1102
state &= ~ Page_entry::REQUEST;
1104
set_page_state(ptr, state);
1111
Pgman::process_cleanup(Signal* signal)
1114
debugOut << "PGMAN: >process_cleanup" << endl;
1116
Page_queue& pl_queue = m_page_queue;
1118
// XXX for now start always from beginning
1119
m_cleanup_ptr.i = RNIL;
1121
if (m_cleanup_ptr.i == RNIL && ! pl_queue.first(m_cleanup_ptr))
1125
debugOut << "PGMAN: <process_cleanup: empty queue" << endl;
1130
int max_loop_count = m_param.m_max_loop_count;
1132
if (m_param.m_max_io_waits > m_stats.m_current_io_waits) {
1133
max_count = m_param.m_max_io_waits - m_stats.m_current_io_waits;
1134
max_count = max_count / 2 + 1;
1137
Ptr<Page_entry> ptr = m_cleanup_ptr;
1138
while (max_loop_count != 0 && max_count != 0)
1140
Page_state state = ptr.p->m_state;
1141
ndbrequire(! (state & Page_entry::LOCKED));
1142
if (state & Page_entry::BUSY)
1145
debugOut << "PGMAN: process_cleanup: break on busy page" << endl;
1146
debugOut << "PGMAN: " << ptr << endl;
1150
if (state & Page_entry::DIRTY &&
1151
! (state & Page_entry::PAGEIN) &&
1152
! (state & Page_entry::PAGEOUT))
1155
debugOut << "PGMAN: " << ptr << " : process_cleanup" << endl;
1157
c_tup->disk_page_unmap_callback(0,
1158
ptr.p->m_real_page_i,
1159
ptr.p->m_dirty_count);
1160
pageout(signal, ptr);
1163
if (! pl_queue.hasNext(ptr))
1168
m_cleanup_ptr = ptr;
1170
debugOut << "PGMAN: <process_cleanup" << endl;
1176
* Call this before queue.remove(ptr). If the removed entry is the
1177
* clean-up pointer, move it towards front.
1180
Pgman::move_cleanup_ptr(Ptr<Page_entry> ptr)
1182
Page_queue& pl_queue = m_page_queue;
1183
if (ptr.i == m_cleanup_ptr.i)
1186
pl_queue.prev(m_cleanup_ptr);
1194
Pgman::execLCP_FRAG_ORD(Signal* signal)
1196
if (ERROR_INSERTED(11008))
1198
ndbout_c("Ignore LCP_FRAG_ORD");
1201
LcpFragOrd* ord = (LcpFragOrd*)signal->getDataPtr();
1202
ndbrequire(ord->lcpId >= m_last_lcp_complete + 1 || m_last_lcp_complete == 0);
1203
m_last_lcp = ord->lcpId;
1204
DBG_LCP("Pgman::execLCP_FRAG_ORD lcp: " << m_last_lcp << endl);
1208
<< "PGMAN: execLCP_FRAG_ORD"
1209
<< " this=" << m_last_lcp << " last_complete=" << m_last_lcp_complete
1210
<< " bucket=" << m_lcp_curr_bucket << endl;
1215
Pgman::execEND_LCP_REQ(Signal* signal)
1217
if (ERROR_INSERTED(11008))
1219
ndbout_c("Ignore END_LCP");
1223
EndLcpReq* req = (EndLcpReq*)signal->getDataPtr();
1224
m_end_lcp_req = *req;
1226
DBG_LCP("execEND_LCP_REQ" << endl);
1228
ndbrequire(!m_lcp_outstanding);
1229
m_lcp_curr_bucket = 0;
1233
<< "PGMAN: execEND_LCP_REQ"
1234
<< " this=" << m_last_lcp << " last_complete=" << m_last_lcp_complete
1235
<< " bucket=" << m_lcp_curr_bucket
1236
<< " outstanding=" << m_lcp_outstanding << endl;
1239
m_last_lcp_complete = m_last_lcp;
1241
do_lcp_loop(signal, true);
1245
Pgman::process_lcp(Signal* signal)
1247
Page_hashlist& pl_hash = m_page_hashlist;
1250
if (m_param.m_max_io_waits > m_stats.m_current_io_waits) {
1251
max_count = m_param.m_max_io_waits - m_stats.m_current_io_waits;
1252
max_count = max_count / 2 + 1;
1257
<< "PGMAN: process_lcp"
1258
<< " this=" << m_last_lcp << " last_complete=" << m_last_lcp_complete
1259
<< " bucket=" << m_lcp_curr_bucket
1260
<< " outstanding=" << m_lcp_outstanding << endl;
1263
// start or re-start from beginning of current hash bucket
1264
if (m_lcp_curr_bucket != ~(Uint32)0)
1266
Page_hashlist::Iterator iter;
1267
pl_hash.next(m_lcp_curr_bucket, iter);
1269
while (iter.curr.i != RNIL &&
1270
m_lcp_outstanding < (Uint32) max_count &&
1271
(loop ++ < 32 || iter.bucket == m_lcp_curr_bucket))
1273
Ptr<Page_entry>& ptr = iter.curr;
1274
Page_state state = ptr.p->m_state;
1276
DBG_LCP("LCP " << ptr << " - ");
1278
if (ptr.p->m_last_lcp < m_last_lcp &&
1279
(state & Page_entry::DIRTY) &&
1280
(! (state & Page_entry::LOCKED)))
1282
if(! (state & Page_entry::BOUND))
1284
ndbout << ptr << endl;
1287
if (state & Page_entry::BUSY)
1289
DBG_LCP(" BUSY" << endl);
1290
break; // wait for it
1292
else if (state & Page_entry::PAGEOUT)
1294
DBG_LCP(" PAGEOUT -> state |= LCP" << endl);
1295
set_page_state(ptr, state | Page_entry::LCP);
1299
DBG_LCP(" pageout()" << endl);
1300
ptr.p->m_state |= Page_entry::LCP;
1301
c_tup->disk_page_unmap_callback(0,
1302
ptr.p->m_real_page_i,
1303
ptr.p->m_dirty_count);
1304
pageout(signal, ptr);
1306
ptr.p->m_last_lcp = m_last_lcp;
1307
m_lcp_outstanding++;
1311
DBG_LCP(" NOT DIRTY" << endl);
1316
m_lcp_curr_bucket = (iter.curr.i != RNIL ? iter.bucket : ~(Uint32)0);
1319
if (m_lcp_curr_bucket == ~(Uint32)0 && !m_lcp_outstanding)
1321
Ptr<Page_entry> ptr;
1322
Page_sublist& pl = *m_page_sublist[Page_entry::SL_LOCKED];
1325
process_lcp_locked(signal, ptr);
1329
if (ERROR_INSERTED(11007))
1331
ndbout << "No more writes..." << endl;
1332
signal->theData[0] = 9999;
1333
sendSignalWithDelay(CMVMI_REF, GSN_NDB_TAMPER, signal, 10000, 1);
1334
SET_ERROR_INSERT_VALUE(11008);
1336
signal->theData[0] = m_end_lcp_req.senderData;
1337
sendSignal(m_end_lcp_req.senderRef, GSN_END_LCP_CONF, signal, 1, JBB);
1346
Pgman::process_lcp_locked(Signal* signal, Ptr<Page_entry> ptr)
1348
CRASH_INSERTION(11006);
1350
ptr.p->m_last_lcp = m_last_lcp;
1351
if (ptr.p->m_state & Page_entry::DIRTY)
1353
Ptr<GlobalPage> org, copy;
1354
ndbrequire(m_global_page_pool.seize(copy));
1355
m_global_page_pool.getPtr(org, ptr.p->m_real_page_i);
1356
memcpy(copy.p, org.p, sizeof(GlobalPage));
1357
ptr.p->m_copy_page_i = copy.i;
1359
m_lcp_outstanding++;
1360
ptr.p->m_state |= Page_entry::LCP;
1361
pageout(signal, ptr);
1365
Page_sublist& pl = *m_page_sublist[Page_entry::SL_LOCKED];
1368
signal->theData[0] = PgmanContinueB::LCP_LOCKED;
1369
signal->theData[1] = ptr.i;
1370
sendSignal(reference(), GSN_CONTINUEB, signal, 2, JBB);
1374
Pgman::process_lcp_locked_fswriteconf(Signal* signal, Ptr<Page_entry> ptr)
1376
Ptr<GlobalPage> org, copy;
1377
m_global_page_pool.getPtr(copy, ptr.p->m_copy_page_i);
1378
m_global_page_pool.getPtr(org, ptr.p->m_real_page_i);
1379
memcpy(org.p, copy.p, sizeof(GlobalPage));
1380
m_global_page_pool.release(copy);
1382
ptr.p->m_copy_page_i = RNIL;
1384
Page_sublist& pl = *m_page_sublist[Page_entry::SL_LOCKED];
1387
signal->theData[0] = PgmanContinueB::LCP_LOCKED;
1388
signal->theData[1] = ptr.i;
1389
sendSignal(reference(), GSN_CONTINUEB, signal, 2, JBB);
1392
// page read and write
1395
Pgman::pagein(Signal* signal, Ptr<Page_entry> ptr)
1398
debugOut << "PGMAN: pagein" << endl;
1399
debugOut << "PGMAN: " << ptr << endl;
1402
ndbrequire(! (ptr.p->m_state & Page_entry::PAGEIN));
1403
set_page_state(ptr, ptr.p->m_state | Page_entry::PAGEIN);
1405
fsreadreq(signal, ptr);
1406
m_stats.m_current_io_waits++;
1410
Pgman::fsreadconf(Signal* signal, Ptr<Page_entry> ptr)
1413
debugOut << "PGMAN: fsreadconf" << endl;
1414
debugOut << "PGMAN: " << ptr << endl;
1416
ndbrequire(ptr.p->m_state & Page_entry::PAGEIN);
1417
Page_state state = ptr.p->m_state;
1419
state &= ~ Page_entry::PAGEIN;
1420
state &= ~ Page_entry::EMPTY;
1421
state |= Page_entry::MAPPED;
1422
set_page_state(ptr, state);
1426
* Update lsn record on page
1427
* as it can be modified/flushed wo/ update_lsn has been called
1428
* (e.g. prealloc) and it then would get lsn 0, which is bad
1429
* when running undo and following SR
1431
Ptr<GlobalPage> pagePtr;
1432
m_global_page_pool.getPtr(pagePtr, ptr.p->m_real_page_i);
1433
File_formats::Datafile::Data_page* page =
1434
(File_formats::Datafile::Data_page*)pagePtr.p;
1437
lsn += page->m_page_header.m_page_lsn_hi; lsn <<= 32;
1438
lsn += page->m_page_header.m_page_lsn_lo;
1442
ndbrequire(m_stats.m_current_io_waits > 0);
1443
m_stats.m_current_io_waits--;
1445
ptr.p->m_last_lcp = m_last_lcp_complete;
1446
do_busy_loop(signal, true);
1450
Pgman::pageout(Signal* signal, Ptr<Page_entry> ptr)
1453
debugOut << "PGMAN: pageout" << endl;
1454
debugOut << "PGMAN: " << ptr << endl;
1457
Page_state state = ptr.p->m_state;
1458
ndbrequire(state & Page_entry::BOUND);
1459
ndbrequire(state & Page_entry::MAPPED);
1460
ndbrequire(! (state & Page_entry::BUSY));
1461
ndbrequire(! (state & Page_entry::PAGEOUT));
1463
state |= Page_entry::PAGEOUT;
1465
// update lsn on page prior to write
1466
Ptr<GlobalPage> pagePtr;
1467
m_global_page_pool.getPtr(pagePtr, ptr.p->m_real_page_i);
1468
File_formats::Datafile::Data_page* page =
1469
(File_formats::Datafile::Data_page*)pagePtr.p;
1470
page->m_page_header.m_page_lsn_hi = ptr.p->m_lsn >> 32;
1471
page->m_page_header.m_page_lsn_lo = ptr.p->m_lsn & 0xFFFFFFFF;
1474
Logfile_client::Request req;
1475
req.m_callback.m_callbackData = ptr.i;
1476
req.m_callback.m_callbackFunction = safe_cast(&Pgman::logsync_callback);
1477
int ret = m_lgman.sync_lsn(signal, ptr.p->m_lsn, &req, 0);
1480
fswritereq(signal, ptr);
1481
m_stats.m_current_io_waits++;
1485
ndbrequire(ret == 0);
1486
state |= Page_entry::LOGSYNC;
1488
set_page_state(ptr, state);
1492
Pgman::logsync_callback(Signal* signal, Uint32 ptrI, Uint32 res)
1494
Ptr<Page_entry> ptr;
1495
m_page_entry_pool.getPtr(ptr, ptrI);
1498
debugOut << "PGMAN: logsync_callback" << endl;
1499
debugOut << "PGMAN: " << ptr << endl;
1502
// it is OK to be "busy" at this point (the commit is queued)
1503
Page_state state = ptr.p->m_state;
1504
ndbrequire(state & Page_entry::PAGEOUT);
1505
ndbrequire(state & Page_entry::LOGSYNC);
1506
state &= ~ Page_entry::LOGSYNC;
1507
set_page_state(ptr, state);
1509
fswritereq(signal, ptr);
1510
m_stats.m_current_io_waits++;
1514
Pgman::fswriteconf(Signal* signal, Ptr<Page_entry> ptr)
1517
debugOut << "PGMAN: fswriteconf" << endl;
1518
debugOut << "PGMAN: " << ptr << endl;
1521
Page_state state = ptr.p->m_state;
1522
ndbrequire(state & Page_entry::PAGEOUT);
1524
c_tup->disk_page_unmap_callback(1,
1525
ptr.p->m_real_page_i,
1526
ptr.p->m_dirty_count);
1528
state &= ~ Page_entry::PAGEOUT;
1529
state &= ~ Page_entry::EMPTY;
1530
state &= ~ Page_entry::DIRTY;
1532
ndbrequire(m_stats.m_current_io_waits > 0);
1533
m_stats.m_current_io_waits--;
1535
if (state & Page_entry::LCP)
1537
ndbrequire(m_lcp_outstanding);
1538
m_lcp_outstanding--;
1539
state &= ~ Page_entry::LCP;
1541
if (ptr.p->m_copy_page_i != RNIL)
1543
process_lcp_locked_fswriteconf(signal, ptr);
1547
set_page_state(ptr, state);
1548
do_busy_loop(signal, true);
1551
// file system interface
1554
Pgman::fsreadreq(Signal* signal, Ptr<Page_entry> ptr)
1556
File_map::ConstDataBufferIterator it;
1557
bool ret = m_file_map.first(it) && m_file_map.next(it, ptr.p->m_file_no);
1559
Uint32 fd = * it.data;
1561
ndbrequire(ptr.p->m_page_no > 0);
1563
FsReadWriteReq* req = (FsReadWriteReq*)signal->getDataPtrSend();
1564
req->filePointer = fd;
1565
req->userReference = reference();
1566
req->userPointer = ptr.i;
1567
req->varIndex = ptr.p->m_page_no;
1568
req->numberOfPages = 1;
1569
req->operationFlag = 0;
1570
FsReadWriteReq::setFormatFlag(req->operationFlag,
1571
FsReadWriteReq::fsFormatGlobalPage);
1572
req->data.pageData[0] = ptr.p->m_real_page_i;
1573
sendSignal(NDBFS_REF, GSN_FSREADREQ, signal,
1574
FsReadWriteReq::FixedLength + 1, JBA);
1578
Pgman::execFSREADCONF(Signal* signal)
1581
FsConf* conf = (FsConf*)signal->getDataPtr();
1582
Ptr<Page_entry> ptr;
1583
m_page_entry_pool.getPtr(ptr, conf->userPointer);
1585
fsreadconf(signal, ptr);
1589
Pgman::execFSREADREF(Signal* signal)
1592
SimulatedBlock::execFSREADREF(signal);
1597
Pgman::fswritereq(Signal* signal, Ptr<Page_entry> ptr)
1599
File_map::ConstDataBufferIterator it;
1600
m_file_map.first(it);
1601
m_file_map.next(it, ptr.p->m_file_no);
1602
Uint32 fd = * it.data;
1604
ndbrequire(ptr.p->m_page_no > 0);
1606
FsReadWriteReq* req = (FsReadWriteReq*)signal->getDataPtrSend();
1607
req->filePointer = fd;
1608
req->userReference = reference();
1609
req->userPointer = ptr.i;
1610
req->varIndex = ptr.p->m_page_no;
1611
req->numberOfPages = 1;
1612
req->operationFlag = 0;
1613
FsReadWriteReq::setFormatFlag(req->operationFlag,
1614
FsReadWriteReq::fsFormatGlobalPage);
1615
req->data.pageData[0] = ptr.p->m_real_page_i;
1617
#if ERROR_INSERT_CODE
1618
if (ptr.p->m_state & Page_entry::LOCKED)
1620
sendSignalWithDelay(NDBFS_REF, GSN_FSWRITEREQ, signal,
1621
3000, FsReadWriteReq::FixedLength + 1);
1622
ndbout_c("pageout locked (3s)");
1627
if (!ERROR_INSERTED(11008))
1629
sendSignal(NDBFS_REF, GSN_FSWRITEREQ, signal,
1630
FsReadWriteReq::FixedLength + 1, JBA);
1635
Pgman::execFSWRITECONF(Signal* signal)
1638
FsConf* conf = (FsConf*)signal->getDataPtr();
1639
Ptr<Page_entry> ptr;
1640
m_page_entry_pool.getPtr(ptr, conf->userPointer);
1642
fswriteconf(signal, ptr);
1647
Pgman::execFSWRITEREF(Signal* signal)
1650
SimulatedBlock::execFSWRITEREF(signal);
1657
Pgman::get_page(Signal* signal, Ptr<Page_entry> ptr, Page_request page_req)
1661
Ptr<Page_request> tmp = { &page_req, RNIL};
1662
debugOut << "PGMAN: >get_page" << endl;
1663
debugOut << "PGMAN: " << ptr << endl;
1664
debugOut << "PGMAN: " << tmp << endl;
1666
Uint32 req_flags = page_req.m_flags;
1668
if (req_flags & Page_request::EMPTY_PAGE)
1670
// Only one can "init" a page at a time
1671
//ndbrequire(ptr.p->m_requests.isEmpty());
1674
Page_state state = ptr.p->m_state;
1675
bool is_new = (state == 0);
1676
bool busy_count = false;
1678
if (req_flags & Page_request::LOCK_PAGE)
1681
state |= Page_entry::LOCKED;
1684
if (req_flags & Page_request::ALLOC_REQ)
1688
else if (req_flags & Page_request::COMMIT_REQ)
1691
state |= Page_entry::BUSY;
1693
else if ((req_flags & Page_request::OP_MASK) != ZREAD)
1699
if (! (state & Page_entry::LOCKED) &&
1700
! (req_flags & Page_request::CORR_REQ))
1703
set_page_state(ptr, state);
1704
lirs_reference(ptr);
1705
state = ptr.p->m_state;
1708
const Page_state LOCKED = Page_entry::LOCKED | Page_entry::MAPPED;
1709
if ((state & LOCKED) == LOCKED &&
1710
! (req_flags & Page_request::UNLOCK_PAGE))
1712
ptr.p->m_state |= (req_flags & DIRTY_FLAGS ? Page_entry::DIRTY : 0);
1713
if (ptr.p->m_copy_page_i != RNIL)
1715
return ptr.p->m_copy_page_i;
1718
return ptr.p->m_real_page_i;
1721
bool only_request = ptr.p->m_requests.isEmpty();
1723
if (req_flags & Page_request::DELAY_REQ)
1726
only_request = false;
1730
state & Page_entry::MAPPED)
1732
if (! (state & Page_entry::PAGEOUT))
1734
if (req_flags & DIRTY_FLAGS)
1735
state |= Page_entry::DIRTY;
1737
ptr.p->m_busy_count += busy_count;
1738
set_page_state(ptr, state);
1741
debugOut << "PGMAN: <get_page: immediate" << endl;
1744
ndbrequire(ptr.p->m_real_page_i != RNIL);
1745
return ptr.p->m_real_page_i;
1749
if (! (req_flags & (Page_request::LOCK_PAGE | Page_request::UNLOCK_PAGE)))
1751
ndbrequire(! (state & Page_entry::LOCKED));
1754
// queue the request
1755
Ptr<Pgman::Page_request> req_ptr;
1757
Local_page_request_list req_list(m_page_request_pool, ptr.p->m_requests);
1758
if (! (req_flags & Page_request::ALLOC_REQ))
1759
req_list.seizeLast(req_ptr);
1761
req_list.seizeFirst(req_ptr);
1764
if (req_ptr.i == RNIL)
1768
release_page_entry(ptr);
1773
req_ptr.p->m_block = page_req.m_block;
1774
req_ptr.p->m_flags = page_req.m_flags;
1775
req_ptr.p->m_callback = page_req.m_callback;
1777
req_ptr.p->m_delay_until_time = page_req.m_delay_until_time;
1780
state |= Page_entry::REQUEST;
1781
if (only_request && (req_flags & Page_request::EMPTY_PAGE))
1783
state |= Page_entry::EMPTY;
1786
if (req_flags & Page_request::UNLOCK_PAGE)
1791
ptr.p->m_busy_count += busy_count;
1792
ptr.p->m_dirty_count += !!(req_flags & DIRTY_FLAGS);
1793
set_page_state(ptr, state);
1795
do_busy_loop(signal, true);
1798
debugOut << "PGMAN: " << req_ptr << endl;
1799
debugOut << "PGMAN: <get_page: queued" << endl;
1805
Pgman::update_lsn(Ptr<Page_entry> ptr, Uint32 block, Uint64 lsn)
1809
const char* bname = getBlockName(block, "?");
1810
debugOut << "PGMAN: >update_lsn: block=" << bname << " lsn=" << lsn << endl;
1811
debugOut << "PGMAN: " << ptr << endl;
1814
Page_state state = ptr.p->m_state;
1817
if (state & Page_entry::BUSY)
1819
ndbrequire(ptr.p->m_busy_count != 0);
1820
if (--ptr.p->m_busy_count == 0)
1822
state &= ~ Page_entry::BUSY;
1826
state |= Page_entry::DIRTY;
1827
set_page_state(ptr, state);
1830
debugOut << "PGMAN: " << ptr << endl;
1831
debugOut << "PGMAN: <update_lsn" << endl;
1836
Pgman::create_data_file()
1838
File_map::DataBufferIterator it;
1839
if(m_file_map.first(it))
1843
if(*it.data == RNIL)
1845
*it.data = (1u << 31) | it.pos;
1848
} while(m_file_map.next(it));
1851
Uint32 file_no = m_file_map.getSize();
1852
Uint32 fd = (1u << 31) | file_no;
1854
if (m_file_map.append(&fd, 1))
1862
Pgman::alloc_data_file(Uint32 file_no)
1864
Uint32 sz = m_file_map.getSize();
1867
Uint32 len = file_no - sz + 1;
1871
if (! m_file_map.append(&fd, 1))
1876
File_map::DataBufferIterator it;
1877
m_file_map.first(it);
1878
m_file_map.next(it, file_no);
1879
if (* it.data != RNIL)
1882
*it.data = (1u << 31) | file_no;
1887
Pgman::map_file_no(Uint32 file_no, Uint32 fd)
1889
File_map::DataBufferIterator it;
1890
m_file_map.first(it);
1891
m_file_map.next(it, file_no);
1893
assert(*it.data == ((1u << 31) | file_no));
1898
Pgman::free_data_file(Uint32 file_no, Uint32 fd)
1900
File_map::DataBufferIterator it;
1901
m_file_map.first(it);
1902
m_file_map.next(it, file_no);
1906
ndbrequire(*it.data == ((1u << 31) | file_no));
1910
ndbrequire(*it.data == fd);
1916
Pgman::drop_page(Ptr<Page_entry> ptr)
1919
debugOut << "PGMAN: drop_page" << endl;
1920
debugOut << "PGMAN: " << ptr << endl;
1923
Page_stack& pl_stack = m_page_stack;
1924
Page_queue& pl_queue = m_page_queue;
1926
Page_state state = ptr.p->m_state;
1927
if (! (state & (Page_entry::PAGEIN | Page_entry::PAGEOUT)))
1929
ndbrequire(state & Page_entry::BOUND);
1930
ndbrequire(state & Page_entry::MAPPED);
1932
if (state & Page_entry::ONSTACK)
1935
bool at_bottom = ! pl_stack.hasPrev(ptr);
1936
pl_stack.remove(ptr);
1937
state &= ~ Page_entry::ONSTACK;
1941
ndbassert(state & Page_entry::HOT);
1946
if (state & Page_entry::ONQUEUE)
1949
pl_queue.remove(ptr);
1950
state &= ~ Page_entry::ONQUEUE;
1953
ndbassert(ptr.p->m_real_page_i != RNIL);
1954
if (ptr.p->m_real_page_i != RNIL)
1957
release_cache_page(ptr.p->m_real_page_i);
1958
ptr.p->m_real_page_i = RNIL;
1961
set_page_state(ptr, state);
1962
release_page_entry(ptr);
1975
Pgman::verify_page_entry(Ptr<Page_entry> ptr)
1977
Uint32 ptrI = ptr.i;
1978
Page_state state = ptr.p->m_state;
1980
bool has_req = state & Page_entry::REQUEST;
1981
bool has_req2 = ! ptr.p->m_requests.isEmpty();
1982
ndbrequire(has_req == has_req2 || dump_page_lists(ptrI));
1984
bool is_bound = state & Page_entry::BOUND;
1985
bool is_bound2 = ptr.p->m_real_page_i != RNIL;
1986
ndbrequire(is_bound == is_bound2 || dump_page_lists(ptrI));
1988
bool is_mapped = state & Page_entry::MAPPED;
1989
// mapped implies bound
1990
ndbrequire(! is_mapped || is_bound || dump_page_lists(ptrI));
1991
// bound is mapped or has open requests
1992
ndbrequire(! is_bound || is_mapped || has_req || dump_page_lists(ptrI));
1994
bool on_stack = state & Page_entry::ONSTACK;
1995
bool is_hot = state & Page_entry::HOT;
1996
// hot entry must be on stack
1997
ndbrequire(! is_hot || on_stack || dump_page_lists(ptrI));
1999
bool on_queue = state & Page_entry::ONQUEUE;
2000
// hot entry is not on queue
2001
ndbrequire(! is_hot || ! on_queue || dump_page_lists(ptrI));
2003
bool is_locked = state & Page_entry::LOCKED;
2004
bool on_queue2 = ! is_locked && ! is_hot && is_bound;
2005
ndbrequire(on_queue == on_queue2 || dump_page_lists(ptrI));
2007
// entries waiting to enter queue
2008
bool to_queue = ! is_locked && ! is_hot && ! is_bound && has_req;
2010
// page is either LOCKED or under LIRS
2011
bool is_lirs = on_stack || to_queue || on_queue;
2012
ndbrequire(is_locked == ! is_lirs || dump_page_lists(ptrI));
2014
bool pagein = state & Page_entry::PAGEIN;
2015
bool pageout = state & Page_entry::PAGEOUT;
2016
// cannot read and write at same time
2017
ndbrequire(! pagein || ! pageout || dump_page_lists(ptrI));
2019
Uint32 no = get_sublist_no(state);
2021
case Page_entry::SL_BIND:
2022
ndbrequire(! pagein && ! pageout || dump_page_lists(ptrI));
2024
case Page_entry::SL_MAP:
2025
ndbrequire(! pagein && ! pageout || dump_page_lists(ptrI));
2027
case Page_entry::SL_MAP_IO:
2028
ndbrequire(pagein && ! pageout || dump_page_lists(ptrI));
2030
case Page_entry::SL_CALLBACK:
2031
ndbrequire(! pagein && ! pageout || dump_page_lists(ptrI));
2033
case Page_entry::SL_CALLBACK_IO:
2034
ndbrequire(! pagein && pageout || dump_page_lists(ptrI));
2036
case Page_entry::SL_BUSY:
2038
case Page_entry::SL_LOCKED:
2040
case Page_entry::SL_IDLE:
2042
case Page_entry::SL_OTHER:
2045
ndbrequire(false || dump_page_lists(ptrI));
2051
Pgman::verify_page_lists()
2053
Page_hashlist& pl_hash = m_page_hashlist;
2054
Page_stack& pl_stack = m_page_stack;
2055
Page_queue& pl_queue = m_page_queue;
2056
Ptr<Page_entry> ptr;
2058
Uint32 stack_count = 0;
2059
Uint32 queue_count = 0;
2060
Uint32 queuewait_count = 0;
2061
Uint32 locked_bound_count = 0;
2063
Page_hashlist::Iterator iter;
2064
pl_hash.next(0, iter);
2065
while (iter.curr.i != RNIL)
2067
verify_page_entry(iter.curr);
2069
Page_state state = iter.curr.p->m_state;
2070
if (state & Page_entry::ONSTACK)
2072
if (state & Page_entry::ONQUEUE)
2074
if (! (state & Page_entry::LOCKED) &&
2075
! (state & Page_entry::HOT) &&
2076
(state & Page_entry::REQUEST) &&
2077
! (state & Page_entry::BOUND))
2079
if (state & Page_entry::LOCKED &&
2080
state & Page_entry::BOUND)
2081
locked_bound_count++;
2085
ndbrequire(stack_count == pl_stack.count() || dump_page_lists());
2086
ndbrequire(queue_count == pl_queue.count() || dump_page_lists());
2088
Uint32 hot_count = 0;
2089
Uint32 hot_bound_count = 0;
2090
Uint32 cold_bound_count = 0;
2091
Uint32 stack_request_count = 0;
2092
Uint32 queue_request_count = 0;
2095
for (pl_stack.first(ptr); ptr.i != RNIL; pl_stack.next(ptr))
2097
ndbrequire(i1 != ptr.i);
2099
Page_state state = ptr.p->m_state;
2100
ndbrequire(state & Page_entry::ONSTACK || dump_page_lists());
2101
if (! pl_stack.hasPrev(ptr))
2102
ndbrequire(state & Page_entry::HOT || dump_page_lists());
2103
if (state & Page_entry::HOT) {
2105
if (state & Page_entry::BOUND)
2108
if (state & Page_entry::REQUEST)
2109
stack_request_count++;
2113
for (pl_queue.first(ptr); ptr.i != RNIL; pl_queue.next(ptr))
2115
ndbrequire(i2 != ptr.i);
2117
Page_state state = ptr.p->m_state;
2118
ndbrequire(state & Page_entry::ONQUEUE || dump_page_lists());
2119
ndbrequire(state & Page_entry::BOUND || dump_page_lists());
2121
if (state & Page_entry::REQUEST)
2122
queue_request_count++;
2125
Uint32 tot_bound_count =
2126
locked_bound_count + hot_bound_count + cold_bound_count;
2127
ndbrequire(m_stats.m_num_pages == tot_bound_count || dump_page_lists());
2130
Uint32 entry_count = 0;
2132
for (k = 0; k < Page_entry::SUBLIST_COUNT; k++)
2134
const Page_sublist& pl = *m_page_sublist[k];
2135
for (pl.first(ptr); ptr.i != RNIL; pl.next(ptr))
2137
ndbrequire(get_sublist_no(ptr.p->m_state) == k || dump_page_lists());
2142
ndbrequire(entry_count == pl_hash.count() || dump_page_lists());
2144
debugOut << "PGMAN: loop"
2145
<< " stats=" << m_stats_loop_on
2146
<< " busy=" << m_busy_loop_on
2147
<< " cleanup=" << m_cleanup_loop_on
2148
<< " lcp=" << m_lcp_loop_on << endl;
2150
debugOut << "PGMAN:"
2151
<< " entry:" << pl_hash.count()
2152
<< " cache:" << m_stats.m_num_pages
2153
<< "(" << locked_bound_count << "L)"
2154
<< " stack:" << pl_stack.count()
2155
<< " hot:" << hot_count
2156
<< " hot_bound:" << hot_bound_count
2157
<< " stack_request:" << stack_request_count
2158
<< " queue:" << pl_queue.count()
2159
<< " queue_request:" << queue_request_count
2160
<< " queuewait:" << queuewait_count << endl;
2162
debugOut << "PGMAN:";
2163
for (k = 0; k < Page_entry::SUBLIST_COUNT; k++)
2165
const Page_sublist& pl = *m_page_sublist[k];
2166
debugOut << " " << get_sublist_name(k) << ":" << pl.count();
2174
Page_sublist& pl_bind = *m_page_sublist[Page_entry::SL_BIND];
2175
Page_sublist& pl_map = *m_page_sublist[Page_entry::SL_MAP];
2176
Page_sublist& pl_callback = *m_page_sublist[Page_entry::SL_CALLBACK];
2178
if (! pl_bind.isEmpty() || ! pl_map.isEmpty() || ! pl_callback.isEmpty())
2180
ndbrequire(m_busy_loop_on || dump_page_lists());
2182
verify_page_lists();
2186
Pgman::dump_page_lists(Uint32 ptrI)
2191
debugOut << "PGMAN: page list dump" << endl;
2193
debugOut << "PGMAN: error on PE [" << ptrI << "]" << endl;
2195
Page_hashlist& pl_hash = m_page_hashlist;
2196
Page_stack& pl_stack = m_page_stack;
2197
Page_queue& pl_queue = m_page_queue;
2198
Ptr<Page_entry> ptr;
2202
debugOut << "hash:" << endl;
2203
Page_hashlist::Iterator iter;
2204
pl_hash.next(0, iter);
2206
while (iter.curr.i != RNIL)
2208
sprintf(buf, "%03d", n++);
2209
debugOut << buf << " " << iter.curr << endl;
2213
debugOut << "stack:" << endl;
2215
for (pl_stack.first(ptr); ptr.i != RNIL; pl_stack.next(ptr))
2217
sprintf(buf, "%03d", n++);
2218
debugOut << buf << " " << ptr << endl;
2221
debugOut << "queue:" << endl;
2223
for (pl_queue.first(ptr); ptr.i != RNIL; pl_queue.next(ptr))
2225
sprintf(buf, "%03d", n++);
2226
debugOut << buf << " " << ptr << endl;
2230
for (k = 0; k < Page_entry::SUBLIST_COUNT; k++)
2232
debugOut << get_sublist_name(k) << ":" << endl;
2233
const Page_sublist& pl = *m_page_sublist[k];
2234
for (pl.first(ptr); ptr.i != RNIL; pl.next(ptr))
2236
sprintf(buf, "%03d", n++);
2237
debugOut << buf << " " << ptr << endl;
2250
Pgman::get_sublist_name(Uint32 list_no)
2253
case Page_entry::SL_BIND:
2255
case Page_entry::SL_MAP:
2257
case Page_entry::SL_MAP_IO:
2259
case Page_entry::SL_CALLBACK:
2261
case Page_entry::SL_CALLBACK_IO:
2262
return "callback_io";
2263
case Page_entry::SL_BUSY:
2265
case Page_entry::SL_LOCKED:
2267
case Page_entry::SL_IDLE:
2269
case Page_entry::SL_OTHER:
2276
operator<<(NdbOut& out, Ptr<Pgman::Page_request> ptr)
2278
const Pgman::Page_request& pr = *ptr.p;
2279
const char* bname = getBlockName(pr.m_block, "?");
2282
out << " [" << dec << ptr.i << "]";
2283
out << " block=" << bname;
2284
out << " flags=" << hex << pr.m_flags;
2285
out << "," << dec << (pr.m_flags & Pgman::Page_request::OP_MASK);
2287
if (pr.m_flags & Pgman::Page_request::LOCK_PAGE)
2288
out << ",lock_page";
2289
if (pr.m_flags & Pgman::Page_request::EMPTY_PAGE)
2290
out << ",empty_page";
2291
if (pr.m_flags & Pgman::Page_request::ALLOC_REQ)
2292
out << ",alloc_req";
2293
if (pr.m_flags & Pgman::Page_request::COMMIT_REQ)
2294
out << ",commit_req";
2295
if (pr.m_flags & Pgman::Page_request::DIRTY_REQ)
2296
out << ",dirty_req";
2297
if (pr.m_flags & Pgman::Page_request::CORR_REQ)
2304
operator<<(NdbOut& out, Ptr<Pgman::Page_entry> ptr)
2306
const Pgman::Page_entry pe = *ptr.p;
2307
Uint32 list_no = Pgman::get_sublist_no(pe.m_state);
2308
out << "PE [" << dec << ptr.i << "]";
2309
out << " state=" << hex << pe.m_state;
2311
if (pe.m_state & Pgman::Page_entry::REQUEST)
2313
if (pe.m_state & Pgman::Page_entry::EMPTY)
2315
if (pe.m_state & Pgman::Page_entry::BOUND)
2317
if (pe.m_state & Pgman::Page_entry::MAPPED)
2319
if (pe.m_state & Pgman::Page_entry::DIRTY)
2321
if (pe.m_state & Pgman::Page_entry::USED)
2323
if (pe.m_state & Pgman::Page_entry::BUSY)
2325
if (pe.m_state & Pgman::Page_entry::LOCKED)
2327
if (pe.m_state & Pgman::Page_entry::PAGEIN)
2329
if (pe.m_state & Pgman::Page_entry::PAGEOUT)
2331
if (pe.m_state & Pgman::Page_entry::LOGSYNC)
2333
if (pe.m_state & Pgman::Page_entry::LCP)
2335
if (pe.m_state & Pgman::Page_entry::HOT)
2337
if (pe.m_state & Pgman::Page_entry::ONSTACK)
2339
if (pe.m_state & Pgman::Page_entry::ONQUEUE)
2343
if (list_no == ZNIL)
2347
out << dec << list_no;
2348
out << "," << Pgman::get_sublist_name(list_no);
2350
out << " diskpage=" << dec << pe.m_file_no << "," << pe.m_page_no;
2351
if (pe.m_real_page_i == RNIL)
2352
out << " realpage=RNIL";
2354
out << " realpage=" << dec << pe.m_real_page_i;
2355
out << " lsn=" << dec << pe.m_lsn;
2356
out << " busy_count=" << dec << pe.m_busy_count;
2359
Pgman::Page_stack& pl_stack = pe.m_this->m_page_stack;
2360
if (! pl_stack.hasNext(ptr))
2362
if (! pl_stack.hasPrev(ptr))
2366
Pgman::Local_page_request_list
2367
req_list(ptr.p->m_this->m_page_request_pool, ptr.p->m_requests);
2368
if (! req_list.isEmpty())
2370
Ptr<Pgman::Page_request> req_ptr;
2372
for (req_list.first(req_ptr); req_ptr.i != RNIL; req_list.next(req_ptr))
2374
out << " " << req_ptr;
2384
Pgman::open_debug_file(Uint32 flag)
2388
FILE* f = globalSignalLoggers.getOutputStream();
2389
debugOut = *new NdbOut(*new FileOutputStream(f));
2393
debugOut = *new NdbOut(*new NullOutputStream());
2399
Pgman::execDUMP_STATE_ORD(Signal* signal)
2402
Page_hashlist& pl_hash = m_page_hashlist;
2404
if (signal->theData[0] == 11000 && signal->getLength() == 2)
2406
Uint32 flag = signal->theData[1];
2407
open_debug_file(flag);
2412
if (signal->theData[0] == 11001)
2414
// XXX print hash list if no sublist
2416
if (signal->getLength() > 1)
2417
list = signal->theData[1];
2419
Page_sublist& pl = *m_page_sublist[list];
2420
Ptr<Page_entry> ptr;
2422
for (pl.first(ptr); ptr.i != RNIL; pl.next(ptr))
2424
ndbout << ptr << endl;
2425
infoEvent(" PE [ file: %d page: %d ] state: %x lsn: %lld lcp: %d busy: %d req-list: %d",
2426
ptr.p->m_file_no, ptr.p->m_page_no,
2427
ptr.p->m_state, ptr.p->m_lsn, ptr.p->m_last_lcp,
2428
ptr.p->m_busy_count,
2429
!ptr.p->m_requests.isEmpty());
2433
if (signal->theData[0] == 11002 && signal->getLength() == 3)
2436
key.m_file_no = signal->theData[1];
2437
key.m_page_no = signal->theData[2];
2439
Ptr<Page_entry> ptr;
2440
if (pl_hash.find(ptr, key))
2442
ndbout << "pageout " << ptr << endl;
2443
c_tup->disk_page_unmap_callback(0,
2444
ptr.p->m_real_page_i,
2445
ptr.p->m_dirty_count);
2446
pageout(signal, ptr);
2451
if (signal->theData[0] == 11003)
2454
verify_page_lists();
2457
ndbout << "Only in VM_TRACE builds" << endl;
2461
if (signal->theData[0] == 11004)
2463
ndbout << "Dump LCP bucket m_lcp_outstanding: " << m_lcp_outstanding;
2464
if (m_lcp_curr_bucket != ~(Uint32)0)
2466
Page_hashlist::Iterator iter;
2467
pl_hash.next(m_lcp_curr_bucket, iter);
2469
ndbout_c(" %d", m_lcp_curr_bucket);
2471
while (iter.curr.i != RNIL && iter.bucket == m_lcp_curr_bucket)
2473
Ptr<Page_entry>& ptr = iter.curr;
2474
ndbout << ptr << endl;
2478
ndbout_c("-- done");
2486
if (signal->theData[0] == 11005)
2488
g_dbg_lcp = ~g_dbg_lcp;
2491
if (signal->theData[0] == 11006)
2493
SET_ERROR_INSERT_VALUE(11006);
2496
if (signal->theData[0] == 11007)
2498
SET_ERROR_INSERT_VALUE(11007);
2501
if (signal->theData[0] == 11008)
2503
SET_ERROR_INSERT_VALUE(11008);
2507
// page cache client
2509
Page_cache_client::Page_cache_client(SimulatedBlock* block, Pgman* pgman)
2511
m_block = block->number();