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