Skip to content

Latest commit

 

History

History
128 lines (83 loc) · 3.96 KB

implementation.md

File metadata and controls

128 lines (83 loc) · 3.96 KB

PV Access to PV Access protocol gateway (aka. proxy)

Theory of Operation

The GW maintains a Channel Cache, which is a dictionary of client side channels (shared_ptrepics::pvAccess::Channel instances) in the NEVER_CONNECTED or CONNECTED states.

Each entry also has an activity flag and reference count.

The activity flag is set each time the server side receives a search request for a PV.

The reference count is incremented for each active server side channel.

Periodically the cache is iterated and any client channels with !activity and count==0 are dropped. In addition the activity flag is unconditionally cleared.

Name search handling

The server side listens for name search requests. When a request is received the channel cache is searched. If no entry exists, then one is created and no further action is taken. If an entry exists, but the client channel is not connected, then it's activiy flag is set and no further action is taken. If a connected entry exists, then an affirmative response is sent to the requester.

When a channel create request is received, the channel cache is checked. If no connected entry exists, then the request is failed.

Structure associations and ownership

struct ServerContextImpl {
  vector<shared_ptr<ChannelProvider> > providers; // GWServerChannelProvider
};

struct GWServerChannelProvider : public pva::ChannelProvider {
  ChannelCache cache;
};

struct ChannelCache {
  weak_pointer<ChannelProvider> server;
  map<string, shared_ptr<ChannelCacheEntry> > entries;

  epicsMutex cacheLock; // guards entries
};

struct ChannelCacheEntry {
  ChannelCache * const cache;
  shared_ptr<Channel> channel; // InternalChannelImpl
  set<GWChannel*> interested;
};

struct InternalChannelImpl { // PVA client channel
  shared_ptr<ChannelRequester> requester; // ChannelCacheEntry::CRequester
};

struct ChannelCacheEntry::CRequester {
  weak_ptr<ChannelCacheEntry> chan;
};

struct GWChannel {
  shared_ptr<ChannelCacheEntry> entry;
  shared_ptr<ChannelRequester> requester; // pva::ServerChannelRequesterImpl
};

struct pva::ServerChannelImpl : public pva::ServerChannel
{
    shared_ptr<Channel> channel; // GWChannel
};

Threading and Locking

ServerContextImpl BeaconServerStatusProvider ?

2x BlockingUDPTransport (bcast and mcast, one thread each) calls ChannelProvider::channelFind with no locks held

BlockingTCPAcceptor BlockingServerTCPTransportCodec -> BlockingAbstractCodec (send and recv threads) ServerResponseHandler calls ChannelProvider::channelFind calls ChannelProvider::createChannel calls Channel::create*

InternalClientContextImpl

2x BlockingUDPTransport (bcast listener and ucast tx/rx, one thread each)

BlockingTCPConnector BlockingClientTCPTransportCodec -> BlockingSocketAbstractCodec (send and recv threads) ClientResponseHandler calls MonitorRequester::monitorEvent with MonitorStrategyQueue::m_mutex locked

TODO

ServerChannelRequesterImpl::channelStateChange() - placeholder, needs implementation

the send queue in BlockingAbstractCodec has no upper bound

Monitor

ServerChannelImpl calls GWChannel::createMonitor with a MonitorRequester which is ServerMonitorRequesterImpl

The MonitorRequester is given a Monitor which is GWMonitor

GWChannel calls InternalChannelImpl::createMonitor with a GWMonitorRequester

GWMonitorRequester is given a Monitor which is ChannelMonitorImpl

Updates originate from the client side, entering as an argument when GWMonitorRequester::monitorEvent is called, and exiting to the server when passed as an argument of a call to ServerMonitorRequesterImpl::monitorEvent.

When an update is added to the monitor queue ServerMonitorRequesterImpl::monitorEvent is called, as notification that the queue is not empty, which enqueues itself for transmission. The associated TCP sender thread later calls ServerMonitorRequesterImpl::send(), which calls GWMonitor::poll() to de-queue an event, which it encodes to the senders bytebuffer. It then reschedules itself.