diff --git a/src/db/db.cc b/src/db/db.cc index 94be50ea7ec..b55bc34405a 100644 --- a/src/db/db.cc +++ b/src/db/db.cc @@ -64,6 +64,10 @@ DBTableBase *DB::FindTable(const string &name) { return NULL; } +DB::iterator DB::FindTableIter(const string &name) { + return tables_.find(name); +} + void DB::AddTable(DBTableBase *tbl_base) { pair result = tables_.insert(make_pair(tbl_base->name(), tbl_base)); diff --git a/src/db/db.h b/src/db/db.h index 74005281809..52c2addd45f 100644 --- a/src/db/db.h +++ b/src/db/db.h @@ -38,6 +38,7 @@ class DB { // Table creation. DBTableBase *CreateTable(const std::string &name); DBTableBase *FindTable(const std::string &name); + iterator FindTableIter(const std::string &name); void RemoveTable(DBTableBase *tbl_base); // Table walker diff --git a/src/db/db_table_partition.cc b/src/db/db_table_partition.cc index 4144aa7d61a..8530ad485ea 100644 --- a/src/db/db_table_partition.cc +++ b/src/db/db_table_partition.cc @@ -144,6 +144,18 @@ DBEntry *DBTablePartition::Find(const DBRequestKey *key) { return NULL; } +DBEntry *DBTablePartition::FindNext(const DBRequestKey *key) { + tbb::mutex::scoped_lock lock(mutex_); + DBTable *table = static_cast(parent()); + std::auto_ptr entry_ptr = table->AllocEntry(key); + + Tree::iterator loc = tree_.upper_bound(*(entry_ptr.get())); + if (loc != tree_.end()) { + return loc.operator->(); + } + return NULL; +} + // Returns the matching entry or next in lex order DBEntry *DBTablePartition::lower_bound(const DBEntryBase *key) { const DBEntry *entry = static_cast(key); diff --git a/src/db/db_table_partition.h b/src/db/db_table_partition.h index 77c8612baf9..dcc3b49e3cb 100644 --- a/src/db/db_table_partition.h +++ b/src/db/db_table_partition.h @@ -77,6 +77,7 @@ class DBTablePartition : public DBTablePartBase { void Process(DBClient *client, DBRequest *req); // Returns the matching route or next in lex order virtual DBEntry *lower_bound(const DBEntryBase *entry); + // Returns the next route (Doesn't search). Threaded walk virtual DBEntry *GetNext(const DBEntryBase *entry); @@ -102,6 +103,9 @@ class DBTablePartition : public DBTablePartBase { // Find DB Entry. Get key from from argument DBEntry *Find(const DBRequestKey *key); + // Find the next in lex order + DBEntry *FindNext(const DBRequestKey *key); + DBTable *table(); size_t size() const { return tree_.size(); } diff --git a/src/ifmap/SConscript b/src/ifmap/SConscript index a69c2faf1dd..e2c3777362b 100644 --- a/src/ifmap/SConscript +++ b/src/ifmap/SConscript @@ -17,6 +17,7 @@ except_env.CppEnableExceptions() except_env.Append(CPPPATH = env['TOP']) SandeshGenFiles = env.SandeshGenCpp('ifmap_server_show.sandesh') +SandeshGenFiles += env.SandeshGenOnlyCpp('ifmap_server_show_internal.sandesh') SandeshGenFiles += env.SandeshGenCpp('ifmap_log.sandesh') SandeshGenSrcs = env.ExtractCpp(SandeshGenFiles) diff --git a/src/ifmap/ifmap_link_table.cc b/src/ifmap/ifmap_link_table.cc index 57da2d29d09..0d63516dbf2 100644 --- a/src/ifmap/ifmap_link_table.cc +++ b/src/ifmap/ifmap_link_table.cc @@ -75,6 +75,15 @@ IFMapLink *IFMapLinkTable::FindLink(const string &name) { return static_cast(partition->Find(&key)); } +IFMapLink *IFMapLinkTable::FindNextLink(const string &name) { + + DBTablePartition *partition = + static_cast(GetTablePartition(0)); + RequestKey key; + key.name = name; + return static_cast(partition->FindNext(&key)); +} + void IFMapLinkTable::DeleteLink(DBGraphEdge *edge) { IFMapLink *link = static_cast(edge); link->set_last_change_at_to_now(); diff --git a/src/ifmap/ifmap_link_table.h b/src/ifmap/ifmap_link_table.h index a4c44e3eb64..efd4f875e29 100644 --- a/src/ifmap/ifmap_link_table.h +++ b/src/ifmap/ifmap_link_table.h @@ -50,6 +50,7 @@ class IFMapLinkTable : public DBTable { static DBTable *CreateTable(DB *db, const std::string &name, DBGraph *graph); IFMapLink *FindLink(const std::string &name); + IFMapLink *FindNextLink(const std::string &name); protected: void DeleteLink(DBGraphEdge *edge); diff --git a/src/ifmap/ifmap_server_show.cc b/src/ifmap/ifmap_server_show.cc index 7c560b62997..cd95cbfa139 100644 --- a/src/ifmap/ifmap_server_show.cc +++ b/src/ifmap/ifmap_server_show.cc @@ -25,6 +25,7 @@ #include "ifmap/ifmap_sandesh_context.h" #include "ifmap/ifmap_server.h" #include "ifmap/ifmap_server_show_types.h" +#include "ifmap/ifmap_server_show_internal_types.h" #include "ifmap/ifmap_log_types.h" #include "ifmap/ifmap_table.h" #include "ifmap/ifmap_update.h" @@ -105,71 +106,111 @@ class IFMapNodeCopier { } }; +const string kShowIterSeparator = "||"; + // almost everything in this class is static since we dont really want to // intantiate this class class ShowIFMapTable { public: - static const int kMaxElementsPerRound = 50; + static const uint32_t kMaxElementsPerRound = 50; struct ShowData : public RequestPipeline::InstData { vector send_buffer; + string next_table_name; + string last_node_name; }; static RequestPipeline::InstData *AllocBuffer(int stage) { return static_cast(new ShowData); } - struct TrackerData : public RequestPipeline::InstData { - // init as 1 indicates we need to init 'first' to begin() since there is - // no way to initialize an iterator here. - TrackerData() : init(1) { } - int init; - vector::const_iterator first; - }; - - static RequestPipeline::InstData *AllocTracker(int stage) { - return static_cast(new TrackerData); - } - + static bool BufferStageCommon(const IFMapTableShowReq *request, + RequestPipeline::InstData *data, + const string &next_table_name, + const string &last_node_name); static bool BufferStage(const Sandesh *sr, const RequestPipeline::PipeSpec ps, int stage, int instNum, RequestPipeline::InstData *data); + static bool BufferStageIterate(const Sandesh *sr, + const RequestPipeline::PipeSpec ps, int stage, + int instNum, RequestPipeline::InstData *data); + static void SendStageCommon(const IFMapTableShowReq *request, + const RequestPipeline::PipeSpec ps, + IFMapTableShowResp *response); static bool SendStage(const Sandesh *sr, const RequestPipeline::PipeSpec ps, int stage, int instNum, RequestPipeline::InstData *data); - static void TableToBuffer(const IFMapTableShowReq *request, IFMapTable *table, - ShowData *show_data, IFMapServer *server); - static bool BufferAllTables(const RequestPipeline::PipeSpec ps, - RequestPipeline::InstData *data); - static bool BufferSomeTables(const RequestPipeline::PipeSpec ps, - RequestPipeline::InstData *data); + static bool SendStageIterate(const Sandesh *sr, + const RequestPipeline::PipeSpec ps, int stage, + int instNum, RequestPipeline::InstData *data); + static bool TableToBuffer(const IFMapTableShowReq *request, + IFMapTable *table, IFMapServer *server, + const string &last_node_name, + ShowData *show_data); + static bool BufferAllTables(const IFMapTableShowReq *req, + RequestPipeline::InstData *data, + const string &next_table_name, + const string &last_node_name); + static bool BufferOneTable(const IFMapTableShowReq *request, + RequestPipeline::InstData *data, + const string &last_node_name); + static bool ConvertReqIterateToReq( + const IFMapTableShowReqIterate *req_iterate, + IFMapTableShowReq *req, string *next_table_name, + string *last_node_name); }; -void ShowIFMapTable::TableToBuffer(const IFMapTableShowReq *request, - IFMapTable *table, ShowData *show_data, IFMapServer *server) { +// Return true if the buffer is full. +bool ShowIFMapTable::TableToBuffer(const IFMapTableShowReq *request, + IFMapTable *table, IFMapServer *server, const string &last_node_name, + ShowData *show_data) { + + DBEntryBase *src = NULL; + if (last_node_name.length()) { + // If the last_node_name is set, it was the last node printed in the + // previous round. Search for the node 'after' last_node_name and start + // this round with it. If there is no next node, we are done with this + // table. + IFMapNode *last_node = table->FindNextNode(last_node_name); + if (last_node) { + src = last_node; + } else { + return false; + } + } + + bool buffer_full = false; string search_string = request->get_search_string(); - for (int i = 0; i < IFMapTable::kPartitionCount; i++) { - DBTablePartBase *partition = table->GetTablePartition(i); - DBEntryBase *src = partition->GetFirst(); - while (src) { - IFMapNode *src_node = static_cast(src); - if (!search_string.empty() && - (src_node->ToString().find(search_string) == string::npos)) { - src = partition->GetNext(src); - continue; - } - IFMapNodeShowInfo dest; - IFMapNodeCopier copyNode(&dest, src, server); - show_data->send_buffer.push_back(dest); - src = partition->GetNext(src); + DBTablePartBase *partition = table->GetTablePartition(0); + if (!src) { + src = partition->GetFirst(); + } + for (; src != NULL; src = partition->GetNext(src)) { + IFMapNode *src_node = static_cast(src); + if (!search_string.empty() && + (src_node->ToString().find(search_string) == string::npos)) { + continue; + } + IFMapNodeShowInfo dest; + IFMapNodeCopier copyNode(&dest, src, server); + show_data->send_buffer.push_back(dest); + // If we have picked up enough nodes for this round... + if (show_data->send_buffer.size() == kMaxElementsPerRound) { + // Save the values needed for the next round. When we come + // back, we will use the 'names' to lookup the elements since + // the 'names' are the keys in the respective tables. + show_data->next_table_name = table->name(); + show_data->last_node_name = src_node->name(); + buffer_full = true; + break; } } + + return buffer_full; } -bool ShowIFMapTable::BufferSomeTables(const RequestPipeline::PipeSpec ps, - RequestPipeline::InstData *data) { - const IFMapTableShowReq *request = - static_cast(ps.snhRequest_.get()); +bool ShowIFMapTable::BufferOneTable(const IFMapTableShowReq *request, + RequestPipeline::InstData *data, const string &last_node_name) { IFMapSandeshContext *sctx = static_cast(request->module_context("IFMap")); @@ -177,8 +218,9 @@ bool ShowIFMapTable::BufferSomeTables(const RequestPipeline::PipeSpec ps, request->get_table_name()); if (table) { ShowData *show_data = static_cast(data); - show_data->send_buffer.reserve(table->Size()); - TableToBuffer(request, table, show_data, sctx->ifmap_server()); + show_data->send_buffer.reserve(kMaxElementsPerRound); + TableToBuffer(request, table, sctx->ifmap_server(), last_node_name, + show_data); } else { IFMAP_WARN(IFMapTblNotFound, "Cant show/find table ", request->get_table_name()); @@ -187,97 +229,192 @@ bool ShowIFMapTable::BufferSomeTables(const RequestPipeline::PipeSpec ps, return true; } -bool ShowIFMapTable::BufferAllTables(const RequestPipeline::PipeSpec ps, - RequestPipeline::InstData *data) { - const IFMapTableShowReq *request = - static_cast(ps.snhRequest_.get()); +bool ShowIFMapTable::BufferAllTables(const IFMapTableShowReq *request, + RequestPipeline::InstData *data, const string &next_table_name, + const string &last_node_name) { IFMapSandeshContext *sctx = static_cast(request->module_context("IFMap")); + string last_name = last_node_name; DB *db = sctx->ifmap_server()->database(); + DB::iterator iter; + if (next_table_name.empty()) { + iter = db->lower_bound("__ifmap__."); + } else { + iter = db->FindTableIter(next_table_name); + } - // Get the sum total of entries in all the tables - int num_entries = 0; - for (DB::iterator iter = db->lower_bound("__ifmap__."); - iter != db->end(); ++iter) { + ShowData *show_data = static_cast(data); + show_data->send_buffer.reserve(kMaxElementsPerRound); + for (; iter != db->end(); ++iter) { if (iter->first.find("__ifmap__.") != 0) { break; } IFMapTable *table = static_cast(iter->second); - num_entries += table->Size(); - } - ShowData *show_data = static_cast(data); - show_data->send_buffer.reserve(num_entries); - for (DB::iterator iter = db->lower_bound("__ifmap__."); - iter != db->end(); ++iter) { - if (iter->first.find("__ifmap__.") != 0) { + bool buffer_full = TableToBuffer(request, table, sctx->ifmap_server(), + last_name, show_data); + if (buffer_full) { break; } - IFMapTable *table = static_cast(iter->second); - TableToBuffer(request, table, show_data, sctx->ifmap_server()); + // last_node_name is only relevant for the first iteration. + last_name.clear(); + } + + return true; +} + +// Format of node_info string: +// table_name||search_string||next_table_name||last_node_name +// table_name/search_string: original input. Could be empty. +// next_table_name: next table to lookup in +// last_node_name: name of last node that was printed in the previous round +bool ShowIFMapTable::ConvertReqIterateToReq( + const IFMapTableShowReqIterate *req_iterate, + IFMapTableShowReq *req, string *next_table_name, + string *last_node_name) { + // First, set the context from the original request since we might return + // due to parsing errors. + req->set_context(req_iterate->context()); + + string node_info = req_iterate->get_node_info(); + size_t sep_size = kShowIterSeparator.size(); + + // table_name + size_t pos1 = node_info.find(kShowIterSeparator); + if (pos1 == string::npos) { + return false; } + string table_name = node_info.substr(0, pos1); + // search_string + size_t pos2 = node_info.find(kShowIterSeparator, (pos1 + sep_size)); + if (pos2 == string::npos) { + return false; + } + string search_string = node_info.substr((pos1 + sep_size), + pos2 - (pos1 + sep_size)); + + // next_table_name + size_t pos3 = node_info.find(kShowIterSeparator, (pos2 + sep_size)); + if (pos3 == string::npos) { + return false; + } + *next_table_name = node_info.substr((pos2 + sep_size), + pos3 - (pos2 + sep_size)); + + // last_node_name + *last_node_name = node_info.substr(pos3 + sep_size); + + // Fill up the fields of IFMapTableShowReq appropriately. + req->set_table_name(table_name); + req->set_search_string(search_string); return true; } +bool ShowIFMapTable::BufferStageCommon(const IFMapTableShowReq *request, + RequestPipeline::InstData *data, const string &next_table_name, + const string &last_node_name) { + // If table name has not been passed, print all tables + if (request->get_table_name().length()) { + return BufferOneTable(request, data, last_node_name); + } else { + return BufferAllTables(request, data, next_table_name, last_node_name); + } +} + bool ShowIFMapTable::BufferStage(const Sandesh *sr, const RequestPipeline::PipeSpec ps, int stage, int instNum, RequestPipeline::InstData *data) { - const IFMapTableShowReq *request = static_cast(ps.snhRequest_.get()); - // If table name has not been passed, print all tables - if (request->get_table_name().length()) { - return BufferSomeTables(ps, data); - } else { - return BufferAllTables(ps, data); + string next_table_name; + string last_node_name; + return BufferStageCommon(request, data, next_table_name, last_node_name); +} + +bool ShowIFMapTable::BufferStageIterate(const Sandesh *sr, + const RequestPipeline::PipeSpec ps, + int stage, int instNum, + RequestPipeline::InstData *data) { + const IFMapTableShowReqIterate *request_iterate = + static_cast(ps.snhRequest_.get()); + + string next_table_name; + string last_node_name; + IFMapTableShowReq *request = new IFMapTableShowReq; + bool success = ConvertReqIterateToReq(request_iterate, request, + &next_table_name, &last_node_name); + if (success) { + BufferStageCommon(request, data, next_table_name, last_node_name); } + request->Release(); + return true; +} + +void ShowIFMapTable::SendStageCommon(const IFMapTableShowReq *request, + const RequestPipeline::PipeSpec ps, + IFMapTableShowResp *response) { + const RequestPipeline::StageData *prev_stage_data = ps.GetStageData(0); + const ShowIFMapTable::ShowData &show_data = + static_cast (prev_stage_data->at(0)); + + vector dest_buffer; + dest_buffer = show_data.send_buffer; + + // If we have filled the buffer, set next_batch with all the values we will + // need in the next round. + string next_batch; + if (dest_buffer.size() == kMaxElementsPerRound) { + next_batch = request->get_table_name() + kShowIterSeparator + + request->get_search_string() + kShowIterSeparator + + show_data.next_table_name + kShowIterSeparator + + show_data.last_node_name; + } + + response->set_ifmap_db(dest_buffer); + response->set_next_batch(next_batch); } -// Can be called multiple times i.e. approx total/kMaxElementsPerRound bool ShowIFMapTable::SendStage(const Sandesh *sr, const RequestPipeline::PipeSpec ps, int stage, int instNum, RequestPipeline::InstData *data) { - const RequestPipeline::StageData *prev_stage_data = ps.GetStageData(0); - const ShowIFMapTable::ShowData &show_data = - static_cast (prev_stage_data->at(0)); - // Data for this stage - TrackerData *tracker_data = static_cast(data); + const IFMapTableShowReq *request = + static_cast(ps.snhRequest_.get()); + IFMapTableShowResp *response = new IFMapTableShowResp; + SendStageCommon(request, ps, response); - vector dest_buffer; - vector::const_iterator first, last; - bool more = false; + response->set_context(request->context()); + response->set_more(false); + response->Response(); + return true; +} - if (tracker_data->init) { - first = show_data.send_buffer.begin(); - tracker_data->init = 0; - } else { - first = tracker_data->first; - } - int rem_num = show_data.send_buffer.end() - first; - int send_num = (rem_num < kMaxElementsPerRound) ? rem_num : - kMaxElementsPerRound; - last = first + send_num; - copy(first, last, back_inserter(dest_buffer)); - // Decide if we want to be called again. - if ((rem_num - send_num) > 0) { - more = true; - } else { - more = false; +bool ShowIFMapTable::SendStageIterate(const Sandesh *sr, + const RequestPipeline::PipeSpec ps, + int stage, int instNum, + RequestPipeline::InstData *data) { + const IFMapTableShowReqIterate *request_iterate = + static_cast(ps.snhRequest_.get()); + + string next_table_name; + string last_node_name; + + IFMapTableShowResp *response = new IFMapTableShowResp; + IFMapTableShowReq *request = new IFMapTableShowReq; + bool success = ConvertReqIterateToReq(request_iterate, request, + &next_table_name, &last_node_name); + if (success) { + SendStageCommon(request, ps, response); } - const IFMapTableShowReq *request = - static_cast(ps.snhRequest_.get()); - IFMapTableShowResp *response = new IFMapTableShowResp(); - response->set_ifmap_db(dest_buffer); + response->set_context(request->context()); - response->set_more(more); + response->set_more(false); response->Response(); - tracker_data->first = first + send_num; - // Return 'false' to be called again - return (!more); + request->Release(); + return true; } void IFMapTableShowReq::HandleRequest() const { @@ -294,7 +431,6 @@ void IFMapTableShowReq::HandleRequest() const { // control-node ifmap show command task s1.taskId_ = scheduler->GetTaskId("cn_ifmap::ShowCommand"); - s1.allocFn_ = ShowIFMapTable::AllocTracker; s1.cbFn_ = ShowIFMapTable::SendStage; s1.instances_.push_back(0); @@ -303,44 +439,73 @@ void IFMapTableShowReq::HandleRequest() const { RequestPipeline rp(ps); } +void IFMapTableShowReqIterate::HandleRequest() const { + + RequestPipeline::StageSpec s0, s1; + TaskScheduler *scheduler = TaskScheduler::GetInstance(); + + // 2 stages - first: gather/read, second: send + + s0.taskId_ = scheduler->GetTaskId("db::DBTable"); + s0.allocFn_ = ShowIFMapTable::AllocBuffer; + s0.cbFn_ = ShowIFMapTable::BufferStageIterate; + s0.instances_.push_back(0); + + // control-node ifmap show command task + s1.taskId_ = scheduler->GetTaskId("cn_ifmap::ShowCommand"); + s1.cbFn_ = ShowIFMapTable::SendStageIterate; + s1.instances_.push_back(0); + + RequestPipeline::PipeSpec ps(this); + ps.stages_= list_of(s0)(s1); + RequestPipeline rp(ps); +} + // Code to display link-table entries class ShowIFMapLinkTable { public: - static const int kMaxElementsPerRound = 50; + static const uint32_t kMaxElementsPerRound = 50; struct ShowData : public RequestPipeline::InstData { vector send_buffer; + uint32_t table_size; + string last_link_name; }; static RequestPipeline::InstData *AllocBuffer(int stage) { return static_cast(new ShowData); } - struct TrackerData : public RequestPipeline::InstData { - // init as 1 indicates we need to init 'first' to begin() since there is - // no way to initialize an iterator here. - TrackerData() : init(1) { } - int init; - vector::const_iterator first; - }; - - static RequestPipeline::InstData *AllocTracker(int stage) { - return static_cast(new TrackerData); - } - static bool SkipLink(DBEntryBase *src, const string &search_string); static void CopyNode(IFMapLinkShowInfo *dest, DBEntryBase *src, IFMapServer *server); + static bool BufferStageCommon(const IFMapLinkTableShowReq *request, + RequestPipeline::InstData *data, + const string &last_link_name); static bool BufferStage(const Sandesh *sr, const RequestPipeline::PipeSpec ps, int stage, int instNum, RequestPipeline::InstData *data); + static bool BufferStageIterate(const Sandesh *sr, + const RequestPipeline::PipeSpec ps, + int stage, int instNum, + RequestPipeline::InstData *data); + static void SendStageCommon(const IFMapLinkTableShowReq *request, + const RequestPipeline::PipeSpec ps, + IFMapLinkTableShowResp *response); static bool SendStage(const Sandesh *sr, const RequestPipeline::PipeSpec ps, int stage, int instNum, RequestPipeline::InstData *data); + static bool SendStageIterate(const Sandesh *sr, + const RequestPipeline::PipeSpec ps, int stage, + int instNum, RequestPipeline::InstData *data); + static bool ConvertReqIterateToReq( + const IFMapLinkTableShowReqIterate *req_iterate, + IFMapLinkTableShowReq *req, string *last_link_name); }; -bool ShowIFMapLinkTable::SkipLink(DBEntryBase *src, const string &search_string) { +bool ShowIFMapLinkTable::SkipLink(DBEntryBase *src, + const string &search_string) { IFMapLink *link = static_cast(src); IFMapNode *left = link->left(); IFMapNode *right = link->right(); @@ -399,85 +564,168 @@ void ShowIFMapLinkTable::CopyNode(IFMapLinkShowInfo *dest, DBEntryBase *src, } } -bool ShowIFMapLinkTable::BufferStage(const Sandesh *sr, - const RequestPipeline::PipeSpec ps, - int stage, int instNum, - RequestPipeline::InstData *data) { - const IFMapLinkTableShowReq *request = - static_cast(ps.snhRequest_.get()); - IFMapSandeshContext *sctx = +// Format of link_info string: +// search_string||last_link_name +// search_string: original input. Could be empty. +// last_link_name: name of last link that was printed in the previous round +bool ShowIFMapLinkTable::ConvertReqIterateToReq( + const IFMapLinkTableShowReqIterate *req_iterate, + IFMapLinkTableShowReq *req, string *last_link_name) { + // First, set the context from the original request since we might return + // due to parsing errors. + req->set_context(req_iterate->context()); + + string link_info = req_iterate->get_link_info(); + size_t sep_size = kShowIterSeparator.size(); + + // search_string + size_t pos1 = link_info.find(kShowIterSeparator); + if (pos1 == string::npos) { + return false; + } + string search_string = link_info.substr(0, pos1); + + // last_link_name + *last_link_name = link_info.substr(pos1 + sep_size); + + // Fill up the fields of IFMapLinkTableShowReq appropriately. + req->set_search_string(search_string); + return true; +} + +bool ShowIFMapLinkTable::BufferStageCommon(const IFMapLinkTableShowReq *request, + RequestPipeline::InstData *data, + const string &last_link_name) { + bool buffer_full = false; + IFMapSandeshContext *sctx = static_cast(request->module_context("IFMap")); IFMapLinkTable *table = static_cast( sctx->ifmap_server()->database()->FindTable("__ifmap_metadata__.0")); if (table) { ShowData *show_data = static_cast(data); - show_data->send_buffer.reserve(table->Size()); + show_data->send_buffer.reserve(kMaxElementsPerRound); + show_data->table_size = table->Size(); + DBEntryBase *src = NULL; DBTablePartBase *partition = table->GetTablePartition(0); - DBEntryBase *src = partition->GetFirst(); - while (src) { + if (last_link_name.length()) { + src = table->FindNextLink(last_link_name); + } else { + src = partition->GetFirst(); + } + for (; src != NULL; src = partition->GetNext(src)) { + IFMapLink *src_link = static_cast(src); if (SkipLink(src, request->get_search_string())) { - src = partition->GetNext(src); continue; } IFMapLinkShowInfo dest; CopyNode(&dest, src, sctx->ifmap_server()); show_data->send_buffer.push_back(dest); - src = partition->GetNext(src); + // If we have picked up enough links for this round... + if (show_data->send_buffer.size() == kMaxElementsPerRound) { + show_data->last_link_name = src_link->link_name(); + buffer_full = true; + break; + } } } else { IFMAP_WARN(IFMapTblNotFound, "Cant show/find ", "link table"); } + return buffer_full; +} + +bool ShowIFMapLinkTable::BufferStage(const Sandesh *sr, + const RequestPipeline::PipeSpec ps, + int stage, int instNum, + RequestPipeline::InstData *data) { + const IFMapLinkTableShowReq *request = + static_cast(ps.snhRequest_.get()); + string last_link_name; + BufferStageCommon(request, data, last_link_name); return true; } -// Can be called multiple times i.e. approx total/kMaxElementsPerRound -bool ShowIFMapLinkTable::SendStage(const Sandesh *sr, - const RequestPipeline::PipeSpec ps, - int stage, int instNum, - RequestPipeline::InstData *data) { +bool ShowIFMapLinkTable::BufferStageIterate(const Sandesh *sr, + const RequestPipeline::PipeSpec ps, + int stage, int instNum, + RequestPipeline::InstData *data) { + const IFMapLinkTableShowReqIterate *request_iterate = + static_cast(ps.snhRequest_.get()); + + IFMapLinkTableShowReq *request = new IFMapLinkTableShowReq; + string last_link_name; + bool success = ConvertReqIterateToReq(request_iterate, request, + &last_link_name); + if (success) { + BufferStageCommon(request, data, last_link_name); + } + request->Release(); + return true; +} + +void ShowIFMapLinkTable::SendStageCommon(const IFMapLinkTableShowReq *request, + const RequestPipeline::PipeSpec ps, + IFMapLinkTableShowResp *response) { const RequestPipeline::StageData *prev_stage_data = ps.GetStageData(0); const ShowIFMapLinkTable::ShowData &show_data = static_cast (prev_stage_data->at(0)); - // Data for this stage - TrackerData *tracker_data = static_cast(data); - vector dest_buffer; - vector::const_iterator first, last; - bool more = false; - - if (tracker_data->init) { - first = show_data.send_buffer.begin(); - tracker_data->init = 0; - } else { - first = tracker_data->first; - } - int rem_num = show_data.send_buffer.end() - first; - int send_num = (rem_num < kMaxElementsPerRound) ? rem_num : - kMaxElementsPerRound; - last = first + send_num; - copy(first, last, back_inserter(dest_buffer)); - // Decide if we want to be called again. - if ((rem_num - send_num) > 0) { - more = true; - } else { - more = false; + dest_buffer = show_data.send_buffer; + + // If we have filled the buffer, set next_batch with all the values we will + // need in the next round. + string next_batch; + if (dest_buffer.size() == kMaxElementsPerRound) { + next_batch = request->get_search_string() + kShowIterSeparator + + show_data.last_link_name; } + + response->set_table_size(show_data.table_size); + response->set_ifmap_db(dest_buffer); + response->set_next_batch(next_batch); +} + +bool ShowIFMapLinkTable::SendStage(const Sandesh *sr, + const RequestPipeline::PipeSpec ps, + int stage, int instNum, + RequestPipeline::InstData *data) { const IFMapLinkTableShowReq *request = static_cast(ps.snhRequest_.get()); - IFMapLinkTableShowResp *response = new IFMapLinkTableShowResp(); - response->set_ifmap_db(dest_buffer); + IFMapLinkTableShowResp *response = new IFMapLinkTableShowResp; + SendStageCommon(request, ps, response); + response->set_context(request->context()); - response->set_more(more); + response->set_more(false); response->Response(); - tracker_data->first = first + send_num; + return true; +} - // Return 'false' to be called again - return (!more); +bool ShowIFMapLinkTable::SendStageIterate(const Sandesh *sr, + const RequestPipeline::PipeSpec ps, + int stage, int instNum, + RequestPipeline::InstData *data) { + const IFMapLinkTableShowReqIterate *request_iterate = + static_cast(ps.snhRequest_.get()); + + IFMapLinkTableShowResp *response = new IFMapLinkTableShowResp; + IFMapLinkTableShowReq *request = new IFMapLinkTableShowReq; + string last_link_name; + bool success = ConvertReqIterateToReq(request_iterate, request, + &last_link_name); + if (success) { + SendStageCommon(request, ps, response); + } + + response->set_context(request->context()); + response->set_more(false); + response->Response(); + + request->Release(); + return true; } void IFMapLinkTableShowReq::HandleRequest() const { @@ -494,7 +742,6 @@ void IFMapLinkTableShowReq::HandleRequest() const { // control-node ifmap show command task s1.taskId_ = scheduler->GetTaskId("cn_ifmap::ShowCommand"); - s1.allocFn_ = ShowIFMapLinkTable::AllocTracker; s1.cbFn_ = ShowIFMapLinkTable::SendStage; s1.instances_.push_back(0); @@ -503,6 +750,28 @@ void IFMapLinkTableShowReq::HandleRequest() const { RequestPipeline rp(ps); } +void IFMapLinkTableShowReqIterate::HandleRequest() const { + + RequestPipeline::StageSpec s0, s1; + TaskScheduler *scheduler = TaskScheduler::GetInstance(); + + // 2 stages - first: gather/read, second: send + + s0.taskId_ = scheduler->GetTaskId("db::DBTable"); + s0.allocFn_ = ShowIFMapLinkTable::AllocBuffer; + s0.cbFn_ = ShowIFMapLinkTable::BufferStageIterate; + s0.instances_.push_back(0); + + // control-node ifmap show command task + s1.taskId_ = scheduler->GetTaskId("cn_ifmap::ShowCommand"); + s1.cbFn_ = ShowIFMapLinkTable::SendStageIterate; + s1.instances_.push_back(0); + + RequestPipeline::PipeSpec ps(this); + ps.stages_= list_of(s0)(s1); + RequestPipeline rp(ps); +} + static bool IFMapNodeShowReqHandleRequest(const Sandesh *sr, const RequestPipeline::PipeSpec ps, int stage, int instNum, diff --git a/src/ifmap/ifmap_server_show.sandesh b/src/ifmap/ifmap_server_show.sandesh index 6a2ef10f197..f54720c7ac6 100644 --- a/src/ifmap/ifmap_server_show.sandesh +++ b/src/ifmap/ifmap_server_show.sandesh @@ -28,6 +28,8 @@ request sandesh IFMapTableShowReq { response sandesh IFMapTableShowResp { 1: list ifmap_db; + 2: optional string next_batch (link="IFMapTableShowReqIterate", + link_title="next_batch"); } /** Definitions for showing link table - IFMapLink **/ @@ -54,7 +56,10 @@ request sandesh IFMapLinkTableShowReq { } response sandesh IFMapLinkTableShowResp { - 1: list ifmap_db; + 1: u32 table_size; + 2: list ifmap_db; + 3: optional string next_batch (link="IFMapLinkTableShowReqIterate", + link_title="next_batch"); } /** Definitions for showing the internal Update Queue **/ diff --git a/src/ifmap/ifmap_server_show_internal.sandesh b/src/ifmap/ifmap_server_show_internal.sandesh new file mode 100644 index 00000000000..93e521817dc --- /dev/null +++ b/src/ifmap/ifmap_server_show_internal.sandesh @@ -0,0 +1,12 @@ +/* + * Copyright (c) 2015 Juniper Networks, Inc. All rights reserved. + */ + +request sandesh IFMapTableShowReqIterate { + 1: string node_info; +} + +request sandesh IFMapLinkTableShowReqIterate { + 1: string link_info; +} + diff --git a/src/ifmap/ifmap_table.cc b/src/ifmap/ifmap_table.cc index c0fc2b059fa..7150cb4b525 100644 --- a/src/ifmap/ifmap_table.cc +++ b/src/ifmap/ifmap_table.cc @@ -11,6 +11,7 @@ #include #include "db/db.h" #include "db/db_table.h" +#include "db/db_table_partition.h" #include "ifmap/autogen.h" #include "ifmap/ifmap_node.h" #include "ifmap/ifmap_server_show_types.h" @@ -21,10 +22,19 @@ IFMapTable::IFMapTable(DB *db, const std::string &name) : DBTable(db, name) { } IFMapNode *IFMapTable::FindNode(const std::string &name) { + DBTablePartition *partition = + static_cast(GetTablePartition(0)); IFMapTable::RequestKey reqkey; reqkey.id_name = name; - auto_ptr key(AllocEntry(&reqkey)); - return static_cast(Find(key.get())); + return static_cast(partition->Find(&reqkey)); +} + +IFMapNode *IFMapTable::FindNextNode(const std::string &name) { + DBTablePartition *partition = + static_cast(GetTablePartition(0)); + IFMapTable::RequestKey reqkey; + reqkey.id_name = name; + return static_cast(partition->FindNext(&reqkey)); } IFMapTable *IFMapTable::FindTable(DB *db, const std::string &element_type) { diff --git a/src/ifmap/ifmap_table.h b/src/ifmap/ifmap_table.h index f2cc36a933b..3968465ff8f 100644 --- a/src/ifmap/ifmap_table.h +++ b/src/ifmap/ifmap_table.h @@ -32,6 +32,7 @@ class IFMapTable : public DBTable { virtual IFMapObject *AllocObject() = 0; IFMapNode *FindNode(const std::string &name); + IFMapNode *FindNextNode(const std::string &name); virtual void Clear() = 0;