void TopicImpl::removeSubscribers(const Ice::IdentitySeq& ids) { // First update the database LogUpdate llu; bool found = false; try { IceDB::ReadWriteTxn txn(_instance->dbEnv()); for(Ice::IdentitySeq::const_iterator id = ids.begin(); id != ids.end(); ++id) { SubscriberRecordKey key; key.topic = _id; key.id = *id; if(_subscriberMap.del(txn, key)) { found = true; } } if(found) { llu = getIncrementedLLU(txn, _lluMap); txn.commit(); } else { txn.rollback(); } } catch(const IceDB::LMDBException& ex) { logError(_instance->communicator(), ex); throw; // will become UnknownException in caller } if(found) { // Then remove the subscriber from the subscribers list. Its // possible that some of these subscribers have already been // removed (consider, for example, a concurrent reap call from two // replicas on the same subscriber). To avoid sending unnecessary // observer updates keep track of the observers that are actually // removed. for(Ice::IdentitySeq::const_iterator id = ids.begin(); id != ids.end(); ++id) { vector<SubscriberPtr>::iterator p = find(_subscribers.begin(), _subscribers.end(), *id); if(p != _subscribers.end()) { (*p)->destroy(); _subscribers.erase(p); } } _instance->observers()->removeSubscriber(llu, _name, ids); } }
void TopicImpl::unsubscribe(const Ice::ObjectPrx& subscriber) { TraceLevelsPtr traceLevels = _instance->traceLevels(); if(!subscriber) { if(traceLevels->topic > 0) { Ice::Trace out(traceLevels->logger, traceLevels->topicCat); out << "unsubscribe with null subscriber."; } return; } Ice::Identity id = subscriber->ice_getIdentity(); if(traceLevels->topic > 0) { Ice::Trace out(traceLevels->logger, traceLevels->topicCat); out << _name << ": unsubscribe: " << _instance->communicator()->identityToString(id); if(traceLevels->topic > 1) { out << " endpoints: " << IceStormInternal::describeEndpoints(subscriber); trace(out, _instance, _subscribers); } } IceUtil::Mutex::Lock sync(_subscribersMutex); Ice::IdentitySeq ids; ids.push_back(id); removeSubscribers(ids); }
Ice::IdentitySeq TopicImpl::getSubscribers() const { IceUtil::Mutex::Lock sync(_subscribersMutex); Ice::IdentitySeq subscribers; for(vector<SubscriberPtr>::const_iterator p = _subscribers.begin(); p != _subscribers.end(); ++p) { subscribers.push_back((*p)->id()); } return subscribers; }
void TopicImpl::observerRemoveSubscriber(const LogUpdate& llu, const Ice::IdentitySeq& ids) { TraceLevelsPtr traceLevels = _instance->traceLevels(); if(traceLevels->topic > 0) { Ice::Trace out(traceLevels->logger, traceLevels->topicCat); out << _name << ": remove replica observer: "; for(Ice::IdentitySeq::const_iterator id = ids.begin(); id != ids.end(); ++id) { if(id != ids.begin()) { out << ","; } out << _instance->communicator()->identityToString(*id); } out << " llu: " << llu.generation << "/" << llu.iteration; } IceUtil::Mutex::Lock sync(_subscribersMutex); // First remove from the database. try { IceDB::ReadWriteTxn txn(_instance->dbEnv()); for(Ice::IdentitySeq::const_iterator id = ids.begin(); id != ids.end(); ++id) { SubscriberRecordKey key; key.topic = _id; key.id = *id; _subscriberMap.del(txn, key); } _lluMap.put(txn, lluDbKey, llu); txn.commit(); } catch(const IceDB::LMDBException& ex) { logError(_instance->communicator(), ex); throw; // will become UnknownException in caller } // Then remove the subscriber from the subscribers list. If the // subscriber had a local failure and was removed from the // subscriber list it could already be gone. That's not a problem. for(Ice::IdentitySeq::const_iterator id = ids.begin(); id != ids.end(); ++id) { vector<SubscriberPtr>::iterator p = find(_subscribers.begin(), _subscribers.end(), *id); if(p != _subscribers.end()) { (*p)->destroy(); _subscribers.erase(p); } } }
Glacier2::SessionPrx AdminSessionFactory::createGlacier2Session(const string& sessionId, const Glacier2::SessionControlPrx& ctl) { assert(_servantManager); AdminSessionIPtr session = createSessionServant(sessionId); Ice::ObjectPrx proxy = session->_register(_servantManager, 0); int timeout = 0; if(ctl) { try { if(_filters) { Ice::IdentitySeq ids; Ice::Identity queryId; queryId.category = _database->getInstanceName(); queryId.name = "Query"; ids.push_back(queryId); _servantManager->setSessionControl(session, ctl, ids); } timeout = ctl->getSessionTimeout(); } catch(const Ice::LocalException& e) { session->destroy(Ice::Current()); Ice::Warning out(_database->getTraceLevels()->logger); out << "Failed to callback Glacier2 session control object:\n" << e; Glacier2::CannotCreateSessionException ex; ex.reason = "internal server error"; throw ex; } } _reaper->add(new SessionReapable<AdminSessionI>(_database->getTraceLevels()->logger, session), timeout); return Glacier2::SessionPrx::uncheckedCast(proxy); }
void TopicImpl::removeSubscribers(const Ice::IdentitySeq& ids) { Ice::IdentitySeq removed; // First remove the subscriber from the subscribers list. Its // possible that some of these subscribers have already been // removed (consider, for example, a concurrent reap call from two // replicas on the same subscriber). To avoid sending unnecessary // observer updates keep track of the observers that are actually // removed. for(Ice::IdentitySeq::const_iterator id = ids.begin(); id != ids.end(); ++id) { vector<SubscriberPtr>::iterator p = find(_subscribers.begin(), _subscribers.end(), *id); if(p != _subscribers.end()) { (*p)->destroy(); _subscribers.erase(p); removed.push_back(*id); } } // If there is no further work to do we are done. if(removed.empty()) { return; } // Next update the database and send the notification to any // slaves. LogUpdate llu; try { IceDB::ReadWriteTxn txn(_instance->dbEnv()); for(Ice::IdentitySeq::const_iterator id = ids.begin(); id != ids.end(); ++id) { SubscriberRecordKey key; key.topic = _id; key.id = *id; _subscriberMap.del(txn, key); } llu = getIncrementedLLU(txn, _lluMap); txn.commit(); } catch(const IceDB::LMDBException& ex) { halt(_instance->communicator(), ex); } _instance->observers()->removeSubscriber(llu, _name, ids); }
void TopicImpl::reap(const Ice::IdentitySeq& ids) { IceUtil::Mutex::Lock sync(_subscribersMutex); TraceLevelsPtr traceLevels = _instance->traceLevels(); if(traceLevels->topic > 0) { Ice::Trace out(traceLevels->logger, traceLevels->topicCat); out << _name << ": reap "; for(Ice::IdentitySeq::const_iterator p = ids.begin(); p != ids.end() ; ++p) { if(p != ids.begin()) { out << ","; } out << _instance->communicator()->identityToString(*p); } } removeSubscribers(ids); }
void TopicImpl::unlink(const TopicPrx& topic) { IceUtil::Mutex::Lock sync(_subscribersMutex); if(_destroyed) { throw Ice::ObjectNotExistException(__FILE__, __LINE__); } Ice::Identity id = topic->ice_getIdentity(); vector<SubscriberPtr>::const_iterator p = find(_subscribers.begin(), _subscribers.end(), id); if(p == _subscribers.end()) { string name = identityToTopicName(id); TraceLevelsPtr traceLevels = _instance->traceLevels(); if(traceLevels->topic > 0) { Ice::Trace out(traceLevels->logger, traceLevels->topicCat); out << _name << ": unlink " << name << " failed - not linked"; } NoSuchLink ex; ex.name = name; throw ex; } TraceLevelsPtr traceLevels = _instance->traceLevels(); if(traceLevels->topic > 0) { Ice::Trace out(traceLevels->logger, traceLevels->topicCat); out << _name << " unlink " << _instance->communicator()->identityToString(id); } Ice::IdentitySeq ids; ids.push_back(id); removeSubscribers(ids); }
void TopicImpl::subscribe(const QoS& origQoS, const Ice::ObjectPrx& obj) { Ice::Identity id = obj->ice_getIdentity(); TraceLevelsPtr traceLevels = _instance->traceLevels(); QoS qos = origQoS; if(traceLevels->topic > 0) { Ice::Trace out(traceLevels->logger, traceLevels->topicCat); out << _name << ": subscribe: " << _instance->communicator()->identityToString(id); if(traceLevels->topic > 1) { out << " endpoints: " << IceStormInternal::describeEndpoints(obj) << " QoS: "; for(QoS::const_iterator p = qos.begin(); p != qos.end() ; ++p) { if(p != qos.begin()) { out << ','; } out << '[' << p->first << "," << p->second << ']'; } out << " subscriptions: "; trace(out, _instance, _subscribers); } } string reliability = "oneway"; { QoS::iterator p = qos.find("reliability"); if(p != qos.end()) { reliability = p->second; qos.erase(p); } } Ice::ObjectPrx newObj = obj; if(reliability == "batch") { if(newObj->ice_isDatagram()) { newObj = newObj->ice_batchDatagram(); } else { newObj = newObj->ice_batchOneway(); } } else if(reliability == "twoway") { newObj = newObj->ice_twoway(); } else if(reliability == "twoway ordered") { qos["reliability"] = "ordered"; newObj = newObj->ice_twoway(); } else // reliability == "oneway" { if(reliability != "oneway" && traceLevels->subscriber > 0) { Ice::Trace out(traceLevels->logger, traceLevels->subscriberCat); out << reliability <<" mode not understood."; } if(!newObj->ice_isDatagram()) { newObj = newObj->ice_oneway(); } } IceUtil::Mutex::Lock sync(_subscribersMutex); SubscriberRecord record; record.id = id; record.obj = newObj; record.theQoS = qos; record.topicName = _name; record.link = false; record.cost = 0; LogUpdate llu; vector<SubscriberPtr>::iterator p = find(_subscribers.begin(), _subscribers.end(), record.id); if(p != _subscribers.end()) { // If we already have this subscriber remove it from our // subscriber list and remove it from the database. (*p)->destroy(); _subscribers.erase(p); for(;;) { try { DatabaseConnectionPtr connection = _connectionPool->newConnection(); TransactionHolder txn(connection); SubscriberRecordKey key; key.topic = _id; key.id = record.id; SubscribersWrapperPtr subscribersWrapper = _connectionPool->getSubscribers(connection); subscribersWrapper->erase(key); LLUWrapperPtr lluWrapper = _connectionPool->getLLU(connection); llu = lluWrapper->get(); llu.iteration++; lluWrapper->put(llu); txn.commit(); break; } catch(const DeadlockException&) { continue; } catch(const DatabaseException& ex) { halt(_instance->communicator(), ex); } } Ice::IdentitySeq ids; ids.push_back(id); _instance->observers()->removeSubscriber(llu, _name, ids); } SubscriberPtr subscriber = Subscriber::create(_instance, record); for(;;) { try { DatabaseConnectionPtr connection = _connectionPool->newConnection(); TransactionHolder txn(connection); SubscriberRecordKey key; key.topic = _id; key.id = subscriber->id(); SubscribersWrapperPtr subscribersWrapper = _connectionPool->getSubscribers(connection); subscribersWrapper->put(key, record); // Update the LLU. LLUWrapperPtr lluWrapper = _connectionPool->getLLU(connection); llu = lluWrapper->get(); llu.iteration++; lluWrapper->put(llu); txn.commit(); break; } catch(const DeadlockException&) { continue; } catch(const DatabaseException& ex) { halt(_instance->communicator(), ex); } } _subscribers.push_back(subscriber); _instance->observers()->addSubscriber(llu, _name, record); }
void TopicImpl::removeSubscribers(const Ice::IdentitySeq& ids) { Ice::IdentitySeq removed; // First remove the subscriber from the subscribers list. Its // possible that some of these subscribers have already been // removed (consider, for example, a concurrent reap call from two // replicas on the same subscriber). To avoid sending unnecessary // observer updates keep track of the observers that are actually // removed. for(Ice::IdentitySeq::const_iterator id = ids.begin(); id != ids.end(); ++id) { vector<SubscriberPtr>::iterator p = find(_subscribers.begin(), _subscribers.end(), *id); if(p != _subscribers.end()) { (*p)->destroy(); _subscribers.erase(p); removed.push_back(*id); } } // If there is no further work to do we are done. if(removed.empty()) { return; } // Next update the database and send the notification to any // slaves. LogUpdate llu; for(;;) { try { DatabaseConnectionPtr connection = _connectionPool->newConnection(); TransactionHolder txn(connection); for(Ice::IdentitySeq::const_iterator id = ids.begin(); id != ids.end(); ++id) { SubscriberRecordKey key; key.topic = _id; key.id = *id; SubscribersWrapperPtr subscribersWrapper = _connectionPool->getSubscribers(connection); subscribersWrapper->erase(key); } LLUWrapperPtr lluWrapper = _connectionPool->getLLU(connection); llu = lluWrapper->get(); llu.iteration++; lluWrapper->put(llu); txn.commit(); break; } catch(const DeadlockException&) { continue; } catch(const DatabaseException& ex) { halt(_instance->communicator(), ex); } } _instance->observers()->removeSubscriber(llu, _name, ids); }
void TopicImpl::observerRemoveSubscriber(const LogUpdate& llu, const Ice::IdentitySeq& ids) { TraceLevelsPtr traceLevels = _instance->traceLevels(); if(traceLevels->topic > 0) { Ice::Trace out(traceLevels->logger, traceLevels->topicCat); out << _name << ": remove replica observer: "; for(Ice::IdentitySeq::const_iterator id = ids.begin(); id != ids.end(); ++id) { if(id != ids.begin()) { out << ","; } out << _instance->communicator()->identityToString(*id); } out << " llu: " << llu.generation << "/" << llu.iteration; } IceUtil::Mutex::Lock sync(_subscribersMutex); // Remove the subscriber from the subscribers list. If the // subscriber had a local failure and was removed from the // subscriber list it could already be gone. That's not a problem. for(Ice::IdentitySeq::const_iterator id = ids.begin(); id != ids.end(); ++id) { vector<SubscriberPtr>::iterator p = find(_subscribers.begin(), _subscribers.end(), *id); if(p != _subscribers.end()) { (*p)->destroy(); _subscribers.erase(p); } } // Next remove from the database. for(;;) { try { DatabaseConnectionPtr connection = _connectionPool->newConnection(); TransactionHolder txn(connection); for(Ice::IdentitySeq::const_iterator id = ids.begin(); id != ids.end(); ++id) { SubscriberRecordKey key; key.topic = _id; key.id = *id; SubscribersWrapperPtr subscribersWrapper = _connectionPool->getSubscribers(connection); subscribersWrapper->erase(key); } LLUWrapperPtr lluWrapper = _connectionPool->getLLU(connection); lluWrapper->put(llu); txn.commit(); break; } catch(const DeadlockException&) { continue; } catch(const DatabaseException& ex) { halt(_instance->communicator(), ex); } } }
void TopicImpl::publish(bool forwarded, const EventDataSeq& events) { TopicInternalPrx masterInternal; Ice::Long generation = -1; Ice::IdentitySeq reap; { // Use cached reads. CachedReadHelper unlock(_instance->node(), __FILE__, __LINE__); // // Copy of the subscriber list so that event publishing can occur // in parallel. // vector<SubscriberPtr> copy; { IceUtil::Mutex::Lock sync(_subscribersMutex); if(_observer) { if(forwarded) { _observer->forwarded(); } else { _observer->published(); } } copy = _subscribers; } // // Queue each event, gathering a list of those subscribers that // must be reaped. // for(vector<SubscriberPtr>::const_iterator p = copy.begin(); p != copy.end(); ++p) { if(!(*p)->queue(forwarded, events) && (*p)->reap()) { reap.push_back((*p)->id()); } } // If there are no subscribers in error then we're done. if(reap.empty()) { return; } if(!unlock.getMaster()) { IceUtil::Mutex::Lock sync(_subscribersMutex); removeSubscribers(reap); return; } masterInternal = TopicInternalPrx::uncheckedCast(unlock.getMaster()->ice_identity(_id)); generation = unlock.generation(); } // Tell the master to reap this set of subscribers. This is an // AMI invocation so it shouldn't block the caller (in the // typical case) we do it outside of the mutex lock for // performance reasons. // // We must release the cached lock before calling this as the AMI // call may raise an exception in the caller (that is directly // call ice_exception) which calls recover() on the node which // would result in a deadlock since the node is locked. masterInternal->begin_reap(reap, newCallback_TopicInternal_reap(new TopicInternalReapCB(_instance, generation), &TopicInternalReapCB::exception)); }
void ServerEntry::released(const SessionIPtr& session) { if(!_loaded.get() && !_load.get()) { return; } ServerDescriptorPtr desc = _loaded.get() ? _loaded->descriptor : _load->descriptor; // // If the server has the session activation mode, we re-load the // server on the node as its deployment might have changed (it's // possible to use ${session.*} variable with server with the // session activation mode. Synchronizing the server will also // shutdown the server on the node. // if(desc->activation == "session") { _updated = true; if(!_load.get()) { _load.reset(_loaded.release()); } _load->sessionId = ""; _session = 0; } TraceLevelsPtr traceLevels = _cache.getTraceLevels(); Glacier2::IdentitySetPrx identitySet = session->getGlacier2IdentitySet(); Glacier2::StringSetPrx adapterIdSet = session->getGlacier2AdapterIdSet(); if(identitySet && adapterIdSet) { ServerHelperPtr helper = createHelper(desc); multiset<string> adapterIds; multiset<Ice::Identity> identities; helper->getIds(adapterIds, identities); try { // // SunCC won't accept the following: // // ctl->adapterIds()->remove(Ice::StringSeq(adapterIds.begin(), adapterIds.end())); // ctl->identities()->remove(Ice::IdentitySeq(identities.begin(), identities.end())); // Ice::StringSeq adapterIdSeq; for(multiset<string>::iterator p = adapterIds.begin(); p != adapterIds.end(); ++p) { adapterIdSeq.push_back(*p); } Ice::IdentitySeq identitySeq; for(multiset<Ice::Identity>::iterator q = identities.begin(); q != identities.end(); ++q) { identitySeq.push_back(*q); } adapterIdSet->remove(adapterIdSeq); identitySet->remove(identitySeq); } catch(const Ice::LocalException& ex) { if(traceLevels && traceLevels->server > 0) { Ice::Trace out(traceLevels->logger, traceLevels->serverCat); out << "couldn't remove Glacier2 filters for server `" << _id << "' allocated by `"; out << session->getId() << ":\n" << ex; } } } if(traceLevels && traceLevels->server > 1) { Ice::Trace out(traceLevels->logger, traceLevels->serverCat); out << "server `" << _id << "' released by `" << session->getId() << "' (" << _count << ")"; } }