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 39852 : 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 18915 : const IFMapExporter::TableInfo *IFMapExporter::Find(
94 : const DBTable *table) const {
95 : TableMap::const_iterator loc =
96 18915 : table_map_.find(const_cast<DBTable *>(table));
97 18915 : if (loc != table_map_.end()) {
98 18915 : return loc->second;
99 : }
100 0 : return NULL;
101 : }
102 :
103 1724 : DBTableBase::ListenerId IFMapExporter::TableListenerId(
104 : const DBTable *table) const {
105 1724 : const IFMapExporter::TableInfo *tinfo = Find(table);
106 1724 : if (tinfo == NULL) {
107 0 : return DBTableBase::kInvalidId;
108 : }
109 1724 : return tinfo->id();
110 : }
111 :
112 10536 : bool IFMapExporter::IsFeasible(const IFMapNode *node) {
113 10536 : if (node->IsDeleted()) {
114 47 : return false;
115 : }
116 10489 : return true;
117 : }
118 :
119 6904 : const BitSet *IFMapExporter::MergeClientInterest(
120 : IFMapNode * node, IFMapNodeState *state, std::unique_ptr<BitSet> *ptr) {
121 :
122 6904 : const BitSet *set = &state->interest();
123 6904 : IFMapTable *table = node->table();
124 :
125 6904 : if (table->name() == "__ifmap__.virtual_router.0") {
126 174 : IFMapClient *client = server_->FindClient(node->name());
127 174 : if (!client) {
128 42 : return set;
129 : }
130 132 : BitSet *merged_set = new BitSet(*set);
131 132 : merged_set->set(client->index());
132 132 : ptr->reset(merged_set);
133 132 : StateInterestSet(state, *merged_set);
134 132 : return merged_set;
135 : }
136 :
137 6730 : return set;
138 : }
139 :
140 3770 : IFMapNodeState *IFMapExporter::NodeStateLookup(IFMapNode *node){
141 3770 : const TableInfo *tinfo = Find(node->table());
142 : IFMapNodeState *state = static_cast<IFMapNodeState *>(
143 3770 : node->GetState(node->table(), tinfo ? tinfo->id() : 0));
144 3770 : return state;
145 : }
146 :
147 5932 : IFMapNodeState *IFMapExporter::NodeStateLocate(IFMapNode *node){
148 5932 : const TableInfo *tinfo = Find(node->table());
149 : IFMapNodeState *state = static_cast<IFMapNodeState *>(
150 5932 : node->GetState(node->table(), tinfo->id()));
151 5932 : if (state == NULL) {
152 1775 : state = new IFMapNodeState(node);
153 1775 : node->SetState(node->table(), tinfo->id(), state);
154 : }
155 5932 : return state;
156 : }
157 :
158 9585 : IFMapUpdateQueue *IFMapExporter::queue() {
159 9585 : return server_->queue();
160 : }
161 :
162 1431 : IFMapUpdateSender *IFMapExporter::sender() {
163 1431 : return server_->sender();
164 : }
165 :
166 : template <class ObjectType>
167 7037 : 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 7037 : IFMapUpdate *update = state->GetUpdate(IFMapListEntry::UPDATE);
173 7037 : if (update != NULL) {
174 586 : update->AdvertiseReset(rm_set);
175 : }
176 :
177 7037 : if (state->interest().empty()) {
178 5267 : if (update != NULL) {
179 14 : queue()->Dequeue(update);
180 14 : state->Remove(update);
181 14 : delete update;
182 : }
183 5267 : return false;
184 : }
185 :
186 1770 : if (!change && add_set.empty()) {
187 87 : return false;
188 : }
189 :
190 1683 : bool is_move = false;
191 1683 : if (update != NULL) {
192 572 : if (!change) {
193 572 : if (update->advertise().Contains(add_set)) {
194 506 : return false;
195 : }
196 : } else {
197 0 : if (state->interest() == update->advertise()) {
198 0 : return false;
199 : }
200 : }
201 66 : is_move = true;
202 66 : queue()->Dequeue(update);
203 : } else {
204 1111 : update = new IFMapUpdate(obj, true);
205 1111 : state->Insert(update);
206 : }
207 :
208 1177 : if (!change) {
209 1168 : update->AdvertiseOr(add_set);
210 : } else {
211 9 : update->SetAdvertise(state->interest());
212 : }
213 1177 : queue()->Enqueue(update);
214 1177 : sender()->QueueActive();
215 1177 : return is_move;
216 : }
217 :
218 : template <class ObjectType>
219 7037 : bool IFMapExporter::UpdateRemove(ObjectType *obj, IFMapState *state,
220 : const BitSet &rm_set) {
221 : // Remove any bit in "interest" from the delete update.
222 7037 : IFMapUpdate *update = state->GetUpdate(IFMapListEntry::DEL);
223 7037 : if (update != NULL) {
224 192 : update->AdvertiseReset(state->interest());
225 : }
226 :
227 7037 : if (rm_set.empty()) {
228 6767 : if (update != NULL) {
229 20 : queue()->Dequeue(update);
230 20 : state->Remove(update);
231 20 : delete update;
232 : }
233 6767 : return false;
234 : }
235 :
236 270 : bool is_move = false;
237 270 : if (update != NULL) {
238 172 : if (rm_set == update->advertise()) {
239 152 : return false;
240 : }
241 20 : is_move = true;
242 20 : queue()->Dequeue(update);
243 : } else {
244 98 : update = new IFMapUpdate(obj, false);
245 98 : state->Insert(update);
246 : }
247 :
248 118 : update->SetAdvertise(rm_set);
249 118 : queue()->Enqueue(update);
250 118 : sender()->QueueActive();
251 118 : return is_move;
252 : }
253 :
254 : template <class ObjectType>
255 81 : void IFMapExporter::EnqueueDelete(ObjectType *obj, IFMapState *state) {
256 81 : IFMapUpdate *update = state->GetUpdate(IFMapListEntry::UPDATE);
257 81 : if (update != NULL) {
258 4 : queue()->Dequeue(update);
259 4 : state->Remove(update);
260 4 : delete update;
261 : }
262 :
263 81 : update = state->GetUpdate(IFMapListEntry::DEL);
264 81 : if (update != NULL) {
265 0 : queue()->Dequeue(update);
266 : }
267 81 : if (state->advertised().empty()) {
268 51 : assert(update == NULL);
269 51 : return;
270 : }
271 :
272 30 : if (update == NULL) {
273 30 : update = new IFMapUpdate(obj, false);
274 30 : state->Insert(update);
275 : }
276 30 : update->SetAdvertise(state->advertised());
277 30 : queue()->Enqueue(update);
278 30 : sender()->QueueActive();
279 : }
280 :
281 358 : IFMapLinkState *IFMapExporter::LinkStateLookup(IFMapLink *link) {
282 358 : const TableInfo *tinfo = Find(link_table_);
283 358 : if (!tinfo)
284 0 : return NULL;
285 : IFMapLinkState *state = static_cast<IFMapLinkState *>(
286 358 : link->GetState(link_table_, tinfo->id()));
287 358 : return state;
288 : }
289 :
290 58 : void IFMapExporter::MoveDependentLinks(IFMapNodeState *state) {
291 230 : for (IFMapNodeState::iterator iter = state->begin(); iter != state->end();
292 172 : ++iter) {
293 172 : IFMapLink *link = iter.operator->();
294 172 : IFMapLinkState *ls = LinkStateLookup(link);
295 172 : if (ls == NULL) {
296 0 : continue;
297 : }
298 172 : IFMapUpdate *update = ls->GetUpdate(IFMapListEntry::UPDATE);
299 172 : if (update == NULL) {
300 78 : continue;
301 : }
302 94 : assert(!update->advertise().empty());
303 94 : queue()->Dequeue(update);
304 94 : queue()->Enqueue(update);
305 94 : sender()->QueueActive();
306 : }
307 58 : }
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 76 : void IFMapExporter::RemoveDependentLinks(IFMapNodeState *state,
320 : const BitSet &rm_set) {
321 76 : for (IFMapNodeState::iterator iter = state->begin(), next = state->begin();
322 258 : iter != state->end(); iter = next) {
323 182 : IFMapLink *link = iter.operator->();
324 182 : next = ++iter;
325 182 : IFMapLinkState *ls = LinkStateLookup(link);
326 182 : if (ls == NULL) {
327 0 : continue;
328 : }
329 182 : BitSet common = ls->advertised() & rm_set;
330 182 : if (!common.empty()) {
331 128 : LinkTableExport(link->get_table_partition(), link);
332 : }
333 182 : }
334 76 : }
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 610 : current |= update->advertise();
342 : }
343 1164 : if (!current.Contains(add_set)) {
344 552 : NodeTableExport(node->get_table_partition(), node);
345 : } else {
346 612 : if (force_process) {
347 52 : if (update) {
348 40 : update->AdvertiseReset(update->advertise());
349 : }
350 52 : state->AdvertisedReset(state->advertised());
351 52 : NodeTableExport(node->get_table_partition(), node);
352 : }
353 : }
354 1164 : }
355 :
356 141 : void IFMapExporter::DeleteStateIfAppropriate(DBTable *table, DBEntryBase *entry,
357 : IFMapState *state) {
358 141 : if (state->CanDelete()) {
359 73 : assert(state->advertised().empty());
360 73 : assert(state->interest().empty());
361 73 : entry->ClearState(table, TableListenerId(table));
362 73 : delete state;
363 : }
364 141 : }
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 3632 : void IFMapExporter::NodeTableExport(DBTablePartBase *partition,
381 : DBEntryBase *entry) {
382 3632 : IFMapNode *node = static_cast<IFMapNode *>(entry);
383 3632 : DBTable *table = static_cast<DBTablePartition *>(partition)->table();
384 :
385 3632 : const TableInfo *tinfo = Find(table);
386 3632 : DBState *entry_state = entry->GetState(table, tinfo->id());
387 3632 : IFMapNodeState *state = static_cast<IFMapNodeState *>(entry_state);
388 :
389 3632 : if (IsFeasible(node)) {
390 3585 : if (state == NULL) {
391 602 : state = new IFMapNodeState(node);
392 602 : entry->SetState(table, tinfo->id(), state);
393 : }
394 3585 : state->SetValid(node);
395 :
396 : // This is an add operation for nodes that are interested and
397 : // have not seen the advertisement.
398 3585 : BitSet add_set;
399 3585 : 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 3585 : BitSet rm_set;
404 3585 : rm_set.BuildComplement(state->advertised(), state->interest());
405 :
406 3585 : 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 3585 : bool move = UpdateAddChange(node, state, add_set, rm_set, change);
414 3585 : if (move) {
415 58 : MoveDependentLinks(state);
416 : }
417 :
418 : // For the subset of clients being removed, make sure that all
419 : // dependent links are removed before.
420 3585 : if (!rm_set.empty()) {
421 76 : RemoveDependentLinks(state, rm_set);
422 : }
423 3585 : UpdateRemove(node, state, rm_set);
424 3632 : } else if (state != NULL) {
425 : // Link deletes must preceed node deletes.
426 41 : ConfigChanged(node);
427 41 : state->ClearValid();
428 41 : if (!state->HasDependents()) {
429 : // enqueue delete.
430 38 : StateInterestReset(state, state->interest());
431 38 : EnqueueDelete(node, state);
432 38 : if (state->update_list().empty()) {
433 26 : DeleteStateIfAppropriate(table, entry, state);
434 : }
435 : }
436 : }
437 3632 : }
438 :
439 86 : static void MaybeNotifyOnLinkDelete(IFMapNode *node, IFMapNodeState *state) {
440 86 : if (node->IsDeleted() && !state->HasDependents()) {
441 38 : IFMapTable *table = node->table();
442 38 : table->Change(node);
443 : }
444 86 : }
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 3499 : void IFMapExporter::LinkTableExport(DBTablePartBase *partition,
451 : DBEntryBase *entry) {
452 3499 : IFMapLink *link = static_cast<IFMapLink *>(entry);
453 3499 : DBTable *table = static_cast<DBTablePartition *>(partition)->table();
454 3499 : const TableInfo *tinfo = Find(table);
455 3499 : DBState *entry_state = entry->GetState(table, tinfo->id());
456 3499 : IFMapLinkState *state = static_cast<IFMapLinkState *>(entry_state);
457 :
458 3499 : if (!entry->IsDeleted()) {
459 3452 : IFMapNodeState *s_left = NULL;
460 3452 : IFMapNodeState *s_right = NULL;
461 :
462 3452 : bool add_link = false;
463 3452 : bool force_update = false;
464 3452 : if (state == NULL) {
465 2712 : state = new IFMapLinkState(link);
466 2712 : entry->SetState(table, tinfo->id(), state);
467 2712 : s_left = NodeStateLocate(link->left());
468 2712 : s_right = NodeStateLocate(link->right());
469 2712 : 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 5550 : if (starts_with(link->left()->ToString(), "virtual-router") &&
484 2838 : (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 740 : if (state->IsValid() && !link->link_revival()) {
491 : // Link change
492 736 : assert(state->HasDependency());
493 736 : s_left = state->left();
494 736 : s_right = state->right();
495 4 : } else if (state->IsValid() && link->link_revival()) {
496 2 : link->SetLinkRevival(false);
497 2 : assert(state->HasDependency());
498 2 : s_left = state->left();
499 2 : s_right = state->right();
500 2 : force_update = true;
501 2 : state->AdvertisedReset(state->advertised());
502 2 : if (s_left->advertised().Contains(state->interest()))
503 2 : s_left->AdvertisedReset(state->interest());
504 2 : if (s_right->advertised().Contains(state->interest()))
505 2 : s_right->AdvertisedReset(state->interest());
506 : } else {
507 : // Link revival i.e. delete quickly followed by add
508 2 : assert(!state->HasDependency());
509 2 : s_left = NodeStateLocate(link->left());
510 2 : s_right = NodeStateLocate(link->right());
511 2 : add_link = true;
512 2 : force_update = true;
513 2 : state->AdvertisedReset(state->advertised());
514 2 : link->SetLinkRevival(false);
515 2 : if (s_left->advertised().Contains(state->interest()))
516 2 : s_left->AdvertisedReset(state->interest());
517 2 : if (s_right->advertised().Contains(state->interest()))
518 2 : 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 3452 : std::unique_ptr<BitSet> ml, mr;
525 3452 : const BitSet *lset = MergeClientInterest(link->left(), s_left, &ml);
526 3452 : const BitSet *rset = MergeClientInterest(link->right(), s_right, &mr);
527 3452 : if (*lset != *rset) {
528 243 : walker_->LinkAdd(link, link->left(), *lset, link->right(), *rset);
529 : }
530 :
531 3452 : if (add_link) {
532 : // Establish dependency.
533 2714 : state->SetDependency(s_left, s_right);
534 2714 : state->SetValid();
535 : }
536 :
537 3452 : if (IsFeasible(link->left()) && IsFeasible(link->right())) {
538 : // Interest mask is the intersection of left and right nodes.
539 3452 : 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 3452 : BitSet add_set;
547 3452 : add_set.BuildComplement(state->interest(), state->advertised());
548 :
549 3452 : BitSet rm_set;
550 3452 : rm_set.BuildComplement(state->advertised(), state->interest());
551 :
552 3452 : 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 3452 : UpdateAddChange(link, state, add_set, rm_set, false);
558 :
559 3452 : bool move = UpdateRemove(link, state, rm_set);
560 3452 : if (move) {
561 6 : MoveAdjacentNode(s_left);
562 6 : MoveAdjacentNode(s_right);
563 : }
564 3499 : } else if ((state != NULL) && state->IsValid()) {
565 43 : IFMapNode *left = link->LeftNode(server_->database());
566 43 : IFMapNodeState *s_left = state->left();
567 43 : assert((left != NULL) && (s_left != NULL));
568 43 : IFMapNode *right = link->RightNode(server_->database());
569 43 : IFMapNodeState *s_right = state->right();
570 43 : assert((right != NULL) && (s_right != NULL));
571 43 : BitSet interest = s_left->interest() & s_right->interest();
572 43 : StateInterestReset(state, state->interest());
573 :
574 43 : IFMAP_DEBUG(LinkOper, "LinkRemove", left->ToString(), right->ToString(),
575 : s_left->interest().ToString(), s_right->interest().ToString());
576 43 : walker_->LinkRemove(interest);
577 :
578 43 : state->RemoveDependency();
579 43 : state->ClearValid();
580 :
581 : // enqueue update.
582 43 : EnqueueDelete(link, state);
583 43 : if (state->update_list().empty()) {
584 25 : DeleteStateIfAppropriate(table, entry, state);
585 : }
586 :
587 43 : MaybeNotifyOnLinkDelete(left, s_left);
588 43 : MaybeNotifyOnLinkDelete(right, s_right);
589 43 : }
590 3499 : }
591 :
592 1159 : void IFMapExporter::StateUpdateOnDequeue(IFMapUpdate *update,
593 : const BitSet &dequeue_set,
594 : bool is_delete) {
595 1159 : DBTable *table = NULL;
596 1159 : DBEntry *db_entry = NULL;
597 :
598 1159 : IFMapState *state = NULL;
599 1159 : if (update->data().type == IFMapObjectPtr::NODE) {
600 567 : IFMapNode *node = update->data().u.node;
601 567 : db_entry = node;
602 567 : 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 1159 : db_entry->GetState(table, TableListenerId(table)));
609 1159 : 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 1069 : StateAdvertisedOr(state, dequeue_set);
617 : }
618 :
619 1159 : if (update->advertise().empty()) {
620 1159 : state->Remove(update);
621 1159 : if (update->IsDelete()) {
622 90 : DeleteStateIfAppropriate(table, db_entry, state);
623 : }
624 1159 : delete update;
625 : }
626 1159 : }
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 12940 : *next = NULL; entry != NULL; entry = next) {
647 5016 : next = static_cast<DBEntry *>(partition->GetNext(entry));
648 : IFMapState *state = static_cast<IFMapState *>(
649 5016 : entry->GetState(table, tsid));
650 5016 : if (state == NULL) {
651 0 : continue;
652 : }
653 5016 : entry->ClearState(table, tsid);
654 5016 : state->ClearAndDispose(disposer);
655 5016 : 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 3626 : bool IFMapExporter::ConfigChanged(IFMapNode *node) {
665 3626 : IFMapNodeState *state = NodeStateLookup(node);
666 3626 : bool changed = false;
667 3626 : assert(state);
668 :
669 3626 : IFMapExporter::crc32type node_crc = node->GetConfigCrc();
670 3626 : if (state->crc() != node_crc) {
671 2210 : changed = true;
672 2210 : state->SetCrc(node_crc);
673 : }
674 :
675 3626 : 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 2510 : void IFMapExporter::UpdateClientConfigTracker(IFMapState *state,
699 : const BitSet& client_bits, bool add, TrackerType tracker_type) {
700 5021 : for (size_t pos = client_bits.find_first(); pos != BitSet::npos;
701 2511 : pos = client_bits.find_next(pos)) {
702 2511 : ConfigSet *set = client_config_tracker_[tracker_type].at(pos);
703 2511 : assert(set);
704 2511 : if (add) {
705 2235 : set->insert(state);
706 : } else {
707 276 : CsSz_t num = set->erase(state);
708 276 : assert(num == 1);
709 : }
710 : }
711 2510 : }
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 20 : IFMapExporter::Cs_citer IFMapExporter::ClientConfigTrackerBegin(
761 : TrackerType tracker_type, int index) const {
762 20 : ConfigSet *set = client_config_tracker_[tracker_type].at(index);
763 20 : assert(set);
764 20 : return set->begin();
765 : }
766 :
767 20 : IFMapExporter::Cs_citer IFMapExporter::ClientConfigTrackerEnd(
768 : TrackerType tracker_type, int index) const {
769 20 : ConfigSet *set = client_config_tracker_[tracker_type].at(index);
770 20 : assert(set);
771 20 : return set->end();
772 : }
773 :
774 3660 : 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 3660 : bool add = true;
779 3660 : BitSet new_clients;
780 3660 : new_clients.BuildComplement(interest_bits, state->interest());
781 3660 : if (!new_clients.empty()) {
782 644 : 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 3660 : add = false;
788 3660 : BitSet old_clients;
789 3660 : old_clients.BuildComplement(state->interest(), interest_bits);
790 3660 : if (!old_clients.empty()) {
791 132 : UpdateClientConfigTracker(state, old_clients, add, INTEREST);
792 : }
793 :
794 3660 : state->SetInterest(interest_bits);
795 3660 : }
796 :
797 : // Add the node to the config-tracker of all clients that just became interested
798 : // in this node.
799 494 : void IFMapExporter::StateInterestOr(IFMapState *state,
800 : const BitSet& interest_bits) {
801 494 : bool add = true;
802 494 : UpdateClientConfigTracker(state, interest_bits, add, INTEREST);
803 494 : state->InterestOr(interest_bits);
804 494 : }
805 :
806 : // Remove the node from the config-tracker of all clients that are no longer
807 : // interested in this node.
808 81 : void IFMapExporter::StateInterestReset(IFMapState *state,
809 : const BitSet& interest_bits) {
810 81 : bool add = false;
811 81 : UpdateClientConfigTracker(state, interest_bits, add, INTEREST);
812 81 : state->InterestReset(interest_bits);
813 81 : }
814 :
815 : // Add the node to the config-tracker of all clients that just sent this node.
816 1069 : void IFMapExporter::StateAdvertisedOr(IFMapState *state,
817 : const BitSet& advertised_bits) {
818 1069 : bool add = true;
819 1069 : UpdateClientConfigTracker(state, advertised_bits, add, ADVERTISED);
820 1069 : state->AdvertisedOr(advertised_bits);
821 1069 : }
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 :
|