3166 Jonas Oreland 2009-11-27 [merge]
merge 70 to 71
modified:
storage/ndb/src/kernel/blocks/pgman.cpp
storage/ndb/src/kernel/blocks/pgman.hpp
3165 Frazer Clement 2009-11-19
Another Windows fix
modified:
storage/ndb/test/src/CMakeLists.txt
=== modified file 'storage/ndb/src/kernel/blocks/pgman.cpp'
--- a/storage/ndb/src/kernel/blocks/pgman.cpp 2009-10-09 11:15:22 +0000
+++ b/storage/ndb/src/kernel/blocks/pgman.cpp 2009-11-27 10:26:10 +0000
@@ -50,6 +50,10 @@ Pgman::Pgman(Block_context& ctx, Uint32
m_page_hashlist(m_page_entry_pool),
m_page_stack(m_page_entry_pool),
m_page_queue(m_page_entry_pool)
+#ifdef VM_TRACE
+ ,debugFlag(false)
+ ,debugSummaryFlag(false)
+#endif
{
BLOCK_CONSTRUCTOR(Pgman);
@@ -150,6 +154,7 @@ Pgman::execREAD_CONFIG_REQ(Signal* signa
m_param.m_max_pages = page_cnt;
m_page_entry_pool.setSize(m_param.m_lirs_stack_mult * page_cnt);
m_param.m_max_hot_pages = (page_cnt * 9) / 10;
+ ndbrequire(m_param.m_max_hot_pages >= 1);
}
Pool_context pc;
@@ -177,9 +182,10 @@ Pgman::Param::Param() :
Pgman::Stats::Stats() :
m_num_pages(0),
+ m_num_hot_pages(0),
+ m_current_io_waits(0),
m_page_hits(0),
- m_page_faults(0),
- m_current_io_waits(0)
+ m_page_faults(0)
{
}
@@ -313,10 +319,6 @@ Pgman::Page_entry::Page_entry(Uint32 fil
Uint32
Pgman::get_sublist_no(Page_state state)
{
- if (state == 0)
- {
- return ZNIL;
- }
if (state & Page_entry::REQUEST)
{
if (! (state & Page_entry::BOUND))
@@ -348,7 +350,11 @@ Pgman::get_sublist_no(Page_state state)
if (state == Page_entry::ONSTACK) {
return Page_entry::SL_IDLE;
}
- return Page_entry::SL_OTHER;
+ if (state != 0)
+ {
+ return Page_entry::SL_OTHER;
+ }
+ return ZNIL;
}
void
@@ -381,9 +387,26 @@ Pgman::set_page_state(Ptr<Page_entry> pt
}
}
ptr.p->m_state = new_state;
+
+ bool old_hot = (old_state & Page_entry::HOT);
+ bool new_hot = (new_state & Page_entry::HOT);
+ if (! old_hot && new_hot)
+ {
+ jam();
+ m_stats.m_num_hot_pages++;
+ }
+ if (old_hot && ! new_hot)
+ {
+ jam();
+ ndbrequire(m_stats.m_num_hot_pages != 0);
+ m_stats.m_num_hot_pages--;
+ }
}
D(ptr << ": after");
+#ifdef VM_TRACE
+ verify_page_entry(ptr);
+#endif
D("<set_page_state");
}
@@ -641,8 +664,10 @@ Pgman::lirs_reference(Ptr<Page_entry> pt
Page_state state = ptr.p->m_state;
ndbrequire(! (state & Page_entry::LOCKED));
- // even non-LIRS cache pages are counted on l.h.s.
- if (m_stats.m_num_pages >= m_param.m_max_hot_pages)
+ ndbrequire(m_stats.m_num_hot_pages <= m_param.m_max_hot_pages);
+
+ // LIRS kicks in when we have max hot pages
+ if (m_stats.m_num_hot_pages == m_param.m_max_hot_pages)
{
if (state & Page_entry::HOT)
{
@@ -684,6 +709,12 @@ Pgman::lirs_reference(Ptr<Page_entry> pt
jam();
pl_stack.add(ptr);
state |= Page_entry::ONSTACK;
+ /*
+ * bug#48910. Using hot page count (not total page count)
+ * guarantees that stack is not empty here. Therefore the new
+ * entry (added to top) is not at bottom and need not be hot.
+ */
+ ndbrequire(pl_stack.hasPrev(ptr));
if (state & Page_entry::ONQUEUE)
{
jam();
@@ -706,7 +737,8 @@ Pgman::lirs_reference(Ptr<Page_entry> pt
}
else
{
- D("hot: " << m_stats.m_num_pages << " of " << m_param.m_max_hot_pages);
+ D("filling up hot pages: " << m_stats.m_num_hot_pages << "/"
+ << m_param.m_max_hot_pages);
jam();
if (state & Page_entry::ONSTACK)
{
@@ -1005,11 +1037,11 @@ Pgman::process_callback(Signal* signal,
{
D(ptr << " : process_callback");
int max_count = 1;
- Page_state state = ptr.p->m_state;
while (! ptr.p->m_requests.isEmpty() && --max_count >= 0)
{
jam();
+ Page_state state = ptr.p->m_state;
SimulatedBlock* b;
Callback callback;
{
@@ -1051,19 +1083,18 @@ Pgman::process_callback(Signal* signal,
}
ndbrequire(state & Page_entry::BOUND);
ndbrequire(state & Page_entry::MAPPED);
+
+ // make REQUEST state consistent before set_page_state()
+ if (ptr.p->m_requests.isEmpty())
+ {
+ jam();
+ state &= ~ Page_entry::REQUEST;
+ }
// callback may re-enter PGMAN and change page state
set_page_state(ptr, state);
b->execute(signal, callback, ptr.p->m_real_page_i);
- state = ptr.p->m_state;
}
-
- if (ptr.p->m_requests.isEmpty())
- {
- jam();
- state &= ~ Page_entry::REQUEST;
- }
- set_page_state(ptr, state);
return true;
}
@@ -1608,7 +1639,7 @@ Pgman::execFSWRITEREF(Signal* signal)
// client methods
int
-Pgman::get_page(Signal* signal, Ptr<Page_entry> ptr, Page_request page_req)
+Pgman::get_page_no_lirs(Signal* signal, Ptr<Page_entry> ptr, Page_request page_req)
{
jamEntry();
Ptr<Page_request> tmp = { &page_req, RNIL};
@@ -1649,16 +1680,6 @@ Pgman::get_page(Signal* signal, Ptr<Page
jam();
}
- // update LIRS
- if (! (state & Page_entry::LOCKED) &&
- ! (req_flags & Page_request::CORR_REQ))
- {
- jam();
- set_page_state(ptr, state);
- lirs_reference(ptr);
- state = ptr.p->m_state;
- }
-
const Page_state LOCKED = Page_entry::LOCKED | Page_entry::MAPPED;
if ((state & LOCKED) == LOCKED &&
! (req_flags & Page_request::UNLOCK_PAGE))
@@ -1746,14 +1767,43 @@ Pgman::get_page(Signal* signal, Ptr<Page
ptr.p->m_busy_count += busy_count;
ptr.p->m_dirty_count += !!(req_flags & DIRTY_FLAGS);
set_page_state(ptr, state);
-
- do_busy_loop(signal, true);
D(req_ptr);
D("<get_page: queued");
return 0;
}
+int
+Pgman::get_page(Signal* signal, Ptr<Page_entry> ptr, Page_request page_req)
+{
+ int i = get_page_no_lirs(signal, ptr, page_req);
+ if (unlikely(i == -1))
+ {
+ jam();
+ return -1;
+ }
+
+ Uint32 req_flags = page_req.m_flags;
+ Page_state state = ptr.p->m_state;
+
+ // update LIRS
+ if (! (state & Page_entry::LOCKED) &&
+ ! (req_flags & Page_request::CORR_REQ))
+ {
+ jam();
+ lirs_reference(ptr);
+ }
+
+ // start processing if request was queued
+ if (i == 0)
+ {
+ jam();
+ do_busy_loop(signal, true);
+ }
+
+ return i;
+}
+
void
Pgman::update_lsn(Ptr<Page_entry> ptr, Uint32 block, Uint64 lsn)
{
@@ -1910,9 +1960,6 @@ Pgman::drop_page(Ptr<Page_entry> ptr)
Page_state state = ptr.p->m_state;
if (! (state & (Page_entry::PAGEIN | Page_entry::PAGEOUT)))
{
- ndbrequire(state & Page_entry::BOUND);
- ndbrequire(state & Page_entry::MAPPED);
-
if (state & Page_entry::ONSTACK)
{
jam();
@@ -1922,9 +1969,13 @@ Pgman::drop_page(Ptr<Page_entry> ptr)
if (at_bottom)
{
jam();
- ndbassert(state & Page_entry::HOT);
lirs_stack_prune();
}
+ if (state & Page_entry::HOT)
+ {
+ jam();
+ state &= ~ Page_entry::HOT;
+ }
}
if (state & Page_entry::ONQUEUE)
@@ -1934,12 +1985,37 @@ Pgman::drop_page(Ptr<Page_entry> ptr)
state &= ~ Page_entry::ONQUEUE;
}
- ndbassert(ptr.p->m_real_page_i != RNIL);
- if (ptr.p->m_real_page_i != RNIL)
+ if (state & Page_entry::BUSY)
{
jam();
+ state &= ~ Page_entry::BUSY;
+ }
+
+ if (state & Page_entry::DIRTY)
+ {
+ jam();
+ state &= ~ Page_entry::DIRTY;
+ }
+
+ if (state & Page_entry::EMPTY)
+ {
+ jam();
+ state &= ~ Page_entry::EMPTY;
+ }
+
+ if (state & Page_entry::MAPPED)
+ {
+ jam();
+ state &= ~ Page_entry::MAPPED;
+ }
+
+ if (state & Page_entry::BOUND)
+ {
+ jam();
+ ndbrequire(ptr.p->m_real_page_i != RNIL);
release_cache_page(ptr.p->m_real_page_i);
ptr.p->m_real_page_i = RNIL;
+ state &= ~ Page_entry::BOUND;
}
set_page_state(ptr, state);
@@ -2152,6 +2228,8 @@ Page_cache_client::free_data_file(Signal
void
Pgman::verify_page_entry(Ptr<Page_entry> ptr)
{
+ Page_stack& pl_stack = m_page_stack;
+
Uint32 ptrI = ptr.i;
Page_state state = ptr.p->m_state;
@@ -2174,6 +2252,10 @@ Pgman::verify_page_entry(Ptr<Page_entry>
// hot entry must be on stack
ndbrequire(! is_hot || on_stack || dump_page_lists(ptrI));
+ // stack bottom is hot
+ bool at_bottom = on_stack && ! pl_stack.hasPrev(ptr);
+ ndbrequire(! at_bottom || is_hot || dump_page_lists(ptrI));
+
bool on_queue = state & Page_entry::ONQUEUE;
// hot entry is not on queue
ndbrequire(! is_hot || ! on_queue || dump_page_lists(ptrI));
@@ -2185,9 +2267,12 @@ Pgman::verify_page_entry(Ptr<Page_entry>
// entries waiting to enter queue
bool to_queue = ! is_locked && ! is_hot && ! is_bound && has_req;
- // page is either LOCKED or under LIRS
+ // page is about to be released
+ bool to_release = (state == 0);
+
+ // page is either LOCKED or under LIRS or about to be released
bool is_lirs = on_stack || to_queue || on_queue;
- ndbrequire(is_locked == ! is_lirs || dump_page_lists(ptrI));
+ ndbrequire(to_release || is_locked == ! is_lirs || dump_page_lists(ptrI));
bool pagein = state & Page_entry::PAGEIN;
bool pageout = state & Page_entry::PAGEOUT;
@@ -2219,6 +2304,9 @@ Pgman::verify_page_entry(Ptr<Page_entry>
break;
case Page_entry::SL_OTHER:
break;
+ case ZNIL:
+ ndbrequire(to_release || dump_page_lists(ptrI));
+ break;
default:
ndbrequire(false || dump_page_lists(ptrI));
break;
@@ -2228,124 +2316,114 @@ Pgman::verify_page_entry(Ptr<Page_entry>
void
Pgman::verify_page_lists()
{
+ const Stats& stats = m_stats;
+ const Param& param = m_param;
Page_hashlist& pl_hash = m_page_hashlist;
Page_stack& pl_stack = m_page_stack;
Page_queue& pl_queue = m_page_queue;
Ptr<Page_entry> ptr;
- Uint32 stack_count = 0;
- Uint32 queue_count = 0;
- Uint32 queuewait_count = 0;
- Uint32 locked_bound_count = 0;
+ Uint32 is_locked = 0;
+ Uint32 is_bound = 0;
+ Uint32 is_mapped = 0;
+ Uint32 is_hot = 0;
+ Uint32 on_stack = 0;
+ Uint32 on_queue = 0;
+ Uint32 to_queue = 0;
Page_hashlist::Iterator iter;
pl_hash.next(0, iter);
while (iter.curr.i != RNIL)
{
- verify_page_entry(iter.curr);
+ ptr = iter.curr;
+ Page_state state = ptr.p->m_state;
+ // (state == 0) occurs only within a time-slice
+ ndbrequire(state != 0);
+ verify_page_entry(ptr);
- Page_state state = iter.curr.p->m_state;
+ if (state & Page_entry::LOCKED)
+ is_locked++;
+ if (state & Page_entry::BOUND)
+ is_bound++;
+ if (state & Page_entry::MAPPED)
+ is_mapped++;
+ if (state & Page_entry::HOT)
+ is_hot++;
if (state & Page_entry::ONSTACK)
- stack_count++;
+ on_stack++;
if (state & Page_entry::ONQUEUE)
- queue_count++;
+ on_queue++;
if (! (state & Page_entry::LOCKED) &&
! (state & Page_entry::HOT) &&
(state & Page_entry::REQUEST) &&
! (state & Page_entry::BOUND))
- queuewait_count++;
- if (state & Page_entry::LOCKED &&
- state & Page_entry::BOUND)
- locked_bound_count++;
+ to_queue++;
pl_hash.next(iter);
}
- ndbrequire(stack_count == pl_stack.count() || dump_page_lists());
- ndbrequire(queue_count == pl_queue.count() || dump_page_lists());
-
- Uint32 hot_count = 0;
- Uint32 hot_bound_count = 0;
- Uint32 cold_bound_count = 0;
- Uint32 stack_request_count = 0;
- Uint32 queue_request_count = 0;
-
- Uint32 i1 = RNIL;
for (pl_stack.first(ptr); ptr.i != RNIL; pl_stack.next(ptr))
{
- ndbrequire(i1 != ptr.i);
- i1 = ptr.i;
Page_state state = ptr.p->m_state;
- ndbrequire(state & Page_entry::ONSTACK || dump_page_lists());
+ ndbrequire(state & Page_entry::ONSTACK || dump_page_lists(ptr.i));
if (! pl_stack.hasPrev(ptr))
- ndbrequire(state & Page_entry::HOT || dump_page_lists());
- if (state & Page_entry::HOT) {
- hot_count++;
- if (state & Page_entry::BOUND)
- hot_bound_count++;
- }
- if (state & Page_entry::REQUEST)
- stack_request_count++;
+ ndbrequire(state & Page_entry::HOT || dump_page_lists(ptr.i));
}
- Uint32 i2 = RNIL;
for (pl_queue.first(ptr); ptr.i != RNIL; pl_queue.next(ptr))
{
- ndbrequire(i2 != ptr.i);
- i2 = ptr.i;
Page_state state = ptr.p->m_state;
- ndbrequire(state & Page_entry::ONQUEUE || dump_page_lists());
- ndbrequire(state & Page_entry::BOUND || dump_page_lists());
- cold_bound_count++;
- if (state & Page_entry::REQUEST)
- queue_request_count++;
+ ndbrequire(state & Page_entry::ONQUEUE || dump_page_lists(ptr.i));
+ ndbrequire(state & Page_entry::BOUND || dump_page_lists(ptr.i));
+ ndbrequire(! (state & Page_entry::HOT) || dump_page_lists(ptr.i));
}
- Uint32 tot_bound_count =
- locked_bound_count + hot_bound_count + cold_bound_count;
- ndbrequire(m_stats.m_num_pages == tot_bound_count || dump_page_lists());
+ ndbrequire(is_bound == stats.m_num_pages || dump_page_lists());
+ ndbrequire(is_hot == stats.m_num_hot_pages || dump_page_lists());
+ ndbrequire(on_stack == pl_stack.count() || dump_page_lists());
+ ndbrequire(on_queue == pl_queue.count() || dump_page_lists());
Uint32 k;
Uint32 entry_count = 0;
-
+ char sublist_info[200] = "";
for (k = 0; k < Page_entry::SUBLIST_COUNT; k++)
{
const Page_sublist& pl = *m_page_sublist[k];
for (pl.first(ptr); ptr.i != RNIL; pl.next(ptr))
- {
- ndbrequire(get_sublist_no(ptr.p->m_state) == k || dump_page_lists());
- entry_count++;
- }
+ ndbrequire(get_sublist_no(ptr.p->m_state) == k || dump_page_lists(ptr.i));
+ entry_count += pl.count();
+ sprintf(sublist_info + strlen(sublist_info),
+ " %s:%u", get_sublist_name(k), pl.count());
}
-
ndbrequire(entry_count == pl_hash.count() || dump_page_lists());
+ Uint32 hit_pct = 0;
+ char hit_pct_str[20];
+ if (stats.m_page_hits + stats.m_page_faults != 0)
+ hit_pct = 10000 * stats.m_page_hits /
+ (stats.m_page_hits + stats.m_page_faults);
+ sprintf(hit_pct_str, "%u.%02u", hit_pct / 100, hit_pct % 100);
+
D("loop"
- << " stats=" << m_stats_loop_on
- << " busy=" << m_busy_loop_on
- << " cleanup=" << m_cleanup_loop_on
- << " lcp=" << m_lcp_loop_on);
-
- D("stat"
- << " entry:" << pl_hash.count()
- << " cache:" << m_stats.m_num_pages
- << "(" << locked_bound_count << "L)"
+ << " stats:" << m_stats_loop_on
+ << " busy:" << m_busy_loop_on
+ << " cleanup:" << m_cleanup_loop_on
+ << " lcp:" << m_lcp_loop_on);
+
+ D("page"
+ << " entries:" << pl_hash.count()
+ << " pages:" << stats.m_num_pages << "/" << param.m_max_pages
+ << " mapped:" << is_mapped
+ << " hot:" << is_hot
+ << " io:" << stats.m_current_io_waits << "/" << param.m_max_io_waits
+ << " hit pct:" << hit_pct_str);
+
+ D("list"
+ << " locked:" << is_locked
<< " stack:" << pl_stack.count()
- << " hot:" << hot_count
- << " hot_bound:" << hot_bound_count
- << " stack_request:" << stack_request_count
<< " queue:" << pl_queue.count()
- << " queue_request:" << queue_request_count
- << " queuewait:" << queuewait_count);
+ << " to queue:" << to_queue);
- char countbuf[200];
- countbuf[0] = 0;
- for (k = 0; k < Page_entry::SUBLIST_COUNT; k++)
- {
- const Page_sublist& pl = *m_page_sublist[k];
- sprintf(countbuf + strlen(countbuf), " %s:%u",
- get_sublist_name(k), pl.count());
- }
- D("list" << countbuf);
+ D(sublist_info);
}
void
@@ -2368,54 +2446,35 @@ Pgman::dump_page_lists(Uint32 ptrI)
// use debugOut directly
debugOut << "PGMAN: page list dump" << endl;
if (ptrI != RNIL)
- debugOut << "PGMAN: error on PE [" << ptrI << "]" << endl;
+ debugOut << "PGMAN: error on PE [" << ptrI << "]" << "\n";
Page_hashlist& pl_hash = m_page_hashlist;
Page_stack& pl_stack = m_page_stack;
Page_queue& pl_queue = m_page_queue;
Ptr<Page_entry> ptr;
Uint32 n;
- char buf[40];
- debugOut << "hash:" << endl;
- Page_hashlist::Iterator iter;
- pl_hash.next(0, iter);
- n = 0;
- while (iter.curr.i != RNIL)
- {
- sprintf(buf, "%03d", n++);
- debugOut << buf << " " << iter.curr << endl;
- pl_hash.next(iter);
- }
-
- debugOut << "stack:" << endl;
+ debugOut << "stack:" << "\n";
n = 0;
for (pl_stack.first(ptr); ptr.i != RNIL; pl_stack.next(ptr))
- {
- sprintf(buf, "%03d", n++);
- debugOut << buf << " " << ptr << endl;
- }
+ debugOut << n++ << " " << ptr << "\n";
- debugOut << "queue:" << endl;
+ debugOut << "queue:" << "\n";
n = 0;
for (pl_queue.first(ptr); ptr.i != RNIL; pl_queue.next(ptr))
- {
- sprintf(buf, "%03d", n++);
- debugOut << buf << " " << ptr << endl;
- }
+ debugOut << n++ << " " << ptr << "\n";
Uint32 k;
for (k = 0; k < Page_entry::SUBLIST_COUNT; k++)
{
- debugOut << get_sublist_name(k) << ":" << endl;
+ debugOut << get_sublist_name(k) << ":" << "\n";
const Page_sublist& pl = *m_page_sublist[k];
+ n = 0;
for (pl.first(ptr); ptr.i != RNIL; pl.next(ptr))
- {
- sprintf(buf, "%03d", n++);
- debugOut << buf << " " << ptr << endl;
- }
+ debugOut << n++ << " " << ptr << "\n";
}
+ debugOut.flushline();
return false;
}
@@ -2432,9 +2491,9 @@ Pgman::get_sublist_name(Uint32 list_no)
case Page_entry::SL_MAP_IO:
return "map_io";
case Page_entry::SL_CALLBACK:
- return "callback";
+ return "cb";
case Page_entry::SL_CALLBACK_IO:
- return "callback_io";
+ return "cb_io";
case Page_entry::SL_BUSY:
return "busy";
case Page_entry::SL_LOCKED:
@@ -2580,6 +2639,15 @@ Pgman::execDUMP_STATE_ORD(Signal* signal
{
jamEntry();
Page_hashlist& pl_hash = m_page_hashlist;
+#ifdef VM_TRACE
+ if (signal->theData[0] == 11000 && signal->getLength() == 2)
+ {
+ // has no effect currently
+ Uint32 flag = signal->theData[1];
+ debugFlag = flag & 1;
+ debugSummaryFlag = flag & 2;
+ }
+#endif
if (signal->theData[0] == 11001)
{
=== modified file 'storage/ndb/src/kernel/blocks/pgman.hpp'
--- a/storage/ndb/src/kernel/blocks/pgman.hpp 2009-05-27 15:21:45 +0000
+++ b/storage/ndb/src/kernel/blocks/pgman.hpp 2009-11-27 09:22:07 +0000
@@ -54,7 +54,7 @@
* Updating a resident cache page makes it "dirty". A background
* clean-up process makes dirty pages "clean" via "pageout" to disk.
* Write ahead logging (WAL) of the page is done first i.e. UNDO log is
- * flushed up to the page log sequence number (LSN) by calling a TSMAN
+ * flushed up to the page log sequence number (LSN) by calling a LGMAN
* method. The reason for this is obvious but not relevant to PGMAN.
*
* A local check point (LCP) periodically performs a complete pageout of
@@ -420,9 +420,10 @@ private:
struct Stats {
Stats();
Uint32 m_num_pages; // current number of cache pages
- Uint32 m_page_hits;
- Uint32 m_page_faults;
+ Uint32 m_num_hot_pages;
Uint32 m_current_io_waits;
+ Uint64 m_page_hits;
+ Uint64 m_page_faults;
} m_stats;
enum CallbackIndex {
@@ -495,6 +496,7 @@ private:
void fswritereq(Signal*, Ptr<Page_entry>);
void fswriteconf(Signal*, Ptr<Page_entry>);
+ int get_page_no_lirs(Signal*, Ptr<Page_entry>, Page_request page_req);
int get_page(Signal*, Ptr<Page_entry>, Page_request page_req);
void update_lsn(Ptr<Page_entry>, Uint32 block, Uint64 lsn);
Uint32 create_data_file();
@@ -504,6 +506,8 @@ private:
int drop_page(Ptr<Page_entry>);
#ifdef VM_TRACE
+ bool debugFlag; // not yet in use in 7.0
+ bool debugSummaryFlag; // loop summary to signal log even if ! debugFlag
void verify_page_entry(Ptr<Page_entry> ptr);
void verify_page_lists();
void verify_all();
Attachment: [text/bzr-bundle] bzr/jonas@mysql.com-20091127114642-ldq7j7hikxtoz6l4.bundle
| Thread |
|---|
| • bzr push into mysql-5.1-telco-7.1 branch (jonas:3165 to 3166) | Jonas Oreland | 27 Nov |