void TopicManagerImpl::observerInit(const LogUpdate& llu, const TopicContentSeq& content) { Lock sync(*this); TraceLevelsPtr traceLevels = _instance->traceLevels(); if(traceLevels->topicMgr > 0) { Ice::Trace out(traceLevels->logger, traceLevels->topicMgrCat); out << "init"; for(TopicContentSeq::const_iterator p = content.begin(); p != content.end(); ++p) { out << " topic: " << _instance->communicator()->identityToString(p->id) << " subscribers: "; for(SubscriberRecordSeq::const_iterator q = p->records.begin(); q != p->records.end(); ++q) { if(q != p->records.begin()) { out << ","; } out << _instance->communicator()->identityToString(q->id); if(traceLevels->topicMgr > 1) { out << " endpoints: " << IceStormInternal::describeEndpoints(q->obj); } } } } // First we update the database state, and then we update our // internal state. for(;;) { try { DatabaseConnectionPtr connection = _connectionPool->newConnection(); TransactionHolder txn(connection); LLUWrapperPtr lluWrapper = _connectionPool->getLLU(connection); lluWrapper->put(llu); SubscribersWrapperPtr subscribersWrapper = _connectionPool->getSubscribers(connection); subscribersWrapper->clear(); for(TopicContentSeq::const_iterator p = content.begin(); p != content.end(); ++p) { SubscriberRecordKey key; key.topic = p->id; SubscriberRecord rec; rec.link = false; rec.cost = 0; subscribersWrapper->put(key, rec); for(SubscriberRecordSeq::const_iterator q = p->records.begin(); q != p->records.end(); ++q) { SubscriberRecordKey key; key.topic = p->id; key.id = q->id; subscribersWrapper->put(key, *q); } } txn.commit(); break; } catch(const DeadlockException&) { continue; } catch(const DatabaseException& ex) { halt(_instance->communicator(), ex); } } // We do this with two scans. The first runs through the topics // that we have and removes those not in the init list. The second // runs through the init list and either adds the ones that don't // exist, or updates those that do. map<string, TopicImplPtr>::iterator p = _topics.begin(); while(p != _topics.end()) { TopicContentSeq::const_iterator q; for(q = content.begin(); q != content.end(); ++q) { if(q->id == p->second->id()) { break; } } if(q == content.end()) { // Note that this destroy should not remove anything from // the database since we've already synced up the db // state. // // TODO: We could short circuit the database operations in // the topic by calling a third form of destroy. p->second->observerDestroyTopic(llu); _topics.erase(p++); } else { ++p; } } // Now run through the contents updating the topics that do exist, // and creating those that do not. for(TopicContentSeq::const_iterator q = content.begin(); q != content.end(); ++q) { string name = identityToTopicName(q->id); map<string, TopicImplPtr>::const_iterator p = _topics.find(name); if(p == _topics.end()) { installTopic(name, q->id, true, q->records); } else { p->second->update(q->records); } } // Clear the set of observers. _instance->observers()->clear(); }
void TopicManagerImpl::observerInit(const LogUpdate& llu, const TopicContentSeq& content) { Lock sync(*this); TraceLevelsPtr traceLevels = _instance->traceLevels(); if(traceLevels->topicMgr > 0) { Ice::Trace out(traceLevels->logger, traceLevels->topicMgrCat); out << "init"; for(TopicContentSeq::const_iterator p = content.begin(); p != content.end(); ++p) { out << " topic: " << _instance->communicator()->identityToString(p->id) << " subscribers: "; for(SubscriberRecordSeq::const_iterator q = p->records.begin(); q != p->records.end(); ++q) { if(q != p->records.begin()) { out << ","; } out << _instance->communicator()->identityToString(q->id); if(traceLevels->topicMgr > 1) { out << " endpoints: " << IceStormInternal::describeEndpoints(q->obj); } } } } // First we update the database state, and then we update our // internal state. try { IceDB::ReadWriteTxn txn(_instance->dbEnv()); _lluMap.put(txn, lluDbKey, llu); _subscriberMap.clear(txn); for(TopicContentSeq::const_iterator p = content.begin(); p != content.end(); ++p) { SubscriberRecordKey key; key.topic = p->id; SubscriberRecord rec; rec.link = false; rec.cost = 0; _subscriberMap.put(txn, key, rec); for(SubscriberRecordSeq::const_iterator q = p->records.begin(); q != p->records.end(); ++q) { SubscriberRecordKey key; key.topic = p->id; key.id = q->id; _subscriberMap.put(txn, key, *q); } } txn.commit(); } catch(const IceDB::LMDBException& ex) { logError(_instance->communicator(), ex); throw; // will become UnknownException in caller } // We do this with two scans. The first runs through the topics // that we have and removes those not in the init list. The second // runs through the init list and either adds the ones that don't // exist, or updates those that do. map<string, TopicImplPtr>::iterator p = _topics.begin(); while(p != _topics.end()) { TopicContentSeq::const_iterator q; for(q = content.begin(); q != content.end(); ++q) { if(q->id == p->second->id()) { break; } } if(q == content.end()) { // Note that this destroy should not remove anything from // the database since we've already synced up the db // state. // // TODO: We could short circuit the database operations in // the topic by calling a third form of destroy. p->second->observerDestroyTopic(llu); _topics.erase(p++); } else { ++p; } } // Now run through the contents updating the topics that do exist, // and creating those that do not. for(TopicContentSeq::const_iterator q = content.begin(); q != content.end(); ++q) { string name = identityToTopicName(q->id); map<string, TopicImplPtr>::const_iterator p = _topics.find(name); if(p == _topics.end()) { installTopic(name, q->id, true, q->records); } else { p->second->update(q->records); } } // Clear the set of observers. _instance->observers()->clear(); }