diff --git a/src/testing/pv/pvaTestClient.h b/src/testing/pv/pvaTestClient.h index aaf5be8..6bd7546 100644 --- a/src/testing/pv/pvaTestClient.h +++ b/src/testing/pv/pvaTestClient.h @@ -17,6 +17,8 @@ class Monitor; class Configuration; }}//namespace epics::pvAccess +class TestClientProvider; + //! Information on get/put/rpc completion struct epicsShareClass TestOperation { @@ -109,11 +111,15 @@ class epicsShareClass TestClientChannel { struct Impl; std::tr1::shared_ptr impl; + friend class TestClientProvider; + + TestClientChannel(const std::tr1::shared_ptr& i) :impl(i) {} public: struct Options { short priority; std::string address; Options(); + bool operator<(const Options&) const; }; TestClientChannel() {} @@ -186,7 +192,8 @@ private: //! Central client context. class epicsShareClass TestClientProvider { - std::tr1::shared_ptr provider; + struct Impl; + std::tr1::shared_ptr impl; public: TestClientProvider(const std::string& providerName, @@ -195,8 +202,17 @@ public: //! Get a new Channel //! Does not block. + //! Never returns NULL. + //! Uses internal Channel cache. TestClientChannel connect(const std::string& name, const TestClientChannel::Options& conf = TestClientChannel::Options()); + + //! Remove from channel cache + bool disconnect(const std::string& name, + const TestClientChannel::Options& conf = TestClientChannel::Options()); + + //! Clear channel cache + void disconnect(); }; #endif // PVATESTCLIENT_H diff --git a/src/testing/pvaTestClient.cpp b/src/testing/pvaTestClient.cpp index 80dde2d..2608743 100644 --- a/src/testing/pvaTestClient.cpp +++ b/src/testing/pvaTestClient.cpp @@ -67,6 +67,11 @@ TestClientChannel::Options::Options() ,address() {} +bool TestClientChannel::Options::operator<(const Options& O) const +{ + return priority& i) :impl(i) {} @@ -138,14 +143,24 @@ std::tr1::shared_ptr TestClientChannel::getChannel() { return impl->channel; } +struct TestClientProvider::Impl +{ + pva::ChannelProvider::shared_pointer provider; + + epicsMutex mutex; + typedef std::map, std::tr1::weak_ptr > channels_t; + channels_t channels; +}; + TestClientProvider::TestClientProvider(const std::string& providerName, const std::tr1::shared_ptr& conf) - :provider(pva::ChannelProviderRegistry::clients()->createProvider(providerName, - conf ? conf : pva::ConfigurationBuilder() - .push_env() - .build())) + :impl(new Impl) { - if(!provider) + impl->provider = pva::ChannelProviderRegistry::clients()->createProvider(providerName, + conf ? conf : pva::ConfigurationBuilder() + .push_env() + .build()); + if(!impl->provider) THROW_EXCEPTION2(std::invalid_argument, providerName); } @@ -155,5 +170,37 @@ TestClientChannel TestClientProvider::connect(const std::string& name, const TestClientChannel::Options& conf) { - return TestClientChannel(provider, name, conf); + Guard G(impl->mutex); + Impl::channels_t::key_type K(name, conf); + Impl::channels_t::iterator it(impl->channels.find(K)); + if(it!=impl->channels.end()) { + // cache hit + std::tr1::shared_ptr chan(it->second.lock()); + if(chan) + return TestClientChannel(chan); + else + impl->channels.erase(it); // remove stale + } + // cache miss + TestClientChannel ret(impl->provider, name, conf); + impl->channels[K] = ret.impl; + return ret; +} + +bool TestClientProvider::disconnect(const std::string& name, + const TestClientChannel::Options& conf) +{ + Guard G(impl->mutex); + + Impl::channels_t::iterator it(impl->channels.find(std::make_pair(name, conf))); + bool found = it!=impl->channels.end(); + if(found) + impl->channels.erase(it); + return found; +} + +void TestClientProvider::disconnect() +{ + Guard G(impl->mutex); + impl->channels.clear(); }