Beispiel #1
0
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);
    }
}
Beispiel #2
0
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);
}
Beispiel #3
0
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;
}
Beispiel #4
0
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);
        }
    }
}
Beispiel #5
0
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);
}
Beispiel #6
0
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);
}
Beispiel #7
0
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);
}
Beispiel #8
0
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);
}
Beispiel #9
0
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);
}
Beispiel #10
0
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);
}
Beispiel #11
0
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);
        }       
    }
}
Beispiel #12
0
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));
}
Beispiel #13
0
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 << ")";
    }
}