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 8074 : TableInfo(DBTable::ListenerId id)
31 8074 : : id_(id) {
32 8074 : }
33 35954 : DBTableBase::ListenerId id() const { return id_; }
34 :
35 : private:
36 : DBTableBase::ListenerId id_;
37 : };
38 :
39 180 : IFMapExporter::IFMapExporter(IFMapServer *server)
40 540 : : server_(server), link_table_(NULL) {
41 180 : }
42 :
43 540 : IFMapExporter::~IFMapExporter() {
44 180 : Shutdown();
45 900 : }
46 :
47 54 : void IFMapExporter::Initialize(DB *db) {
48 54 : for (DB::iterator iter = db->lower_bound("__ifmap__");
49 8074 : iter != db->end(); ++iter) {
50 8074 : DBTable *table = static_cast<DBTable *>(iter->second);
51 8074 : if (table->name().find("__ifmap__") != 0) {
52 54 : break;
53 : }
54 : DBTable::ListenerId id =
55 8020 : table->Register(
56 : boost::bind(&IFMapExporter::NodeTableExport, this, _1, _2));
57 8020 : table_map_.insert(make_pair(table, new TableInfo(id)));
58 : }
59 :
60 54 : link_table_ = static_cast<DBTable *>(
61 54 : db->FindTable("__ifmap_metadata__.0"));
62 54 : assert(link_table_);
63 : DBTable::ListenerId id =
64 54 : link_table_->Register(
65 : boost::bind(&IFMapExporter::LinkTableExport, this, _1, _2));
66 54 : table_map_.insert(make_pair(link_table_, new TableInfo(id)));
67 :
68 54 : walker_.reset(new IFMapGraphWalker(server_->graph(), this));
69 54 : }
70 :
71 340 : void IFMapExporter::Shutdown() {
72 1020 : for (int i = 0; i < TT_END; ++i) {
73 984 : for (size_t index = 0; index < client_config_tracker_[i].size(); ++index) {
74 304 : ConfigSet *set = client_config_tracker_[i][index];
75 304 : if (set) {
76 144 : set->clear();
77 144 : delete set;
78 144 : client_config_tracker_[i][index] = NULL;
79 : }
80 : }
81 : }
82 8414 : for (TableMap::iterator iter = table_map_.begin(); iter != table_map_.end();
83 8074 : ++iter) {
84 8074 : DBTable *table = iter->first;
85 8074 : TableInfo *info = iter->second;
86 8074 : table->Unregister(info->id());
87 8074 : TableStateClear(table, info->id());
88 8074 : delete info;
89 : }
90 340 : table_map_.clear();
91 340 : }
92 :
93 15698 : const IFMapExporter::TableInfo *IFMapExporter::Find(
94 : const DBTable *table) const {
95 : TableMap::const_iterator loc =
96 15698 : table_map_.find(const_cast<DBTable *>(table));
97 15698 : if (loc != table_map_.end()) {
98 15698 : return loc->second;
99 : }
100 0 : return NULL;
101 : }
102 :
103 1594 : DBTableBase::ListenerId IFMapExporter::TableListenerId(
104 : const DBTable *table) const {
105 1594 : const IFMapExporter::TableInfo *tinfo = Find(table);
106 1594 : if (tinfo == NULL) {
107 0 : return DBTableBase::kInvalidId;
108 : }
109 1594 : return tinfo->id();
110 : }
111 :
112 8596 : bool IFMapExporter::IsFeasible(const IFMapNode *node) {
113 8596 : if (node->IsDeleted()) {
114 26 : return false;
115 : }
116 8570 : return true;
117 : }
118 :
119 5488 : const BitSet *IFMapExporter::MergeClientInterest(
120 : IFMapNode * node, IFMapNodeState *state, std::unique_ptr<BitSet> *ptr) {
121 :
122 5488 : const BitSet *set = &state->interest();
123 5488 : IFMapTable *table = node->table();
124 :
125 5488 : if (table->name() == "__ifmap__.virtual_router.0") {
126 178 : IFMapClient *client = server_->FindClient(node->name());
127 178 : if (!client) {
128 40 : return set;
129 : }
130 138 : BitSet *merged_set = new BitSet(*set);
131 138 : merged_set->set(client->index());
132 138 : ptr->reset(merged_set);
133 138 : StateInterestSet(state, *merged_set);
134 138 : return merged_set;
135 : }
136 :
137 5310 : return set;
138 : }
139 :
140 3220 : IFMapNodeState *IFMapExporter::NodeStateLookup(IFMapNode *node){
141 3220 : const TableInfo *tinfo = Find(node->table());
142 : IFMapNodeState *state = static_cast<IFMapNodeState *>(
143 3220 : node->GetState(node->table(), tinfo ? tinfo->id() : 0));
144 3220 : return state;
145 : }
146 :
147 4724 : IFMapNodeState *IFMapExporter::NodeStateLocate(IFMapNode *node){
148 4724 : const TableInfo *tinfo = Find(node->table());
149 : IFMapNodeState *state = static_cast<IFMapNodeState *>(
150 4724 : node->GetState(node->table(), tinfo->id()));
151 4724 : if (state == NULL) {
152 1459 : state = new IFMapNodeState(node);
153 1459 : node->SetState(node->table(), tinfo->id(), state);
154 : }
155 4724 : return state;
156 : }
157 :
158 9542 : IFMapUpdateQueue *IFMapExporter::queue() {
159 9542 : return server_->queue();
160 : }
161 :
162 1307 : IFMapUpdateSender *IFMapExporter::sender() {
163 1307 : return server_->sender();
164 : }
165 :
166 : template <class ObjectType>
167 5826 : 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 5826 : IFMapUpdate *update = state->GetUpdate(IFMapListEntry::UPDATE);
173 5826 : if (update != NULL) {
174 525 : update->AdvertiseReset(rm_set);
175 : }
176 :
177 5826 : if (state->interest().empty()) {
178 4205 : if (update != NULL) {
179 10 : queue()->Dequeue(update);
180 10 : state->Remove(update);
181 10 : delete update;
182 : }
183 4205 : return false;
184 : }
185 :
186 1621 : if (!change && add_set.empty()) {
187 38 : return false;
188 : }
189 :
190 1583 : bool is_move = false;
191 1583 : if (update != NULL) {
192 515 : if (!change) {
193 515 : if (update->advertise().Contains(add_set)) {
194 467 : return false;
195 : }
196 : } else {
197 0 : if (state->interest() == update->advertise()) {
198 0 : return false;
199 : }
200 : }
201 48 : is_move = true;
202 48 : queue()->Dequeue(update);
203 : } else {
204 1068 : update = new IFMapUpdate(obj, true);
205 1068 : state->Insert(update);
206 : }
207 :
208 1116 : if (!change) {
209 1108 : update->AdvertiseOr(add_set);
210 : } else {
211 8 : update->SetAdvertise(state->interest());
212 : }
213 1116 : queue()->Enqueue(update);
214 1116 : sender()->QueueActive();
215 1116 : return is_move;
216 : }
217 :
218 : template <class ObjectType>
219 5826 : bool IFMapExporter::UpdateRemove(ObjectType *obj, IFMapState *state,
220 : const BitSet &rm_set) {
221 : // Remove any bit in "interest" from the delete update.
222 5826 : IFMapUpdate *update = state->GetUpdate(IFMapListEntry::DEL);
223 5826 : if (update != NULL) {
224 116 : update->AdvertiseReset(state->interest());
225 : }
226 :
227 5826 : if (rm_set.empty()) {
228 5648 : if (update != NULL) {
229 14 : queue()->Dequeue(update);
230 14 : state->Remove(update);
231 14 : delete update;
232 : }
233 5648 : return false;
234 : }
235 :
236 178 : bool is_move = false;
237 178 : if (update != NULL) {
238 102 : if (rm_set == update->advertise()) {
239 96 : return false;
240 : }
241 6 : is_move = true;
242 6 : queue()->Dequeue(update);
243 : } else {
244 76 : update = new IFMapUpdate(obj, false);
245 76 : state->Insert(update);
246 : }
247 :
248 82 : update->SetAdvertise(rm_set);
249 82 : queue()->Enqueue(update);
250 82 : sender()->QueueActive();
251 82 : return is_move;
252 : }
253 :
254 : template <class ObjectType>
255 36 : void IFMapExporter::EnqueueDelete(ObjectType *obj, IFMapState *state) {
256 36 : IFMapUpdate *update = state->GetUpdate(IFMapListEntry::UPDATE);
257 36 : if (update != NULL) {
258 4 : queue()->Dequeue(update);
259 4 : state->Remove(update);
260 4 : delete update;
261 : }
262 :
263 36 : update = state->GetUpdate(IFMapListEntry::DEL);
264 36 : if (update != NULL) {
265 0 : queue()->Dequeue(update);
266 : }
267 36 : if (state->advertised().empty()) {
268 6 : assert(update == NULL);
269 6 : 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 278 : IFMapLinkState *IFMapExporter::LinkStateLookup(IFMapLink *link) {
282 278 : const TableInfo *tinfo = Find(link_table_);
283 278 : if (!tinfo)
284 0 : return NULL;
285 : IFMapLinkState *state = static_cast<IFMapLinkState *>(
286 278 : link->GetState(link_table_, tinfo->id()));
287 278 : return state;
288 : }
289 :
290 48 : void IFMapExporter::MoveDependentLinks(IFMapNodeState *state) {
291 198 : for (IFMapNodeState::iterator iter = state->begin(); iter != state->end();
292 150 : ++iter) {
293 150 : IFMapLink *link = iter.operator->();
294 150 : IFMapLinkState *ls = LinkStateLookup(link);
295 150 : if (ls == NULL) {
296 0 : continue;
297 : }
298 150 : IFMapUpdate *update = ls->GetUpdate(IFMapListEntry::UPDATE);
299 150 : if (update == NULL) {
300 71 : continue;
301 : }
302 79 : assert(!update->advertise().empty());
303 79 : queue()->Dequeue(update);
304 79 : queue()->Enqueue(update);
305 79 : sender()->QueueActive();
306 : }
307 48 : }
308 :
309 0 : void IFMapExporter::MoveAdjacentNode(IFMapNodeState *state) {
310 0 : IFMapUpdate *update = state->GetUpdate(IFMapListEntry::DEL);
311 0 : if (update != NULL) {
312 0 : assert(!update->advertise().empty());
313 0 : queue()->Dequeue(update);
314 0 : queue()->Enqueue(update);
315 0 : sender()->QueueActive();
316 : }
317 0 : }
318 :
319 54 : void IFMapExporter::RemoveDependentLinks(IFMapNodeState *state,
320 : const BitSet &rm_set) {
321 54 : for (IFMapNodeState::iterator iter = state->begin(), next = state->begin();
322 178 : iter != state->end(); iter = next) {
323 124 : IFMapLink *link = iter.operator->();
324 124 : next = ++iter;
325 124 : IFMapLinkState *ls = LinkStateLookup(link);
326 124 : if (ls == NULL) {
327 0 : continue;
328 : }
329 124 : BitSet common = ls->advertised() & rm_set;
330 124 : if (!common.empty()) {
331 80 : LinkTableExport(link->get_table_partition(), link);
332 : }
333 124 : }
334 54 : }
335 :
336 1072 : void IFMapExporter::ProcessAdjacentNode(IFMapNode *node, const BitSet &add_set,
337 : IFMapNodeState *state, bool force_process) {
338 1072 : BitSet current = state->advertised();
339 1072 : IFMapUpdate *update = state->GetUpdate(IFMapListEntry::UPDATE);
340 1072 : if (update) {
341 538 : current |= update->advertise();
342 : }
343 1072 : if (!current.Contains(add_set)) {
344 528 : NodeTableExport(node->get_table_partition(), node);
345 : } else {
346 544 : 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 1072 : }
355 :
356 84 : void IFMapExporter::DeleteStateIfAppropriate(DBTable *table, DBEntryBase *entry,
357 : IFMapState *state) {
358 84 : if (state->CanDelete()) {
359 28 : assert(state->advertised().empty());
360 28 : assert(state->interest().empty());
361 28 : entry->ClearState(table, TableListenerId(table));
362 28 : delete state;
363 : }
364 84 : }
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 3108 : void IFMapExporter::NodeTableExport(DBTablePartBase *partition,
381 : DBEntryBase *entry) {
382 3108 : IFMapNode *node = static_cast<IFMapNode *>(entry);
383 3108 : DBTable *table = static_cast<DBTablePartition *>(partition)->table();
384 :
385 3108 : const TableInfo *tinfo = Find(table);
386 3108 : DBState *entry_state = entry->GetState(table, tinfo->id());
387 3108 : IFMapNodeState *state = static_cast<IFMapNodeState *>(entry_state);
388 :
389 3108 : if (IsFeasible(node)) {
390 3082 : if (state == NULL) {
391 525 : state = new IFMapNodeState(node);
392 525 : entry->SetState(table, tinfo->id(), state);
393 : }
394 3082 : state->SetValid(node);
395 :
396 : // This is an add operation for nodes that are interested and
397 : // have not seen the advertisement.
398 3082 : BitSet add_set;
399 3082 : 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 3082 : BitSet rm_set;
404 3082 : rm_set.BuildComplement(state->advertised(), state->interest());
405 :
406 3082 : 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 3082 : bool move = UpdateAddChange(node, state, add_set, rm_set, change);
414 3082 : if (move) {
415 48 : MoveDependentLinks(state);
416 : }
417 :
418 : // For the subset of clients being removed, make sure that all
419 : // dependent links are removed before.
420 3082 : if (!rm_set.empty()) {
421 54 : RemoveDependentLinks(state, rm_set);
422 : }
423 3082 : UpdateRemove(node, state, rm_set);
424 3108 : } else if (state != NULL) {
425 : // Link deletes must preceed node deletes.
426 14 : ConfigChanged(node);
427 14 : state->ClearValid();
428 14 : if (!state->HasDependents()) {
429 : // enqueue delete.
430 14 : StateInterestReset(state, state->interest());
431 14 : EnqueueDelete(node, state);
432 14 : if (state->update_list().empty()) {
433 2 : DeleteStateIfAppropriate(table, entry, state);
434 : }
435 : }
436 : }
437 3108 : }
438 :
439 44 : static void MaybeNotifyOnLinkDelete(IFMapNode *node, IFMapNodeState *state) {
440 44 : if (node->IsDeleted() && !state->HasDependents()) {
441 14 : IFMapTable *table = node->table();
442 14 : table->Change(node);
443 : }
444 44 : }
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 2774 : void IFMapExporter::LinkTableExport(DBTablePartBase *partition,
451 : DBEntryBase *entry) {
452 2774 : IFMapLink *link = static_cast<IFMapLink *>(entry);
453 2774 : DBTable *table = static_cast<DBTablePartition *>(partition)->table();
454 2774 : const TableInfo *tinfo = Find(table);
455 2774 : DBState *entry_state = entry->GetState(table, tinfo->id());
456 2774 : IFMapLinkState *state = static_cast<IFMapLinkState *>(entry_state);
457 :
458 2774 : if (!entry->IsDeleted()) {
459 2744 : IFMapNodeState *s_left = NULL;
460 2744 : IFMapNodeState *s_right = NULL;
461 :
462 2744 : bool add_link = false;
463 2744 : bool force_update = false;
464 2744 : if (state == NULL) {
465 2124 : state = new IFMapLinkState(link);
466 2124 : entry->SetState(table, tinfo->id(), state);
467 2124 : s_left = NodeStateLocate(link->left());
468 2124 : s_right = NodeStateLocate(link->right());
469 2124 : 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 4372 : if (starts_with(link->left()->ToString(), "virtual-router") &&
484 2248 : (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 620 : if (state->IsValid() && !link->link_revival()) {
491 : // Link change
492 616 : assert(state->HasDependency());
493 616 : s_left = state->left();
494 616 : 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 2744 : std::unique_ptr<BitSet> ml, mr;
525 2744 : const BitSet *lset = MergeClientInterest(link->left(), s_left, &ml);
526 2744 : const BitSet *rset = MergeClientInterest(link->right(), s_right, &mr);
527 2744 : if (*lset != *rset) {
528 208 : walker_->LinkAdd(link, link->left(), *lset, link->right(), *rset);
529 : }
530 :
531 2744 : if (add_link) {
532 : // Establish dependency.
533 2126 : state->SetDependency(s_left, s_right);
534 2126 : state->SetValid();
535 : }
536 :
537 2744 : if (IsFeasible(link->left()) && IsFeasible(link->right())) {
538 : // Interest mask is the intersection of left and right nodes.
539 2744 : 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 2744 : BitSet add_set;
547 2744 : add_set.BuildComplement(state->interest(), state->advertised());
548 :
549 2744 : BitSet rm_set;
550 2744 : rm_set.BuildComplement(state->advertised(), state->interest());
551 :
552 2744 : if (!add_set.empty()) {
553 536 : ProcessAdjacentNode(link->left(), add_set, s_left, force_update);
554 536 : ProcessAdjacentNode(link->right(), add_set, s_right, force_update);
555 : }
556 :
557 2744 : UpdateAddChange(link, state, add_set, rm_set, false);
558 :
559 2744 : bool move = UpdateRemove(link, state, rm_set);
560 2744 : if (move) {
561 0 : MoveAdjacentNode(s_left);
562 0 : MoveAdjacentNode(s_right);
563 : }
564 2774 : } else if ((state != NULL) && state->IsValid()) {
565 22 : IFMapNode *left = link->LeftNode(server_->database());
566 22 : IFMapNodeState *s_left = state->left();
567 22 : assert((left != NULL) && (s_left != NULL));
568 22 : IFMapNode *right = link->RightNode(server_->database());
569 22 : IFMapNodeState *s_right = state->right();
570 22 : assert((right != NULL) && (s_right != NULL));
571 22 : BitSet interest = s_left->interest() & s_right->interest();
572 22 : StateInterestReset(state, state->interest());
573 :
574 22 : IFMAP_DEBUG(LinkOper, "LinkRemove", left->ToString(), right->ToString(),
575 : s_left->interest().ToString(), s_right->interest().ToString());
576 22 : walker_->LinkRemove(interest);
577 :
578 22 : state->RemoveDependency();
579 22 : state->ClearValid();
580 :
581 : // enqueue update.
582 22 : EnqueueDelete(link, state);
583 22 : if (state->update_list().empty()) {
584 4 : DeleteStateIfAppropriate(table, entry, state);
585 : }
586 :
587 22 : MaybeNotifyOnLinkDelete(left, s_left);
588 22 : MaybeNotifyOnLinkDelete(right, s_right);
589 22 : }
590 2774 : }
591 :
592 1112 : void IFMapExporter::StateUpdateOnDequeue(IFMapUpdate *update,
593 : const BitSet &dequeue_set,
594 : bool is_delete) {
595 1112 : DBTable *table = NULL;
596 1112 : DBEntry *db_entry = NULL;
597 :
598 1112 : IFMapState *state = NULL;
599 1112 : if (update->data().type == IFMapObjectPtr::NODE) {
600 552 : IFMapNode *node = update->data().u.node;
601 552 : db_entry = node;
602 552 : table = node->table();
603 560 : } else if (update->data().type == IFMapObjectPtr::LINK) {
604 560 : db_entry = update->data().u.link;
605 560 : table = link_table_;
606 : }
607 : state = static_cast<IFMapState *>(
608 1112 : db_entry->GetState(table, TableListenerId(table)));
609 1112 : 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 78 : BitSet adv_bits = state->advertised() & dequeue_set;
614 78 : StateAdvertisedReset(state, adv_bits);
615 78 : } else {
616 1034 : StateAdvertisedOr(state, dequeue_set);
617 : }
618 :
619 1112 : if (update->advertise().empty()) {
620 1112 : state->Remove(update);
621 1112 : if (update->IsDelete()) {
622 78 : DeleteStateIfAppropriate(table, db_entry, state);
623 : }
624 1112 : delete update;
625 : }
626 1112 : }
627 :
628 : struct IFMapUpdateDisposer {
629 8074 : explicit IFMapUpdateDisposer(IFMapUpdateQueue *queue) : queue_(queue) { }
630 34 : void operator()(IFMapUpdate *ptr) {
631 34 : queue_->Dequeue(ptr);
632 34 : boost::checked_delete(ptr);
633 34 : }
634 :
635 : private:
636 : IFMapUpdateQueue *queue_;
637 : };
638 :
639 8074 : void IFMapExporter::TableStateClear(DBTable *table,
640 : DBTable::ListenerId tsid) {
641 : DBTablePartition *partition = static_cast<DBTablePartition *>(
642 8074 : table->GetTablePartition(0));
643 :
644 8074 : IFMapUpdateDisposer disposer(queue());
645 8074 : for (DBEntry *entry = static_cast<DBEntry *>(partition->GetFirst()),
646 12154 : *next = NULL; entry != NULL; entry = next) {
647 4080 : next = static_cast<DBEntry *>(partition->GetNext(entry));
648 : IFMapState *state = static_cast<IFMapState *>(
649 4080 : entry->GetState(table, tsid));
650 4080 : if (state == NULL) {
651 0 : continue;
652 : }
653 4080 : entry->ClearState(table, tsid);
654 4080 : state->ClearAndDispose(disposer);
655 4080 : boost::checked_delete(state);
656 : }
657 :
658 8074 : }
659 :
660 176 : bool IFMapExporter::FilterNeighbor(IFMapNode *lnode, IFMapLink *link) {
661 176 : return walker_->FilterNeighbor(lnode, link);
662 : }
663 :
664 3096 : bool IFMapExporter::ConfigChanged(IFMapNode *node) {
665 3096 : IFMapNodeState *state = NodeStateLookup(node);
666 3096 : bool changed = false;
667 3096 : assert(state);
668 :
669 3096 : IFMapExporter::crc32type node_crc = node->GetConfigCrc();
670 3096 : if (state->crc() != node_crc) {
671 1856 : changed = true;
672 1856 : state->SetCrc(node_crc);
673 : }
674 :
675 3096 : return changed;
676 : }
677 :
678 78 : void IFMapExporter::AddClientConfigTracker(int index) {
679 234 : for (int tracker_type = 0; tracker_type < TT_END; ++tracker_type) {
680 156 : if (index >= (int)client_config_tracker_[tracker_type].size()) {
681 152 : client_config_tracker_[tracker_type].resize(index + 1, NULL);
682 : }
683 156 : assert(client_config_tracker_[tracker_type][index] == NULL);
684 156 : ConfigSet *set = new ConfigSet();
685 156 : client_config_tracker_[tracker_type][index] = set;
686 : }
687 78 : }
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 2312 : void IFMapExporter::UpdateClientConfigTracker(IFMapState *state,
699 : const BitSet& client_bits, bool add, TrackerType tracker_type) {
700 4638 : for (size_t pos = client_bits.find_first(); pos != BitSet::npos;
701 2326 : pos = client_bits.find_next(pos)) {
702 2326 : ConfigSet *set = client_config_tracker_[tracker_type].at(pos);
703 2326 : assert(set);
704 2326 : if (add) {
705 2116 : set->insert(state);
706 : } else {
707 210 : CsSz_t num = set->erase(state);
708 210 : assert(num == 1);
709 : }
710 : }
711 2312 : }
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 2938 : 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 2938 : bool add = true;
779 2938 : BitSet new_clients;
780 2938 : new_clients.BuildComplement(interest_bits, state->interest());
781 2938 : if (!new_clients.empty()) {
782 610 : 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 2938 : add = false;
788 2938 : BitSet old_clients;
789 2938 : old_clients.BuildComplement(state->interest(), interest_bits);
790 2938 : if (!old_clients.empty()) {
791 92 : UpdateClientConfigTracker(state, old_clients, add, INTEREST);
792 : }
793 :
794 2938 : state->SetInterest(interest_bits);
795 2938 : }
796 :
797 : // Add the node to the config-tracker of all clients that just became interested
798 : // in this node.
799 462 : void IFMapExporter::StateInterestOr(IFMapState *state,
800 : const BitSet& interest_bits) {
801 462 : bool add = true;
802 462 : UpdateClientConfigTracker(state, interest_bits, add, INTEREST);
803 462 : state->InterestOr(interest_bits);
804 462 : }
805 :
806 : // Remove the node from the config-tracker of all clients that are no longer
807 : // interested in this node.
808 36 : void IFMapExporter::StateInterestReset(IFMapState *state,
809 : const BitSet& interest_bits) {
810 36 : bool add = false;
811 36 : UpdateClientConfigTracker(state, interest_bits, add, INTEREST);
812 36 : state->InterestReset(interest_bits);
813 36 : }
814 :
815 : // Add the node to the config-tracker of all clients that just sent this node.
816 1034 : void IFMapExporter::StateAdvertisedOr(IFMapState *state,
817 : const BitSet& advertised_bits) {
818 1034 : bool add = true;
819 1034 : UpdateClientConfigTracker(state, advertised_bits, add, ADVERTISED);
820 1034 : state->AdvertisedOr(advertised_bits);
821 1034 : }
822 :
823 : // Remove the node from the config-tracker of all clients from whom the node
824 : // was withdrawn.
825 78 : void IFMapExporter::StateAdvertisedReset(IFMapState *state,
826 : const BitSet& advertised_bits) {
827 78 : bool add = false;
828 78 : UpdateClientConfigTracker(state, advertised_bits, add, ADVERTISED);
829 78 : state->AdvertisedReset(advertised_bits);
830 78 : }
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 :
|