From: John David Duncan Date: May 17 2011 4:55am Subject: bzr commit into mysql-5.1-telco-7.2 branch (john.duncan:4177) List-Archive: http://lists.mysql.com/commits/137493 Message-Id: <201105170456.p4H4uASA023897@acsmt358.oracle.com> MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="===============0651389663==" --===============0651389663== MIME-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Content-Disposition: inline #At file:///Users/jdd/bzr-repo/working/cluster-7.2-labs-memcached/ based on revid:john.duncan@stripped 4177 John David Duncan 2011-05-16 Send NdbApi requests from the commit thread. modified: storage/ndb/memcache/include/Scheduler.h storage/ndb/memcache/include/ndb_worker.h storage/ndb/memcache/include/workitem.h storage/ndb/memcache/src/ClusterConnectionPool.cc storage/ndb/memcache/src/ndb_worker.cc storage/ndb/memcache/src/schedulers/Bulk.h storage/ndb/memcache/src/schedulers/Flex.h storage/ndb/memcache/src/schedulers/Flex_cluster.cc storage/ndb/memcache/src/schedulers/Stockholm.cc storage/ndb/memcache/src/schedulers/Stockholm.h === modified file 'storage/ndb/memcache/include/Scheduler.h' --- a/storage/ndb/memcache/include/Scheduler.h 2011-04-08 08:14:11 +0000 +++ b/storage/ndb/memcache/include/Scheduler.h 2011-05-17 04:55:39 +0000 @@ -54,6 +54,10 @@ public: an Ndb object for the operation and send the workitem to be executed. */ virtual ENGINE_ERROR_CODE schedule(workitem *) = 0; + /** when a workitem requires multiple NDB operations, reschedule() is used + to schedule the second and subsequent ones. */ + virtual void reschedule(workitem *) const = 0; + /** io_completed() is called from the NDB Engine thread when an IO completion notification has been received */ virtual void io_completed(workitem *) = 0; === modified file 'storage/ndb/memcache/include/ndb_worker.h' --- a/storage/ndb/memcache/include/ndb_worker.h 2011-04-06 04:31:28 +0000 +++ b/storage/ndb/memcache/include/ndb_worker.h 2011-05-17 04:55:39 +0000 @@ -21,9 +21,8 @@ #define NDBMEMCACHE_NDB_WORKER_H -/* worker_prepare_operation(). - Returns TRUE if operation is prepared. - FALSE if it is not supported. +/* worker_prepare_operation(): + Returns TRUE if an operation has been prepared with executeAsynchPrepare(). */ bool worker_prepare_operation(workitem *); === modified file 'storage/ndb/memcache/include/workitem.h' --- a/storage/ndb/memcache/include/workitem.h 2011-04-06 04:31:28 +0000 +++ b/storage/ndb/memcache/include/workitem.h 2011-05-17 04:55:39 +0000 @@ -50,7 +50,8 @@ typedef struct workitem { unsigned retries : 3; /*! how many times this job has been retried */ unsigned complete : 1; /*! is this operation finished? */ unsigned broker : 2; /*! for use by the flex scheduler */ - unsigned _unused : 2; /*! (32 bits total) */ + unsigned reschedule : 1; /*! inform scheduler to send and poll again */ + unsigned cas_owner : 1; /*! set if this engine owns the CAS ID */ } base; unsigned int id; struct workitem *previous; /*! used to chain workitems in multi-key get */ === modified file 'storage/ndb/memcache/src/ClusterConnectionPool.cc' --- a/storage/ndb/memcache/src/ClusterConnectionPool.cc 2011-04-07 11:20:56 +0000 +++ b/storage/ndb/memcache/src/ClusterConnectionPool.cc 2011-05-17 04:55:39 +0000 @@ -27,6 +27,7 @@ extern EXTENSION_LOGGER_DESCRIPTOR *logger; +// TODO: Why doesn't this use member variable connect_string ?? Ndb_cluster_connection * ClusterConnectionPool::connect(const char *connectstring) { DEBUG_ENTER(); === modified file 'storage/ndb/memcache/src/ndb_worker.cc' --- a/storage/ndb/memcache/src/ndb_worker.cc 2011-04-19 01:16:36 +0000 +++ b/storage/ndb/memcache/src/ndb_worker.cc 2011-05-17 04:55:39 +0000 @@ -46,6 +46,7 @@ #include "NdbInstance.h" #include "status_block.h" #include "Operation.h" +#include "Scheduler.h" #include "ndb_engine.h" #include "hash_item_util.h" #include "ndb_worker.h" @@ -116,7 +117,10 @@ void worker_set_cas(ndb_pipeline *p, uin DEBUG_PRINT("hi:%lx lo:%lx cas:%llx (%llu)", cas_hi, cas_lo, *cas, *cas); } - +/* worker_prepare_operation(): + Called from the scheduler. + Returns true if executeAsynchPrepare() has been called on the item. +*/ bool worker_prepare_operation(workitem *newitem) { bool server_cas = (newitem->prefix_info.has_cas_col && newitem->cas); bool r; @@ -148,7 +152,7 @@ bool worker_prepare_operation(workitem * return false; /* not supported */ } - return r; /* fixme: distinguish "not supported" from "failed" */ + return r; } @@ -183,9 +187,8 @@ bool worker_do_delete(workitem *wqitem, } } - /* NdbTransaction::executeAsynch() */ - tx->executeAsynch(NdbTransaction::Commit, DBcallback, (void *) wqitem, - NdbOperation::DefaultAbortOption, 1); + /* Prepare for execution */ + tx->executeAsynchPrepare(NdbTransaction::Commit, DBcallback, (void *) wqitem); return true; } @@ -285,9 +288,7 @@ bool worker_do_write(workitem *wqitem, b return false; } - /* NdbTransaction::executeAsynch() */ - tx->executeAsynch(NdbTransaction::Commit, DBcallback, (void *) wqitem, - NdbOperation::DefaultAbortOption, 1); + tx->executeAsynchPrepare(NdbTransaction::Commit, DBcallback, (void *) wqitem); return true; } @@ -321,15 +322,13 @@ bool worker_do_read(workitem *wqitem, bo /* Save the workitem in the transaction and prepare for async execution */ if(wqitem->base.verb == OPERATION_APPEND || wqitem->base.verb == OPERATION_PREPEND) { - DEBUG_PRINT("In read() portion of APPEND. Value = %s", + DEBUG_PRINT("In read() portion of APPEND. Value = %s", hash_item_get_data(wqitem->cache_item)); - tx->executeAsynch(NdbTransaction::NoCommit, rewriteCallback, (void *) wqitem, - NdbOperation::DefaultAbortOption, 1); + tx->executeAsynchPrepare(NdbTransaction::NoCommit, rewriteCallback, (void *) wqitem); } else { - tx->executeAsynch(NdbTransaction::Commit, DBcallback, (void *) wqitem, - NdbOperation::DefaultAbortOption, 1); + tx->executeAsynchPrepare(NdbTransaction::Commit, DBcallback, (void *) wqitem); } return true; @@ -476,8 +475,7 @@ bool worker_do_math(workitem *wqitem, bo } } - tx->executeAsynch(NdbTransaction::Commit, incrCallback, (void *) wqitem, - NdbOperation::DefaultAbortOption, 1); + tx->executeAsynchPrepare(NdbTransaction::Commit, incrCallback, (void *) wqitem); return true; } @@ -630,14 +628,13 @@ void rewriteCallback(int result, NdbTran op.setColumnBigUnsigned(COL_STORE_CAS, * item->cas); ndb_op = op.updateTuple(tx); - /* Error case; operation has not been built */ if(ndb_op) { - tx->executeAsynch(NdbTransaction::Commit, DBcallback, (void *) item, - NdbOperation::DefaultAbortOption, 1); - // fixme: this should call back into the scheduler! - item->ndb_instance->db->pollNdb(); + // Inform the scheduler that this item must be re-polled + item->pipeline->scheduler->reschedule(item); + tx->executeAsynchPrepare(NdbTransaction::Commit, DBcallback, (void *) item); } else { + /* Error case; operation has not been built */ DEBUG_PRINT("NDB operation failed. workitem %d.%d", item->pipeline->id, item->id); tx->close(); === modified file 'storage/ndb/memcache/src/schedulers/Bulk.h' --- a/storage/ndb/memcache/src/schedulers/Bulk.h 2011-04-19 01:16:36 +0000 +++ b/storage/ndb/memcache/src/schedulers/Bulk.h 2011-05-17 04:55:39 +0000 @@ -27,6 +27,7 @@ #include #include "config.h" +#include "workitem.h" #include "Scheduler.h" #include "NdbInstance.h" @@ -42,6 +43,7 @@ public: void init(int threadnum, int nthreads, const char *config_string); void attach_thread(thread_identifier *); ENGINE_ERROR_CODE schedule(workitem *); + void reschedule(workitem *) const; // inlined void io_completed(workitem *); void add_stats(ADD_STAT, const void *); void * run_ndb_commit_thread(int thread_id); @@ -61,5 +63,11 @@ private: }; +inline void Scheduler_bulk::reschedule(workitem *item) const { + LockableNdbInstance * inst = (LockableNdbInstance *) item->ndb_instance ; + assert(inst->is_locked); + inst->npending++; +} + #endif === modified file 'storage/ndb/memcache/src/schedulers/Flex.h' --- a/storage/ndb/memcache/src/schedulers/Flex.h 2011-04-07 11:20:56 +0000 +++ b/storage/ndb/memcache/src/schedulers/Flex.h 2011-05-17 04:55:39 +0000 @@ -56,6 +56,7 @@ public: void init(int threadnum, int nthreads, const char *config_string); void attach_thread(thread_identifier *); ENGINE_ERROR_CODE schedule(workitem *); + void reschedule(workitem *) const; // inlined void io_completed(workitem *); void add_stats(ADD_STAT, const void *); @@ -83,6 +84,11 @@ protected: }; +inline void Scheduler_flex::reschedule(workitem *item) const { + item->base.reschedule = 1; +} + + /* Random stat samples will on average be taken twice as often as FLEX_STATS_SAMPLE_INTERVAL (based on uniform random distribution). FLEX_STATS_INITIAL_INTERVAL is lower so as to get stats quickly on startup. === modified file 'storage/ndb/memcache/src/schedulers/Flex_cluster.cc' --- a/storage/ndb/memcache/src/schedulers/Flex_cluster.cc 2011-04-09 07:36:24 +0000 +++ b/storage/ndb/memcache/src/schedulers/Flex_cluster.cc 2011-05-17 04:55:39 +0000 @@ -162,8 +162,8 @@ ENGINE_ERROR_CODE Scheduler_flex::Cluste if(! newitem->plan) return ENGINE_FAILED; // Build the NDB transaction - if(worker_prepare_operation(newitem)) { - + if(worker_prepare_operation(newitem)) { + if(do_queue_sample-- == 0) { // Sample for statistics. /* To simulate sampling the depth immediately after the item is added, sample it now and add one. */ @@ -174,11 +174,11 @@ ENGINE_ERROR_CODE Scheduler_flex::Cluste stats.queue_total_depth += depth; stats.queue_samples++; } - do_queue_sample = random() % FLEX_STATS_SAMPLE_INTERVAL; + do_queue_sample = (random() % FLEX_STATS_SAMPLE_INTERVAL) + 1; } - // Put the NdbInstance on the queue for the commit thread. - workqueue_add(queue, inst); + // Put the workitem on the queue for the commit thread. + workqueue_add(queue, newitem); return ENGINE_EWOULDBLOCK; } else return ENGINE_ENOTSUP; @@ -211,16 +211,20 @@ void Scheduler_flex::Cluster::contribute void * Scheduler_flex::Cluster::run_commit_thread() { DEBUG_ENTER(); - NdbInstance *inst; + workitem *item; while(1) { /* Wait for something to appear on the queue */ - inst = (NdbInstance *) workqueue_consumer_wait(queue); + item = (workitem *) workqueue_consumer_wait(queue); - if(inst == NULL) return 0; /* queue has been shut down and emptied */ + if(item == NULL) return 0; /* queue has been shut down and emptied */ - /* Poll */ - inst->db->pollNdb(); + /* Send & Poll */ + item->ndb_instance->db->sendPollNdb(WAITFOR_RESPONSE_TIMEOUT, 1, 1); + while(item->base.reschedule) { + item->base.reschedule = 0; + item->ndb_instance->db->sendPollNdb(WAITFOR_RESPONSE_TIMEOUT, 1, 1); + } } } === modified file 'storage/ndb/memcache/src/schedulers/Stockholm.cc' --- a/storage/ndb/memcache/src/schedulers/Stockholm.cc 2011-04-19 01:16:36 +0000 +++ b/storage/ndb/memcache/src/schedulers/Stockholm.cc 2011-05-17 04:55:39 +0000 @@ -186,9 +186,7 @@ ENGINE_ERROR_CODE Scheduler_stockholm::s // Build the NDB transaction if(worker_prepare_operation(newitem)) { - // Put the NdbInstance on the queue for the commit thread. - // Should probably be the workitem? - workqueue_add(cluster[c].queue, inst); + workqueue_add(cluster[c].queue, newitem); // place item on queue return ENGINE_EWOULDBLOCK; } else return ENGINE_ENOTSUP; @@ -241,16 +239,20 @@ void * run_stockholm_commit_thread(void Get an item off the workqueue, and call pollNdb() on that item. */ void * Scheduler_stockholm::run_ndb_commit_thread(int c) { - NdbInstance *inst; + workitem *item; DEBUG_ENTER(); while(1) { /* Wait for something to appear on the queue */ - inst = (NdbInstance *) workqueue_consumer_wait(cluster[c].queue); + item = (workitem *) workqueue_consumer_wait(cluster[c].queue); - /* Poll */ - inst->db->pollNdb(); + /* Sen & poll for response */ + item->ndb_instance->db->sendPollNdb(WAITFOR_RESPONSE_TIMEOUT, 1, 1); + while(item->base.reschedule == 1) { + item->base.reschedule = 0; + item->ndb_instance->db->sendPollNdb(WAITFOR_RESPONSE_TIMEOUT, 1, 1); + } cluster[c].stats.cycles++; if(! (cluster[c].stats.cycles % STAT_INTERVAL)) === modified file 'storage/ndb/memcache/src/schedulers/Stockholm.h' --- a/storage/ndb/memcache/src/schedulers/Stockholm.h 2011-04-07 11:20:56 +0000 +++ b/storage/ndb/memcache/src/schedulers/Stockholm.h 2011-05-17 04:55:39 +0000 @@ -28,6 +28,7 @@ #include #include "ndbmemcache_config.h" +#include "workitem.h" #include "Scheduler.h" #include "KeyPrefix.h" @@ -45,6 +46,7 @@ public: void init(int threadnum, int nthreads, const char *config_string); void attach_thread(thread_identifier *); ENGINE_ERROR_CODE schedule(workitem *); + void reschedule(workitem *) const; // inlined void io_completed(workitem *); void add_stats(ADD_STAT, const void *); void * run_ndb_commit_thread(int cluster_id); @@ -64,5 +66,10 @@ private: }; +inline void Scheduler_stockholm::reschedule(workitem *item) const { + item->base.reschedule = 1; +} + + #endif --===============0651389663== MIME-Version: 1.0 Content-Type: text/bzr-bundle; charset="us-ascii"; name="bzr/john.duncan@stripped" Content-Transfer-Encoding: 7bit Content-Disposition: inline # Bazaar merge directive format 2 (Bazaar 0.90) # revision_id: john.duncan@stripped # target_branch: file:///Users/jdd/bzr-repo/working/cluster-7.2-labs-\ # memcached/ # testament_sha1: 5b1b9539f15d1389b0f5af331ac4f757037bd99b # timestamp: 2011-05-16 21:56:02 -0700 # base_revision_id: john.duncan@stripped\ # 8n3n4e2wdzq2p15p # # Begin bundle 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 f/F3JFOFCQMl1paQ --===============0651389663==--