Line data Source code
1 : /*
2 : * Copyright (c) 2013 Juniper Networks, Inc. All rights reserved.
3 : */
4 :
5 : #include "ifmap/ifmap_exporter.h"
6 :
7 : #include <boost/bind/bind.hpp>
8 : #include <boost/checked_delete.hpp>
9 :
10 : #include "db/db.h"
11 : #include "db/db_table_partition.h"
12 : #include "ifmap/ifmap_client.h"
13 : #include "ifmap/ifmap_graph_walker.h"
14 : #include "ifmap/ifmap_link.h"
15 : #include "ifmap/ifmap_log.h"
16 : #include "ifmap/ifmap_server.h"
17 : #include "ifmap/ifmap_log_types.h"
18 : #include "ifmap/ifmap_table.h"
19 : #include "ifmap/ifmap_update.h"
20 : #include "ifmap/ifmap_update_queue.h"
21 : #include "ifmap/ifmap_update_sender.h"
22 : #include "ifmap/ifmap_util.h"
23 :
24 : using namespace std;
25 : using namespace boost::algorithm;
26 : using namespace boost::placeholders;
27 :
28 : class IFMapExporter::TableInfo {
29 : public:
30 7924 : TableInfo(DBTable::ListenerId id)
31 7924 : : id_(id) {
32 7924 : }
33 39870 : DBTableBase::ListenerId id() const { return id_; }
34 :
35 : private:
36 : DBTableBase::ListenerId id_;
37 : };
38 :
39 179 : IFMapExporter::IFMapExporter(IFMapServer *server)
40 537 : : server_(server), link_table_(NULL) {
41 179 : }
42 :
43 537 : IFMapExporter::~IFMapExporter() {
44 179 : Shutdown();
45 895 : }
46 :
47 53 : void IFMapExporter::Initialize(DB *db) {
48 53 : for (DB::iterator iter = db->lower_bound("__ifmap__");
49 7924 : iter != db->end(); ++iter) {
50 7924 : DBTable *table = static_cast<DBTable *>(iter->second);
51 7924 : if (table->name().find("__ifmap__") != 0) {
52 53 : break;
53 : }
54 : DBTable::ListenerId id =
55 7871 : table->Register(
56 : boost::bind(&IFMapExporter::NodeTableExport, this, _1, _2));
57 7871 : table_map_.insert(make_pair(table, new TableInfo(id)));
58 : }
59 :
60 53 : link_table_ = static_cast<DBTable *>(
61 53 : db->FindTable("__ifmap_metadata__.0"));
62 53 : assert(link_table_);
63 : DBTable::ListenerId id =
64 53 : link_table_->Register(
65 : boost::bind(&IFMapExporter::LinkTableExport, this, _1, _2));
66 53 : table_map_.insert(make_pair(link_table_, new TableInfo(id)));
67 :
68 53 : walker_.reset(new IFMapGraphWalker(server_->graph(), this));
69 53 : }
70 :
71 338 : void IFMapExporter::Shutdown() {
72 1014 : for (int i = 0; i < TT_END; ++i) {
73 964 : for (size_t index = 0; index < client_config_tracker_[i].size(); ++index) {
74 288 : ConfigSet *set = client_config_tracker_[i][index];
75 288 : if (set) {
76 136 : set->clear();
77 136 : delete set;
78 136 : client_config_tracker_[i][index] = NULL;
79 : }
80 : }
81 : }
82 8262 : for (TableMap::iterator iter = table_map_.begin(); iter != table_map_.end();
83 7924 : ++iter) {
84 7924 : DBTable *table = iter->first;
85 7924 : TableInfo *info = iter->second;
86 7924 : table->Unregister(info->id());
87 7924 : TableStateClear(table, info->id());
88 7924 : delete info;
89 : }
90 338 : table_map_.clear();
91 338 : }
92 :
93 18929 : const IFMapExporter::TableInfo *IFMapExporter::Find(
94 : const DBTable *table) const {
95 : TableMap::const_iterator loc =
96 18929 : table_map_.find(const_cast<DBTable *>(table));
97 18929 : if (loc != table_map_.end()) {
98 18929 : return loc->second;
99 : }
100 0 : return NULL;
101 : }
102 :
103 1745 : DBTableBase::ListenerId IFMapExporter::TableListenerId(
104 : const DBTable *table) const {
105 1745 : const IFMapExporter::TableInfo *tinfo = Find(table);
106 1745 : if (tinfo == NULL) {
107 0 : return DBTableBase::kInvalidId;
108 : }
109 1745 : return tinfo->id();
110 : }
111 :
112 10527 : bool IFMapExporter::IsFeasible(const IFMapNode *node) {
113 10527 : if (node->IsDeleted()) {
114 55 : return false;
115 : }
116 10472 : return true;
117 : }
118 :
119 6900 : const BitSet *IFMapExporter::MergeClientInterest(
120 : IFMapNode * node, IFMapNodeState *state, std::unique_ptr<BitSet> *ptr) {
121 :
122 6900 : const BitSet *set = &state->interest();
123 6900 : IFMapTable *table = node->table();
124 :
125 6900 : if (table->name() == "__ifmap__.virtual_router.0") {
126 172 : IFMapClient *client = server_->FindClient(node->name());
127 172 : if (!client) {
128 42 : return set;
129 : }
130 130 : BitSet *merged_set = new BitSet(*set);
131 130 : merged_set->set(client->index());
132 130 : ptr->reset(merged_set);
133 130 : StateInterestSet(state, *merged_set);
134 130 : return merged_set;
135 : }
136 :
137 6728 : return set;
138 : }
139 :
140 3776 : IFMapNodeState *IFMapExporter::NodeStateLookup(IFMapNode *node){
141 3776 : const TableInfo *tinfo = Find(node->table());
142 : IFMapNodeState *state = static_cast<IFMapNodeState *>(
143 3776 : node->GetState(node->table(), tinfo ? tinfo->id() : 0));
144 3776 : return state;
145 : }
146 :
147 5941 : IFMapNodeState *IFMapExporter::NodeStateLocate(IFMapNode *node){
148 5941 : const TableInfo *tinfo = Find(node->table());
149 : IFMapNodeState *state = static_cast<IFMapNodeState *>(
150 5941 : node->GetState(node->table(), tinfo->id()));
151 5941 : if (state == NULL) {
152 1733 : state = new IFMapNodeState(node);
153 1733 : node->SetState(node->table(), tinfo->id(), state);
154 : }
155 5941 : return state;
156 : }
157 :
158 9584 : IFMapUpdateQueue *IFMapExporter::queue() {
159 9584 : return server_->queue();
160 : }
161 :
162 1430 : IFMapUpdateSender *IFMapExporter::sender() {
163 1430 : return server_->sender();
164 : }
165 :
166 : template <class ObjectType>
167 7022 : bool IFMapExporter::UpdateAddChange(ObjectType *obj, IFMapState *state,
168 : const BitSet &add_set, const BitSet &rm_set,
169 : bool change) {
170 : // Remove any bit in "advertise" from the positive update.
171 : // This is a NOP in case the interest set is non empty and this is change.
172 7022 : IFMapUpdate *update = state->GetUpdate(IFMapListEntry::UPDATE);
173 7022 : if (update != NULL) {
174 582 : update->AdvertiseReset(rm_set);
175 : }
176 :
177 7022 : if (state->interest().empty()) {
178 5260 : if (update != NULL) {
179 14 : queue()->Dequeue(update);
180 14 : state->Remove(update);
181 14 : delete update;
182 : }
183 5260 : return false;
184 : }
185 :
186 1762 : if (!change && add_set.empty()) {
187 84 : return false;
188 : }
189 :
190 1678 : bool is_move = false;
191 1678 : if (update != NULL) {
192 568 : if (!change) {
193 568 : if (update->advertise().Contains(add_set)) {
194 508 : return false;
195 : }
196 : } else {
197 0 : if (state->interest() == update->advertise()) {
198 0 : return false;
199 : }
200 : }
201 60 : is_move = true;
202 60 : queue()->Dequeue(update);
203 : } else {
204 1110 : update = new IFMapUpdate(obj, true);
205 1110 : state->Insert(update);
206 : }
207 :
208 1170 : if (!change) {
209 1162 : update->AdvertiseOr(add_set);
210 : } else {
211 8 : update->SetAdvertise(state->interest());
212 : }
213 1170 : queue()->Enqueue(update);
214 1170 : sender()->QueueActive();
215 1170 : return is_move;
216 : }
217 :
218 : template <class ObjectType>
219 7022 : bool IFMapExporter::UpdateRemove(ObjectType *obj, IFMapState *state,
220 : const BitSet &rm_set) {
221 : // Remove any bit in "interest" from the delete update.
222 7022 : IFMapUpdate *update = state->GetUpdate(IFMapListEntry::DEL);
223 7022 : if (update != NULL) {
224 189 : update->AdvertiseReset(state->interest());
225 : }
226 :
227 7022 : if (rm_set.empty()) {
228 6757 : if (update != NULL) {
229 28 : queue()->Dequeue(update);
230 28 : state->Remove(update);
231 28 : delete update;
232 : }
233 6757 : return false;
234 : }
235 :
236 265 : bool is_move = false;
237 265 : if (update != NULL) {
238 161 : if (rm_set == update->advertise()) {
239 141 : return false;
240 : }
241 20 : is_move = true;
242 20 : queue()->Dequeue(update);
243 : } else {
244 104 : update = new IFMapUpdate(obj, false);
245 104 : state->Insert(update);
246 : }
247 :
248 124 : update->SetAdvertise(rm_set);
249 124 : queue()->Enqueue(update);
250 124 : sender()->QueueActive();
251 124 : return is_move;
252 : }
253 :
254 : template <class ObjectType>
255 102 : void IFMapExporter::EnqueueDelete(ObjectType *obj, IFMapState *state) {
256 102 : IFMapUpdate *update = state->GetUpdate(IFMapListEntry::UPDATE);
257 102 : if (update != NULL) {
258 4 : queue()->Dequeue(update);
259 4 : state->Remove(update);
260 4 : delete update;
261 : }
262 :
263 102 : update = state->GetUpdate(IFMapListEntry::DEL);
264 102 : if (update != NULL) {
265 0 : queue()->Dequeue(update);
266 : }
267 102 : if (state->advertised().empty()) {
268 70 : assert(update == NULL);
269 70 : return;
270 : }
271 :
272 32 : if (update == NULL) {
273 32 : update = new IFMapUpdate(obj, false);
274 32 : state->Insert(update);
275 : }
276 32 : update->SetAdvertise(state->advertised());
277 32 : queue()->Enqueue(update);
278 32 : sender()->QueueActive();
279 : }
280 :
281 338 : IFMapLinkState *IFMapExporter::LinkStateLookup(IFMapLink *link) {
282 338 : const TableInfo *tinfo = Find(link_table_);
283 338 : if (!tinfo)
284 0 : return NULL;
285 : IFMapLinkState *state = static_cast<IFMapLinkState *>(
286 338 : link->GetState(link_table_, tinfo->id()));
287 338 : return state;
288 : }
289 :
290 54 : void IFMapExporter::MoveDependentLinks(IFMapNodeState *state) {
291 216 : for (IFMapNodeState::iterator iter = state->begin(); iter != state->end();
292 162 : ++iter) {
293 162 : IFMapLink *link = iter.operator->();
294 162 : IFMapLinkState *ls = LinkStateLookup(link);
295 162 : if (ls == NULL) {
296 0 : continue;
297 : }
298 162 : IFMapUpdate *update = ls->GetUpdate(IFMapListEntry::UPDATE);
299 162 : if (update == NULL) {
300 70 : continue;
301 : }
302 92 : assert(!update->advertise().empty());
303 92 : queue()->Dequeue(update);
304 92 : queue()->Enqueue(update);
305 92 : sender()->QueueActive();
306 : }
307 54 : }
308 :
309 12 : void IFMapExporter::MoveAdjacentNode(IFMapNodeState *state) {
310 12 : IFMapUpdate *update = state->GetUpdate(IFMapListEntry::DEL);
311 12 : if (update != NULL) {
312 12 : assert(!update->advertise().empty());
313 12 : queue()->Dequeue(update);
314 12 : queue()->Enqueue(update);
315 12 : sender()->QueueActive();
316 : }
317 12 : }
318 :
319 74 : void IFMapExporter::RemoveDependentLinks(IFMapNodeState *state,
320 : const BitSet &rm_set) {
321 74 : for (IFMapNodeState::iterator iter = state->begin(), next = state->begin();
322 246 : iter != state->end(); iter = next) {
323 172 : IFMapLink *link = iter.operator->();
324 172 : next = ++iter;
325 172 : IFMapLinkState *ls = LinkStateLookup(link);
326 172 : if (ls == NULL) {
327 0 : continue;
328 : }
329 172 : BitSet common = ls->advertised() & rm_set;
330 172 : if (!common.empty()) {
331 123 : LinkTableExport(link->get_table_partition(), link);
332 : }
333 172 : }
334 74 : }
335 :
336 1164 : void IFMapExporter::ProcessAdjacentNode(IFMapNode *node, const BitSet &add_set,
337 : IFMapNodeState *state, bool force_process) {
338 1164 : BitSet current = state->advertised();
339 1164 : IFMapUpdate *update = state->GetUpdate(IFMapListEntry::UPDATE);
340 1164 : if (update) {
341 614 : current |= update->advertise();
342 : }
343 1164 : if (!current.Contains(add_set)) {
344 546 : NodeTableExport(node->get_table_partition(), node);
345 : } else {
346 618 : if (force_process) {
347 54 : if (update) {
348 40 : update->AdvertiseReset(update->advertise());
349 : }
350 54 : state->AdvertisedReset(state->advertised());
351 54 : NodeTableExport(node->get_table_partition(), node);
352 : }
353 : }
354 1164 : }
355 :
356 160 : void IFMapExporter::DeleteStateIfAppropriate(DBTable *table, DBEntryBase *entry,
357 : IFMapState *state) {
358 160 : if (state->CanDelete()) {
359 92 : assert(state->advertised().empty());
360 92 : assert(state->interest().empty());
361 92 : entry->ClearState(table, TableListenerId(table));
362 92 : delete state;
363 : }
364 160 : }
365 :
366 : // Propagate changes to all the interested peers.
367 : //
368 : // Update order:
369 : // link updates (adds) should only be advertised after the corresponding nodes
370 : // are advertised.
371 : // node membership removal (deletes) should only be advertised after all the
372 : // refering links are removed.
373 : // When enqueuing a link add, the code forces node processing of adjacent links
374 : // before the link update is added to the queue.
375 : // When enqueueing a node removal, the corresponding link removals are placed
376 : // in the queue before the node.
377 : // When a node update moves, any dependent (positive) link update moves also.
378 : // When a (negative) link update moves the corresponding node removals move
379 : // also.
380 3627 : void IFMapExporter::NodeTableExport(DBTablePartBase *partition,
381 : DBEntryBase *entry) {
382 3627 : IFMapNode *node = static_cast<IFMapNode *>(entry);
383 3627 : DBTable *table = static_cast<DBTablePartition *>(partition)->table();
384 :
385 3627 : const TableInfo *tinfo = Find(table);
386 3627 : DBState *entry_state = entry->GetState(table, tinfo->id());
387 3627 : IFMapNodeState *state = static_cast<IFMapNodeState *>(entry_state);
388 :
389 3627 : if (IsFeasible(node)) {
390 3572 : if (state == NULL) {
391 647 : state = new IFMapNodeState(node);
392 647 : entry->SetState(table, tinfo->id(), state);
393 : }
394 3572 : state->SetValid(node);
395 :
396 : // This is an add operation for nodes that are interested and
397 : // have not seen the advertisement.
398 3572 : BitSet add_set;
399 3572 : add_set.BuildComplement(state->interest(), state->advertised());
400 :
401 : // This is a delete operation for nodes that have seen it but are no
402 : // longer interested.
403 3572 : BitSet rm_set;
404 3572 : rm_set.BuildComplement(state->advertised(), state->interest());
405 :
406 3572 : bool change = ConfigChanged(node);
407 :
408 : // enqueue update
409 : // If there is a previous update in the queue, if that update has
410 : // been seen by any of receivers, we need to move the update to
411 : // the tail of the list. When that happens, dependent updates
412 : // moved also.
413 3572 : bool move = UpdateAddChange(node, state, add_set, rm_set, change);
414 3572 : if (move) {
415 54 : MoveDependentLinks(state);
416 : }
417 :
418 : // For the subset of clients being removed, make sure that all
419 : // dependent links are removed before.
420 3572 : if (!rm_set.empty()) {
421 74 : RemoveDependentLinks(state, rm_set);
422 : }
423 3572 : UpdateRemove(node, state, rm_set);
424 3627 : } else if (state != NULL) {
425 : // Link deletes must preceed node deletes.
426 55 : ConfigChanged(node);
427 55 : state->ClearValid();
428 55 : if (!state->HasDependents()) {
429 : // enqueue delete.
430 50 : StateInterestReset(state, state->interest());
431 50 : EnqueueDelete(node, state);
432 50 : if (state->update_list().empty()) {
433 37 : DeleteStateIfAppropriate(table, entry, state);
434 : }
435 : }
436 : }
437 3627 : }
438 :
439 104 : static void MaybeNotifyOnLinkDelete(IFMapNode *node, IFMapNodeState *state) {
440 104 : if (node->IsDeleted() && !state->HasDependents()) {
441 50 : IFMapTable *table = node->table();
442 50 : table->Change(node);
443 : }
444 104 : }
445 :
446 : // When a link is created or deleted this may affect the interest graph for
447 : // the agents.
448 : // Link changes should only be propagated after the respective nodes are
449 : // feasible.
450 3502 : void IFMapExporter::LinkTableExport(DBTablePartBase *partition,
451 : DBEntryBase *entry) {
452 3502 : IFMapLink *link = static_cast<IFMapLink *>(entry);
453 3502 : DBTable *table = static_cast<DBTablePartition *>(partition)->table();
454 3502 : const TableInfo *tinfo = Find(table);
455 3502 : DBState *entry_state = entry->GetState(table, tinfo->id());
456 3502 : IFMapLinkState *state = static_cast<IFMapLinkState *>(entry_state);
457 :
458 3502 : if (!entry->IsDeleted()) {
459 3450 : IFMapNodeState *s_left = NULL;
460 3450 : IFMapNodeState *s_right = NULL;
461 :
462 3450 : bool add_link = false;
463 3450 : bool force_update = false;
464 3450 : if (state == NULL) {
465 2713 : state = new IFMapLinkState(link);
466 2713 : entry->SetState(table, tinfo->id(), state);
467 2713 : s_left = NodeStateLocate(link->left());
468 2713 : s_right = NodeStateLocate(link->right());
469 2713 : add_link = true;
470 : // This is special as internally generated
471 : // We can end up in this situation where add comes just after
472 : // delete but processing of delete happens just before
473 : // Delete for link comes and link is marked for deletion
474 : // Delete event gets picked up, state gets deleted and delete
475 : // event is raised to send updates
476 : // Add event comes in and revives the link since it is only
477 : // marked for deletion, add event is enqueued
478 : // Send update gets picked up but CleanupInterest does not
479 : // do anything because old interest is same as new one
480 : // Add event gets picked up but state was deleted earlier
481 : // This is a corner case and should not happen for other
482 : // config based events
483 5552 : if (starts_with(link->left()->ToString(), "virtual-router") &&
484 2839 : (starts_with(link->right()->ToString(), "virtual-machine:"))) {
485 86 : if (!s_right->advertised().empty())
486 0 : s_right->AdvertisedReset(s_right->advertised());
487 86 : force_update = true;
488 : }
489 : } else {
490 737 : if (state->IsValid() && !link->link_revival()) {
491 : // Link change
492 733 : assert(state->HasDependency());
493 733 : s_left = state->left();
494 733 : s_right = state->right();
495 4 : } else if (state->IsValid() && link->link_revival()) {
496 1 : link->SetLinkRevival(false);
497 1 : assert(state->HasDependency());
498 1 : s_left = state->left();
499 1 : s_right = state->right();
500 1 : force_update = true;
501 1 : state->AdvertisedReset(state->advertised());
502 1 : if (s_left->advertised().Contains(state->interest()))
503 1 : s_left->AdvertisedReset(state->interest());
504 1 : if (s_right->advertised().Contains(state->interest()))
505 1 : s_right->AdvertisedReset(state->interest());
506 : } else {
507 : // Link revival i.e. delete quickly followed by add
508 3 : assert(!state->HasDependency());
509 3 : s_left = NodeStateLocate(link->left());
510 3 : s_right = NodeStateLocate(link->right());
511 3 : add_link = true;
512 3 : force_update = true;
513 3 : state->AdvertisedReset(state->advertised());
514 3 : link->SetLinkRevival(false);
515 3 : if (s_left->advertised().Contains(state->interest()))
516 3 : s_left->AdvertisedReset(state->interest());
517 3 : if (s_right->advertised().Contains(state->interest()))
518 3 : s_right->AdvertisedReset(state->interest());
519 : }
520 : }
521 :
522 : // If one of the nodes is a vswitch node, then the interest mask
523 : // is the corresponding peer bit.
524 3450 : std::unique_ptr<BitSet> ml, mr;
525 3450 : const BitSet *lset = MergeClientInterest(link->left(), s_left, &ml);
526 3450 : const BitSet *rset = MergeClientInterest(link->right(), s_right, &mr);
527 3450 : if (*lset != *rset) {
528 244 : walker_->LinkAdd(link, link->left(), *lset, link->right(), *rset);
529 : }
530 :
531 3450 : if (add_link) {
532 : // Establish dependency.
533 2716 : state->SetDependency(s_left, s_right);
534 2716 : state->SetValid();
535 : }
536 :
537 3450 : if (IsFeasible(link->left()) && IsFeasible(link->right())) {
538 : // Interest mask is the intersection of left and right nodes.
539 3450 : StateInterestSet(state, (s_left->interest() & s_right->interest()));
540 : } else {
541 0 : StateInterestSet(state, BitSet());
542 : }
543 :
544 : // This is an add operation for nodes that are interested and
545 : // have not seen the advertisement.
546 3450 : BitSet add_set;
547 3450 : add_set.BuildComplement(state->interest(), state->advertised());
548 :
549 3450 : BitSet rm_set;
550 3450 : rm_set.BuildComplement(state->advertised(), state->interest());
551 :
552 3450 : if (!add_set.empty()) {
553 582 : ProcessAdjacentNode(link->left(), add_set, s_left, force_update);
554 582 : ProcessAdjacentNode(link->right(), add_set, s_right, force_update);
555 : }
556 :
557 3450 : UpdateAddChange(link, state, add_set, rm_set, false);
558 :
559 3450 : bool move = UpdateRemove(link, state, rm_set);
560 3450 : if (move) {
561 6 : MoveAdjacentNode(s_left);
562 6 : MoveAdjacentNode(s_right);
563 : }
564 3502 : } else if ((state != NULL) && state->IsValid()) {
565 52 : IFMapNode *left = link->LeftNode(server_->database());
566 52 : IFMapNodeState *s_left = state->left();
567 52 : assert((left != NULL) && (s_left != NULL));
568 52 : IFMapNode *right = link->RightNode(server_->database());
569 52 : IFMapNodeState *s_right = state->right();
570 52 : assert((right != NULL) && (s_right != NULL));
571 52 : BitSet interest = s_left->interest() & s_right->interest();
572 52 : StateInterestReset(state, state->interest());
573 :
574 52 : IFMAP_DEBUG(LinkOper, "LinkRemove", left->ToString(), right->ToString(),
575 : s_left->interest().ToString(), s_right->interest().ToString());
576 52 : walker_->LinkRemove(interest);
577 :
578 52 : state->RemoveDependency();
579 52 : state->ClearValid();
580 :
581 : // enqueue update.
582 52 : EnqueueDelete(link, state);
583 52 : if (state->update_list().empty()) {
584 33 : DeleteStateIfAppropriate(table, entry, state);
585 : }
586 :
587 52 : MaybeNotifyOnLinkDelete(left, s_left);
588 52 : MaybeNotifyOnLinkDelete(right, s_right);
589 52 : }
590 3502 : }
591 :
592 1158 : void IFMapExporter::StateUpdateOnDequeue(IFMapUpdate *update,
593 : const BitSet &dequeue_set,
594 : bool is_delete) {
595 1158 : DBTable *table = NULL;
596 1158 : DBEntry *db_entry = NULL;
597 :
598 1158 : IFMapState *state = NULL;
599 1158 : if (update->data().type == IFMapObjectPtr::NODE) {
600 566 : IFMapNode *node = update->data().u.node;
601 566 : db_entry = node;
602 566 : table = node->table();
603 592 : } else if (update->data().type == IFMapObjectPtr::LINK) {
604 592 : db_entry = update->data().u.link;
605 592 : table = link_table_;
606 : }
607 : state = static_cast<IFMapState *>(
608 1158 : db_entry->GetState(table, TableListenerId(table)));
609 1158 : if (is_delete) {
610 : // For any bit in dequeue_set, its possible that advertised is not set.
611 : // EG: update is UPDATE and we are called from UpdateQ.Leave(). Reset
612 : // only the bits that are really set.
613 90 : BitSet adv_bits = state->advertised() & dequeue_set;
614 90 : StateAdvertisedReset(state, adv_bits);
615 90 : } else {
616 1068 : StateAdvertisedOr(state, dequeue_set);
617 : }
618 :
619 1158 : if (update->advertise().empty()) {
620 1158 : state->Remove(update);
621 1158 : if (update->IsDelete()) {
622 90 : DeleteStateIfAppropriate(table, db_entry, state);
623 : }
624 1158 : delete update;
625 : }
626 1158 : }
627 :
628 : struct IFMapUpdateDisposer {
629 7924 : explicit IFMapUpdateDisposer(IFMapUpdateQueue *queue) : queue_(queue) { }
630 42 : void operator()(IFMapUpdate *ptr) {
631 42 : queue_->Dequeue(ptr);
632 42 : boost::checked_delete(ptr);
633 42 : }
634 :
635 : private:
636 : IFMapUpdateQueue *queue_;
637 : };
638 :
639 7924 : void IFMapExporter::TableStateClear(DBTable *table,
640 : DBTable::ListenerId tsid) {
641 : DBTablePartition *partition = static_cast<DBTablePartition *>(
642 7924 : table->GetTablePartition(0));
643 :
644 7924 : IFMapUpdateDisposer disposer(queue());
645 7924 : for (DBEntry *entry = static_cast<DBEntry *>(partition->GetFirst()),
646 12925 : *next = NULL; entry != NULL; entry = next) {
647 5001 : next = static_cast<DBEntry *>(partition->GetNext(entry));
648 : IFMapState *state = static_cast<IFMapState *>(
649 5001 : entry->GetState(table, tsid));
650 5001 : if (state == NULL) {
651 0 : continue;
652 : }
653 5001 : entry->ClearState(table, tsid);
654 5001 : state->ClearAndDispose(disposer);
655 5001 : boost::checked_delete(state);
656 : }
657 :
658 7924 : }
659 :
660 168 : bool IFMapExporter::FilterNeighbor(IFMapNode *lnode, IFMapLink *link) {
661 168 : return walker_->FilterNeighbor(lnode, link);
662 : }
663 :
664 3627 : bool IFMapExporter::ConfigChanged(IFMapNode *node) {
665 3627 : IFMapNodeState *state = NodeStateLookup(node);
666 3627 : bool changed = false;
667 3627 : assert(state);
668 :
669 3627 : IFMapExporter::crc32type node_crc = node->GetConfigCrc();
670 3627 : if (state->crc() != node_crc) {
671 2212 : changed = true;
672 2212 : state->SetCrc(node_crc);
673 : }
674 :
675 3627 : return changed;
676 : }
677 :
678 74 : void IFMapExporter::AddClientConfigTracker(int index) {
679 222 : for (int tracker_type = 0; tracker_type < TT_END; ++tracker_type) {
680 148 : if (index >= (int)client_config_tracker_[tracker_type].size()) {
681 144 : client_config_tracker_[tracker_type].resize(index + 1, NULL);
682 : }
683 148 : assert(client_config_tracker_[tracker_type][index] == NULL);
684 148 : ConfigSet *set = new ConfigSet();
685 148 : client_config_tracker_[tracker_type][index] = set;
686 : }
687 74 : }
688 :
689 6 : void IFMapExporter::DeleteClientConfigTracker(int index) {
690 18 : for (int tracker_type = 0; tracker_type < TT_END; ++tracker_type) {
691 12 : ConfigSet *set = client_config_tracker_[tracker_type].at(index);
692 12 : assert(set);
693 12 : delete set;
694 12 : client_config_tracker_[tracker_type][index] = NULL;
695 : }
696 6 : }
697 :
698 2542 : void IFMapExporter::UpdateClientConfigTracker(IFMapState *state,
699 : const BitSet& client_bits, bool add, TrackerType tracker_type) {
700 5068 : for (size_t pos = client_bits.find_first(); pos != BitSet::npos;
701 2526 : pos = client_bits.find_next(pos)) {
702 2526 : ConfigSet *set = client_config_tracker_[tracker_type].at(pos);
703 2526 : assert(set);
704 2526 : if (add) {
705 2242 : set->insert(state);
706 : } else {
707 284 : CsSz_t num = set->erase(state);
708 284 : assert(num == 1);
709 : }
710 : }
711 2542 : }
712 :
713 6 : void IFMapExporter::CleanupClientConfigTrackedEntries(int index) {
714 6 : BitSet rm_bs;
715 6 : rm_bs.set(index);
716 :
717 6 : ConfigSet *set = client_config_tracker_[INTEREST].at(index);
718 6 : assert(set);
719 48 : for (ConfigSet::iterator iter = set->begin(); iter != set->end(); ++iter) {
720 42 : IFMapState *state = *iter;
721 42 : state->InterestReset(rm_bs);
722 : }
723 :
724 6 : set = client_config_tracker_[ADVERTISED].at(index);
725 6 : assert(set);
726 48 : for (ConfigSet::iterator iter = set->begin(); iter != set->end(); ++iter) {
727 42 : IFMapState *state = *iter;
728 42 : state->AdvertisedReset(rm_bs);
729 : }
730 6 : }
731 :
732 0 : bool IFMapExporter::ClientHasConfigTracker(TrackerType tracker_type,
733 : int index) {
734 0 : ConfigSet *set = client_config_tracker_[tracker_type].at(index);
735 0 : return ((set != NULL) ? true : false);
736 : }
737 :
738 24 : bool IFMapExporter::ClientConfigTrackerHasState(TrackerType tracker_type,
739 : int index, IFMapState *state) {
740 24 : ConfigSet *set = client_config_tracker_[tracker_type].at(index);
741 24 : assert(set);
742 24 : ConfigSet::iterator iter = set->find(state);
743 24 : return (iter == set->end() ? false : true);
744 : }
745 :
746 16 : bool IFMapExporter::ClientConfigTrackerEmpty(TrackerType tracker_type,
747 : int index) {
748 16 : ConfigSet *set = client_config_tracker_[tracker_type].at(index);
749 16 : assert(set);
750 16 : return set->empty();
751 : }
752 :
753 8 : size_t IFMapExporter::ClientConfigTrackerSize(TrackerType tracker_type,
754 : int index) {
755 8 : ConfigSet *set = client_config_tracker_[tracker_type].at(index);
756 8 : assert(set);
757 8 : return set->size();
758 : }
759 :
760 21 : IFMapExporter::Cs_citer IFMapExporter::ClientConfigTrackerBegin(
761 : TrackerType tracker_type, int index) const {
762 21 : ConfigSet *set = client_config_tracker_[tracker_type].at(index);
763 21 : assert(set);
764 21 : return set->begin();
765 : }
766 :
767 21 : IFMapExporter::Cs_citer IFMapExporter::ClientConfigTrackerEnd(
768 : TrackerType tracker_type, int index) const {
769 21 : ConfigSet *set = client_config_tracker_[tracker_type].at(index);
770 21 : assert(set);
771 21 : return set->end();
772 : }
773 :
774 3659 : void IFMapExporter::StateInterestSet(IFMapState *state,
775 : const BitSet& interest_bits) {
776 : // Add the node to the config-tracker of all clients that just became
777 : // interested in this node.
778 3659 : bool add = true;
779 3659 : BitSet new_clients;
780 3659 : new_clients.BuildComplement(interest_bits, state->interest());
781 3659 : if (!new_clients.empty()) {
782 647 : UpdateClientConfigTracker(state, new_clients, add, INTEREST);
783 : }
784 :
785 : // Remove the node from the config-tracker of all clients that are no longer
786 : // interested in this node.
787 3659 : add = false;
788 3659 : BitSet old_clients;
789 3659 : old_clients.BuildComplement(state->interest(), interest_bits);
790 3659 : if (!old_clients.empty()) {
791 138 : UpdateClientConfigTracker(state, old_clients, add, INTEREST);
792 : }
793 :
794 3659 : state->SetInterest(interest_bits);
795 3659 : }
796 :
797 : // Add the node to the config-tracker of all clients that just became interested
798 : // in this node.
799 497 : void IFMapExporter::StateInterestOr(IFMapState *state,
800 : const BitSet& interest_bits) {
801 497 : bool add = true;
802 497 : UpdateClientConfigTracker(state, interest_bits, add, INTEREST);
803 497 : state->InterestOr(interest_bits);
804 497 : }
805 :
806 : // Remove the node from the config-tracker of all clients that are no longer
807 : // interested in this node.
808 102 : void IFMapExporter::StateInterestReset(IFMapState *state,
809 : const BitSet& interest_bits) {
810 102 : bool add = false;
811 102 : UpdateClientConfigTracker(state, interest_bits, add, INTEREST);
812 102 : state->InterestReset(interest_bits);
813 102 : }
814 :
815 : // Add the node to the config-tracker of all clients that just sent this node.
816 1068 : void IFMapExporter::StateAdvertisedOr(IFMapState *state,
817 : const BitSet& advertised_bits) {
818 1068 : bool add = true;
819 1068 : UpdateClientConfigTracker(state, advertised_bits, add, ADVERTISED);
820 1068 : state->AdvertisedOr(advertised_bits);
821 1068 : }
822 :
823 : // Remove the node from the config-tracker of all clients from whom the node
824 : // was withdrawn.
825 90 : void IFMapExporter::StateAdvertisedReset(IFMapState *state,
826 : const BitSet& advertised_bits) {
827 90 : bool add = false;
828 90 : UpdateClientConfigTracker(state, advertised_bits, add, ADVERTISED);
829 90 : state->AdvertisedReset(advertised_bits);
830 90 : }
831 :
832 0 : const IFMapTypenameWhiteList &IFMapExporter::get_traversal_white_list() const {
833 0 : return walker_->get_traversal_white_list();
834 : }
835 :
836 6 : void IFMapExporter::ResetLinkDeleteClients(const BitSet &bset) {
837 6 : walker_->ResetLinkDeleteClients(bset);
838 6 : }
839 :
|