#At file:///home/marty/MySQL/mysql-5.1-telco-6.2/
3040 Martin Skold 2009-12-01 [merge]
Merge
modified:
storage/ndb/src/kernel/blocks/ndbfs/AsyncFile.hpp
storage/ndb/src/kernel/blocks/ndbfs/MemoryChannel.hpp
storage/ndb/src/kernel/blocks/pgman.cpp
storage/ndb/src/kernel/blocks/pgman.hpp
storage/ndb/src/ndbapi/NdbOperationDefine.cpp
storage/ndb/src/ndbapi/NdbOperationSearch.cpp
storage/ndb/test/ndbapi/testBlobs.cpp
storage/ndb/test/run-test/daily-basic-tests.txt
=== modified file 'storage/ndb/src/kernel/blocks/ndbfs/AsyncFile.hpp'
--- a/storage/ndb/src/kernel/blocks/ndbfs/AsyncFile.hpp 2009-05-26 18:53:34 +0000
+++ b/storage/ndb/src/kernel/blocks/ndbfs/AsyncFile.hpp 2009-11-30 11:12:13 +0000
@@ -167,6 +167,8 @@ public:
// Information for open, needed if the first open action fails.
AsyncFile* file;
Uint32 theTrace;
+
+ MemoryChannel<Request>::ListMember m_mem_channel;
};
NdbOut& operator <<(NdbOut&, const Request&);
=== modified file 'storage/ndb/src/kernel/blocks/ndbfs/MemoryChannel.hpp'
--- a/storage/ndb/src/kernel/blocks/ndbfs/MemoryChannel.hpp 2009-05-26 18:53:34 +0000
+++ b/storage/ndb/src/kernel/blocks/ndbfs/MemoryChannel.hpp 2009-11-30 11:12:13 +0000
@@ -78,19 +78,26 @@ template <class T>
class MemoryChannel
{
public:
- MemoryChannel( int size= 512);
- virtual ~MemoryChannel( );
+ MemoryChannel();
+ virtual ~MemoryChannel();
- void writeChannel( T *t);
- void writeChannelNoSignal( T *t);
+ void writeChannel(T *t);
+ void writeChannelNoSignal(T *t);
T* readChannel();
T* tryReadChannel();
+ /**
+ * Should be made class using MemoryChannel
+ */
+ struct ListMember
+ {
+ T* m_next;
+ };
+
private:
- int theSize;
- T **theChannel;
- CircularIndex theWriteIndex;
- CircularIndex theReadIndex;
+ Uint32 m_occupancy;
+ T* m_head; // First element in list (e.g will be read by readChannel)
+ T* m_tail;
NdbMutex* theMutexPtr;
NdbCondition* theConditionPtr;
@@ -102,18 +109,14 @@ template <class T>
NdbOut& operator<<(NdbOut& out, const MemoryChannel<T> & chn)
{
NdbMutex_Lock(chn.theMutexPtr);
- out << "[ theSize: " << chn.theSize
- << " theReadIndex: " << (int)chn.theReadIndex
- << " theWriteIndex: " << (int)chn.theWriteIndex << " ]";
+ out << "[ occupancy: " << chn.m_occupancy
+ << " ]";
NdbMutex_Unlock(chn.theMutexPtr);
return out;
}
-template <class T> MemoryChannel<T>::MemoryChannel( int size):
- theSize(size),
- theChannel(new T*[size] ),
- theWriteIndex(0, size),
- theReadIndex(0, size)
+template <class T> MemoryChannel<T>::MemoryChannel() :
+ m_occupancy(0), m_head(0), m_tail(0)
{
theMutexPtr = NdbMutex_Create();
theConditionPtr = NdbCondition_Create();
@@ -123,55 +126,79 @@ template <class T> MemoryChannel<T>::~Me
{
NdbMutex_Destroy(theMutexPtr);
NdbCondition_Destroy(theConditionPtr);
- delete [] theChannel;
}
template <class T> void MemoryChannel<T>::writeChannel( T *t)
{
-
- NdbMutex_Lock(theMutexPtr);
- if(full(theWriteIndex, theReadIndex) || theChannel == NULL) abort();
- theChannel[theWriteIndex]= t;
- ++theWriteIndex;
- NdbMutex_Unlock(theMutexPtr);
+ writeChannelNoSignal(t);
NdbCondition_Signal(theConditionPtr);
}
template <class T> void MemoryChannel<T>::writeChannelNoSignal( T *t)
{
-
NdbMutex_Lock(theMutexPtr);
- if(full(theWriteIndex, theReadIndex) || theChannel == NULL) abort();
- theChannel[theWriteIndex]= t;
- ++theWriteIndex;
+ if (m_head == 0)
+ {
+ assert(m_occupancy == 0);
+ m_head = m_tail = t;
+ }
+ else
+ {
+ assert(m_tail != 0);
+ m_tail->m_mem_channel.m_next = t;
+ m_tail = t;
+ }
+ t->m_mem_channel.m_next = 0;
+ m_occupancy++;
NdbMutex_Unlock(theMutexPtr);
}
template <class T> T* MemoryChannel<T>::readChannel()
{
- T* tmp;
-
NdbMutex_Lock(theMutexPtr);
- while ( empty(theWriteIndex, theReadIndex) )
+ while (m_head == 0)
{
+ assert(m_occupancy == 0);
NdbCondition_Wait(theConditionPtr,
- theMutexPtr);
+ theMutexPtr);
}
-
- tmp= theChannel[theReadIndex];
- ++theReadIndex;
+ assert(m_occupancy > 0);
+ T* tmp = m_head;
+ if (m_head == m_tail)
+ {
+ assert(m_occupancy == 1);
+ m_head = m_tail = 0;
+ }
+ else
+ {
+ m_head = m_head->m_mem_channel.m_next;
+ }
+ m_occupancy--;
NdbMutex_Unlock(theMutexPtr);
return tmp;
}
template <class T> T* MemoryChannel<T>::tryReadChannel()
{
- T* tmp= 0;
NdbMutex_Lock(theMutexPtr);
- if ( !empty(theWriteIndex, theReadIndex) )
- {
- tmp= theChannel[theReadIndex];
- ++theReadIndex;
+ T* tmp = m_head;
+ if (m_head != 0)
+ {
+ assert(m_occupancy > 0);
+ if (m_head == m_tail)
+ {
+ assert(m_occupancy == 1);
+ m_head = m_tail = 0;
+ }
+ else
+ {
+ m_head = m_head->m_mem_channel.m_next;
+ }
+ m_occupancy--;
+ }
+ else
+ {
+ assert(m_occupancy == 0);
}
NdbMutex_Unlock(theMutexPtr);
return tmp;
=== modified file 'storage/ndb/src/kernel/blocks/pgman.cpp'
--- a/storage/ndb/src/kernel/blocks/pgman.cpp 2009-05-26 18:53:34 +0000
+++ b/storage/ndb/src/kernel/blocks/pgman.cpp 2009-11-26 19:25:10 +0000
@@ -34,14 +34,6 @@
Page_request::DIRTY_REQ | \
Page_request::ALLOC_REQ)
-// todo use this
-#ifdef VM_TRACE
-#define dbg(x) \
- do { if (! debugFlag) break; debugOut << "PGMAN: " << x << endl; } while (0)
-#else
-#define dbg(x)
-#endif
-
static bool g_dbg_lcp = false;
#if 1
#define DBG_LCP(x)
@@ -58,6 +50,7 @@ Pgman::Pgman(Block_context& ctx) :
#ifdef VM_TRACE
,debugOut(* new NullOutputStream())
,debugFlag(false)
+ ,debugSummaryFlag(false)
#endif
{
BLOCK_CONSTRUCTOR(Pgman);
@@ -129,6 +122,7 @@ Pgman::execREAD_CONFIG_REQ(Signal* signa
m_param.m_max_pages = page_buffer;
m_page_entry_pool.setSize(m_param.m_lirs_stack_mult * page_buffer);
m_param.m_max_hot_pages = (page_buffer * 9) / 10;
+ ndbrequire(m_param.m_max_hot_pages >= 1);
}
Pool_context pc;
@@ -156,9 +150,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)
{
}
@@ -280,10 +275,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))
@@ -315,7 +306,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
@@ -350,10 +345,25 @@ 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--;
+ }
}
#ifdef VM_TRACE
debugOut << "PGMAN: " << ptr << ": after" << endl;
+ verify_page_entry(ptr);
debugOut << "PGMAN: <set_page_state" << endl;
#endif
}
@@ -635,8 +645,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)
{
@@ -678,6 +690,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();
@@ -701,8 +719,8 @@ Pgman::lirs_reference(Ptr<Page_entry> pt
else
{
#ifdef VM_TRACE
- debugOut << "PGMAN: filling up initial hot pages: "
- << m_stats.m_num_pages << " of "
+ debugOut << "PGMAN: filling up hot pages: "
+ << m_stats.m_num_hot_pages << "/"
<< m_param.m_max_hot_pages << endl;
#endif
jam();
@@ -1046,11 +1064,11 @@ Pgman::process_callback(Signal* signal,
debugOut << "PGMAN: " << ptr << " : process_callback" << endl;
#endif
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;
{
@@ -1092,19 +1110,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;
}
@@ -1657,7 +1674,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();
#ifdef VM_TRACE
@@ -1698,16 +1715,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))
@@ -1794,8 +1801,6 @@ 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);
#ifdef VM_TRACE
debugOut << "PGMAN: " << req_ptr << endl;
@@ -1804,6 +1809,37 @@ Pgman::get_page(Signal* signal, Ptr<Page
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)
{
@@ -1929,9 +1965,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();
@@ -1941,9 +1974,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)
@@ -1953,12 +1990,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);
@@ -1977,6 +2039,8 @@ Pgman::drop_page(Ptr<Page_entry> ptr)
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;
@@ -1999,6 +2063,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));
@@ -2010,9 +2078,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;
@@ -2044,6 +2115,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;
@@ -2053,122 +2127,125 @@ 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());
- debugOut << "PGMAN: loop"
- << " stats=" << m_stats_loop_on
- << " busy=" << m_busy_loop_on
- << " cleanup=" << m_cleanup_loop_on
- << " lcp=" << m_lcp_loop_on << endl;
-
- debugOut << "PGMAN:"
- << " entry:" << pl_hash.count()
- << " cache:" << m_stats.m_num_pages
- << "(" << locked_bound_count << "L)"
- << " 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 << endl;
+ 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);
- debugOut << "PGMAN:";
- for (k = 0; k < Page_entry::SUBLIST_COUNT; k++)
- {
- const Page_sublist& pl = *m_page_sublist[k];
- debugOut << " " << get_sublist_name(k) << ":" << pl.count();
- }
- debugOut << endl;
+ if (! debugFlag && debugSummaryFlag)
+ open_debug_file(1);
+
+ debugOut
+ << "PGMAN: loop"
+ << " stats:" << m_stats_loop_on
+ << " busy:" << m_busy_loop_on
+ << " cleanup:" << m_cleanup_loop_on
+ << " lcp:" << m_lcp_loop_on << endl;
+
+ debugOut
+ << "PGMAN:"
+ << " 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 << endl;
+
+ debugOut
+ << "PGMAN:"
+ << " locked:" << is_locked
+ << " stack:" << pl_stack.count()
+ << " queue:" << pl_queue.count()
+ << " to queue:" << to_queue << endl;
+
+ debugOut
+ << "PGMAN:"
+ << sublist_info << endl;
+
+ if (! debugFlag && debugSummaryFlag)
+ open_debug_file(0);
}
void
@@ -2191,56 +2268,37 @@ Pgman::dump_page_lists(Uint32 ptrI)
if (! debugFlag)
open_debug_file(1);
- debugOut << "PGMAN: page list dump" << endl;
+ debugOut << "PGMAN: page list dump" << "\n";
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();
if (! debugFlag)
open_debug_file(0);
@@ -2260,9 +2318,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:
@@ -2407,8 +2465,9 @@ Pgman::execDUMP_STATE_ORD(Signal* signal
if (signal->theData[0] == 11000 && signal->getLength() == 2)
{
Uint32 flag = signal->theData[1];
- open_debug_file(flag);
- debugFlag = flag;
+ debugFlag = flag & 1;
+ debugSummaryFlag = flag & 2;
+ open_debug_file(debugFlag);
}
#endif
=== modified file 'storage/ndb/src/kernel/blocks/pgman.hpp'
--- a/storage/ndb/src/kernel/blocks/pgman.hpp 2009-05-26 18:53:34 +0000
+++ b/storage/ndb/src/kernel/blocks/pgman.hpp 2009-11-26 19:24:32 +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
@@ -418,9 +418,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;
protected:
@@ -482,6 +483,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();
@@ -493,6 +495,7 @@ private:
#ifdef VM_TRACE
NdbOut debugOut;
bool debugFlag;
+ 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();
=== modified file 'storage/ndb/src/ndbapi/NdbOperationDefine.cpp'
--- a/storage/ndb/src/ndbapi/NdbOperationDefine.cpp 2009-05-26 18:53:34 +0000
+++ b/storage/ndb/src/ndbapi/NdbOperationDefine.cpp 2009-11-27 13:17:22 +0000
@@ -698,6 +698,26 @@ NdbOperation::getBlobHandle(NdbTransacti
return NULL;
}
+ /* Check key fully defined for key operations */
+ switch (theStatus)
+ {
+ case TupleKeyDefined:
+ case GetValue:
+ case SetValue:
+ case FinalGetValue:
+ case ExecInterpretedValue:
+ case SetValueInterpreted:
+ /* All ok states to create a Blob Handle in */
+ break;
+ default:
+ {
+ /* Unexpected state to be obtaining Blob handle */
+ /* Invalid usage of blob attribute */
+ setErrorCodeAbort(4264);
+ return NULL;
+ }
+ }
+
tBlob = theNdb->getNdbBlob();
if (tBlob == NULL)
return NULL;
=== modified file 'storage/ndb/src/ndbapi/NdbOperationSearch.cpp'
--- a/storage/ndb/src/ndbapi/NdbOperationSearch.cpp 2009-05-26 18:53:34 +0000
+++ b/storage/ndb/src/ndbapi/NdbOperationSearch.cpp 2009-11-27 13:13:26 +0000
@@ -473,7 +473,8 @@ NdbOperation::reorderKEYINFO()
{
Uint32 data[ NDB_MAX_KEYSIZE_IN_WORDS ];
Uint32 size = NDB_MAX_KEYSIZE_IN_WORDS;
- getKeyFromTCREQ(data, size);
+ int rc = getKeyFromTCREQ(data, size);
+ assert(rc == 0);
Uint32 pos = 1;
Uint32 k;
for (k = 0; k < m_accessTable->m_noOfKeys; k++) {
@@ -505,7 +506,10 @@ NdbOperation::reorderKEYINFO()
int
NdbOperation::getKeyFromTCREQ(Uint32* data, Uint32 & size)
{
- assert(size >= theTupKeyLen && theTupKeyLen > 0);
+ /* Check that we can correctly return a valid key */
+ if ((size < theTupKeyLen) || (theTupKeyLen == 0))
+ return -1;
+
size = theTupKeyLen;
unsigned pos = 0;
while (pos < 8 && pos < size) {
=== modified file 'storage/ndb/test/ndbapi/testBlobs.cpp'
--- a/storage/ndb/test/ndbapi/testBlobs.cpp 2009-10-26 20:02:17 +0000
+++ b/storage/ndb/test/ndbapi/testBlobs.cpp 2009-11-27 13:17:22 +0000
@@ -3997,6 +3997,87 @@ bugtest_27370()
return 0;
}
+static int
+bugtest_28116()
+{
+ DBG("bug test 28116 - Crash in getBlobHandle() when called without full key");
+
+ if (g_opt.m_pk2chr.m_len == 0)
+ {
+ DBG(" ... skipped, requires multi-column primary key.");
+ return 0;
+ }
+
+ for (unsigned k = 0; k < g_opt.m_rows; k++) {
+ Tup& tup = g_tups[k];
+ CHK((g_con = g_ndb->startTransaction()) != 0);
+ CHK((g_opr = g_con->getNdbOperation(g_opt.m_tname)) != 0);
+ int reqType = urandom(4);
+ switch(reqType) {
+ case 0:
+ {
+ DBG("Read");
+ CHK(g_opr->readTuple() == 0);
+ break;
+ }
+ case 1:
+ {
+ DBG("Insert");
+ CHK(g_opr->insertTuple() == 0);
+ break;
+ }
+ case 2:
+ {
+ DBG("Update");
+ CHK(g_opr->updateTuple() == 0);
+ break;
+ }
+ case 3:
+ default:
+ {
+ DBG("Delete");
+ CHK(g_opr->deleteTuple() == 0);
+ break;
+ }
+ }
+ switch (urandom(3)) {
+ case 0:
+ {
+ DBG(" No keys");
+ break;
+ }
+ case 1:
+ {
+ DBG(" Pk1 only");
+ CHK(g_opr->equal("PK1", tup.m_pk1) == 0);
+ break;
+ }
+ case 2:
+ default:
+ {
+ DBG(" Pk2/3 only");
+ if (g_opt.m_pk2chr.m_len != 0)
+ {
+ CHK(g_opr->equal("PK2", tup.m_pk2) == 0);
+ CHK(g_opr->equal("PK3", tup.m_pk3) == 0);
+ }
+ break;
+ }
+ }
+ /* Deliberately no equal() on rest of primary key, to provoke error. */
+ CHK(g_opr->getBlobHandle("BL1") == 0);
+
+ /* 4264 - Invalid usage of Blob attribute */
+ CHK(g_con->getNdbError().code == 4264);
+ CHK(g_opr->getNdbError().code == 4264);
+
+ g_ndb->closeTransaction(g_con);
+ g_opr = 0;
+ g_con = 0;
+ }
+ return 0;
+}
+
static struct {
int m_bug;
int (*m_test)();
@@ -4006,7 +4087,8 @@ static struct {
{ 27370, bugtest_27370 },
{ 36756, bugtest_36756 },
{ 45768, bugtest_45768 },
- { 48040, bugtest_48040 }
+ { 48040, bugtest_48040 },
+ { 28116, bugtest_28116 }
};
NDB_COMMAND(testOdbcDriver, "testBlobs", "testBlobs", "testBlobs", 65535)
=== modified file 'storage/ndb/test/run-test/daily-basic-tests.txt'
--- a/storage/ndb/test/run-test/daily-basic-tests.txt 2009-10-26 20:02:17 +0000
+++ b/storage/ndb/test/run-test/daily-basic-tests.txt 2009-11-27 13:17:22 +0000
@@ -1378,3 +1378,7 @@ max-time: 300
cmd: testBasic
args: -n DDInsertFailUpdateBatch D1 D2
+max-time: 300
+cmd: testBlobs
+args: -skip hp -bug 28116
+
| Thread |
|---|
| • bzr commit into mysql-5.1-telco-6.2 branch (Martin.Skold:3040) Bug#28116Bug#48861 Bug#48910 Bug#48973 | Martin Skold | 1 Dec |