V4 CA Interfaces
CA Preliminary 2nd Generation Interfaces
C++ Namespace
All of the following will be in namespace ??????
Exceptions
The following base class will be used for all exceptions thrown by the library and or passed to exception callbacks to communicate asynchronous failure. The c++ dynamic_cast
will be used to test for a particular, concrete condition.
class diagnostic : public std::exception { public: enum severity_t { sevWarning, sevError, sevFatal }; virtual severity_t severity () const = 0; virtual context ( stringSegment & ) const = 0; };
Event Specifications
This interface will be used to specify a set of events.
class eventSpec { public: virtual bool operator == ( epicsGuard &, const eventSpec & ) const = 0; virtual bool compare ( epicsGuard &, const eventSpec & comparand, const eventSpec & select ) const = 0; virtual bool isEmpty ( epicsGuard & ) const = 0; virtual void show ( epicsGuard &, unsigned level ) const = 0; virtual void include ( epicsGuard &, const eventSpec & ) = 0; virtual void exclude ( epicsGuard &, const eventSpec & ) = 0; virtual void excludeAll ( epicsGuard & ) = 0; };
Subscription Event Specification
This interface is used to specify what events will and will not be present if a subscription update is triggered.
It is hoped that one subscription specification might be shared by several subscriptions in the server.
class subscrEventSpec { public: // subscrSpec is by default is a dont care w.r.t // the eventSpec space virtual void require ( epicsGuard &, const eventSpec & ) = 0; virtual void prohibit ( epicsGuard &, const eventSpec & ) = 0; virtual bool isMatch ( epicsGuard &, const eventSpec & ) const = 0; virtual void show ( epicsGuard &, unsigned level ) const = 0; };
Subscription Filter Specification
It is hoped that one subscription filter might be shared by several subscriptions installed into a service.
Should (can) a subscription spec be a property catalog?
class subscrFilterSpec { public: // updates no less frequently than specified virtual void setPeriodMinimum ( epicsGuard &, double periodInSeconds ) = 0; // updates no more frequently than specified virtual void setPeriodMaximum ( epicsGuard &, double periodInSeconds ) = 0; // delta between updates no less than specified virtual void setPercentChangeMinimum ( epicsGuard &, double percentChange ) = 0; // delta between updates no more than specified virtual void setPercentChangeMaximum ( epicsGuard &, double percentChange ) = 0; // when data acquisition system can pluck data at an offset virtual void setTriggerTimeOffset ( epicsGuard &, double delayInSeconds ) = 0; // number of intermediate values saved when busy // before replacing last entry on queue virtual void setEventQueueLength ( epicsGuard &, unsigned length ) = 0; // when supported by data store, specify // retrieval of values from the past virtual void setTimeWindow ( epicsGuard &, epicsTime & begin, epicsTime & end ) = 0; };
Write Request
class writeCompletionNotify { public: virtual void success ( epicsGuard & ) = 0; virtual void exception ( epicsGuard &, const diagnostic & ) = 0; };
class writeRequest { public: virtual void write ( epicsGuard &, const propertyCatalog & ) = 0; virtual void write ( epicsGuard &, const propertyCatalog &, writeCompletionNotify & ) = 0; virtual void cancel ( epicsGuard & ) = 0; virtual void show ( epicsGuard &, unsigned level ) const = 0; };
Read Request
class readCompletionNotify { public: virtual void success ( epicsGuard &, const propertyCatalog & ) = 0; virtual void exception ( epicsGuard &, const diagnostic & ) = 0; };
class readRequest { public: virtual void read ( epicsGuard &, readCompletionNotify & ) = 0; virtual void cancel ( epicsGuard & ) = 0; virtual void show ( epicsGuard &, unsigned level ) const = 0; };
Subscription Request
class subscriptionUpdateNotify { public: virtual void update ( epicsGuard &, const eventSpec &, const propertyCatalog & ) = 0; virtual void exception ( epicsGuard &, const diagnostic & ) = 0; };
class subscriptionRequest { virtual void subscribe ( epicsGuard &, subscriptionUpdateNotify & ) = 0; virtual void cancel ( epicsGuard & ) = 0; virtual void show ( epicsGuard &, unsigned level ) const = 0; };
Channel
The old interface assumed that when a channel is deleted then all related IO is also deleted. This requires an IO list in every channelwith attendent potential for redundant overhead. As a baseline, I intend to eliminate this practice, and therefore, a channel reference is not passed to the IO completion callback.
Users can subscribe for many different types of properties and events and therefore there might no longer be any need for native type/count returning functions in channel ( they can subscribe for "dimension", "bounds", "valueBehavior", "readAccess", "writeAccess", "confirmationRequested" properties ). This is also related to connect / disconnect notify callbacks specified when creating channel(they can subscribe for "state" property).
// I am actively considering abandoning this in favor of allowing // them to subscribe when the channel is created. class channelStateNotify { public: virtual void connectNotify () = 0; virtual void responsiveNotify () = 0; virtual void unresponsiveNotify () = 0; virtual void disconnectNotify () = 0; };
class channel { public: typedef unsigned priLevel_t; static const priLevel_t priorityMax; static const priLevel_t priorityMin;
virtual writeRequest & createWriteRequest ( epicsGuard &, const propertyCatalogRegistration & ) = 0; virtual void destroyWriteRequest ( epicsGuard &, writeRequest & ) = 0; virtual readRequest & createReadRequest ( epicsGuard &, const propertyCatalogRegistration & ) = 0; // receive property description list, but not all // property values (avoid large arrays)? Does this identify a // interface defect in data access virtual readRequest & createAllPropertiesReadRequest ( epicsGuard & ) = 0; virtual void destroyReadRequest epicsGuard &, readRequest & ) = 0; virtual subscriptionRequest & createSubscriptionRequest ( epicsGuard &, const propertyCatalogRegistration & ) = 0; virtual void destroySubscriptionRequest ( epicsGuard &, subscriptionRequest & ) = 0; virtual void name ( epicsGuard &, stringSegment & ) const = 0; virtual void show ( epicsGuard &, unsigned level ) const = 0; virtual bool isConnected ( epicsGuard & ) const = 0; virtual unsigned serviceName ( epicsGuard &, stringSegment & ) const () = 0; virtual void flush ( epicsGuard & ) = 0; // exceptions class badType : public diagnostic {}; class propertyValueOutOfBounds {} : public diagnostic {}; class invalidEventSelection {} : public diagnostic {}; class noWriteAccess {} : public diagnostic {}; class noReadAccess {} : public diagnostic {}; class unsupportedByService {} : public diagnostic {}; class requestTimedOut {} : public diagnostic {}; class unresponsive {} : public diagnostic {}; class disconnect {} : public diagnostic {}; }
Channel Factory
class channelFactory { virtual cacChannel & createChannel ( epicsGuard &, const stringSegment & name, channelStateNotify &, cacChannel::priLevel_t = cacChannel::priorityMin ) = 0; virtual cacChannel & destroyChannel ( epicsGuard &, cacChannel & ) = 0; // exceptions class priorityOutOfBounds {} : public diagnostic {}; };
Event Specification Factory
class eventSpecFactory { virtual eventSpec & createEventSpec ( epicsGuard &, const stringSegment & eventName ) = 0; virtual eventSpec & createChannelTriggeredEventSpec ( epicsGuard &, const stringSegment & triggerExpression ) = 0; virtual void destroyEventSpec ( epicsGuard &, eventSpec & ) = 0; };
class subscrSpecFactory { virtual subscrFilterSpec & createSubscrFilterSpec ( epicsGuard & ) = 0; virtual void destroySubscrFilterSpec ( epicsGuard &, subscrFilterSpec & ) = 0; virtual subscrEventSpec & createSubscrEventSpec ( epicsGuard & ) = 0; virtual void destroySubscrEventSpec ( epicsGuard &, subscrEventSpec & ) = 0; };
Property Catalog Registration
class propertyCatalogRegistration;
Perhaps its a defect that to register a data structure with a large array we must present a propertyCatalog which has reserved that much space, and therefore should a propertyCatalog
have a "traverseStructure()" interface ?
class propertyCatalogRegistry { virtual class propertyCatalogRegistration & createRegistration ( epicsGuard &, const propertyCatalog & ) = 0; virtual void destroyRegistration ( epicsGuard &, propertyCatalogRegistration & ) = 0; };
Name Service Interface
A name service might also have subscription capabilities?
How does a name service differ from an ordinary service where each channel has an address property, and subordinate properties conveying the various different address formats? How do we accomodate a failover service address. Is this a subordinate property?
class nameLookupNotify { virtual void success ( epicsGuard &, const propertyCatalog & address, const stringSegment & match, bool last ) = 0; virtual void exception ( epicsGuard &, const diagnostic & ) = 0; };
class nameLookupRequest { virtual void lookup ( epicsGuard &, const stringSegment & name, const nameLookupNotify & ) = 0; virtual void cancel ( epicsGuard & ) = 0; virtual void show ( epicsGuard &, unsigned level ) const; };
class nameService { virtual nameLookupRequest & createNameLookupRequest ( epicsGuard & ) = 0; // not supported by all name services? virtual nameLookupRequest & createRegularExpressionNameLookupRequest ( epicsGuard & ) = 0; virtual void destroyNameLookupRequest ( epicsGuard &, nameRequest & ) = 0; };
Client Context
The name "clientContext" should possibly be changed.
class clientContext : public eventSpecFactory, public subscrSpecFactory, public propertyCatalogRegistry { };
Service
A service might failover to a backup service, but currently there appears to be no need to reveal this in public interfaces?
The relation between a name service, channelFactory, service, and genericService to each other are areas which are under active consideration.
class service : public channelFactory, public nameService { virtual void flush ( epicsGuard & ) = 0; virtual void show ( epicsGuard &, unsigned level ) const = 0; // exceptions class disconnect {} : public diagnostic {}; };
Server
This interface is passed to the service factory.
class server : public eventSpecFactory { public: virtual void serviceExceptionNotify ( epicsGuard &, diagnostic & ) = 0; // for attaching thread private variables // in preparation for asynchronous callback // from a service thread virtual void serviceThreadInitiateNotify ( epicsGuard & ) = 0; virtual void serviceThreadExitNotify ( epicsGuard & ) = 0; // for implementing non-preemptive callback // **** probably not needed if guard is based on a pure virtual mutex interface // **** and given that they can use thread private variables //virtual void serviceCallbackProcessingInitiateNotify ( // epicsGuard & ) = 0; //virtual void serviceCallbackProcessingCompleteNotify ( // epicsGuard & ) = 0; };
Generic Service
A genericService
is a special service granting homogenous access to multiple underlying services of different types. When an application creates a channel they might not need to know what service is the factory for the channel. Likewise, when they delete a channel they would not need to remember that the channel is recycled with the same service that created it. A genericService
will attempt to initially locate the appropriate service, and should a connected service disconnect, attempt to transparently find a new one. A genericService
might hide the need to recreate a channel or an IO request when a service disconnects from client applications. This would be accomplished by creating a channel that is a handle to a service specific channel, and an IO request that is a handle to a service specific IO request.
class genericServiceFactory { public: virtual service & createGenericService ( epicsGuard &, epicsMutex &, serviceStateChangeNotify &, serviceLocator & ) = 0; virtual void destroyGenericService ( epicsGuard &, service & ) = 0; };
Network Server/Service Interfaces
These interfaces may be accessed with the dynamic_cast
operator
class beaconGenerator { public: virtual void generateBeaconAnomaly ( epicsGuard & ) = 0; };
class beaconAnomalyDetectorStateChangeNotify { public: virtual unsigned beaconAnomlyDetectNotify ( epicsGuard &, const propertyCatalog & ) const = 0; };
// only access to this will be using dynamic_cast class networkChannelDiagnostics { virtual unsigned searchAttempts ( epicsGuard & ) const = 0; };
// only access to this will be using dynamic_cast class networkCircuitDiagnostics { virtual double estimatedBeaconPeriod ( epicsGuard & ) const; // negative DBL_MAX if UKN virtual double receiveWatchdogDelayToExperation ( epicsGuard & ) const; // negative DBL_MAX if UKN virtual unsigned protocolRevision ( epicsGuard & ) const; };
only access to this will be using dynamic_cast
class serviceDiagnostics { public: epicsShareFunc unsigned subscriptionEventsPosted () const; epicsShareFunc unsigned subscriptionEventsProcessed () const; };
only access to this will be using dynamic_cast
class beaconAnomalyDetectorDiagnostics { public: virtual unsigned beaconAnomliesDetected ( epicsGuard & ) const = 0; };
Oustanding Issues
Locking issues. To what degree are we forcing everything to use the same lock? What will be the minimal locking granularity?
How much of the class name should be in the pure virtual function name for uniqueness?
Unification with the PCAS interface requires more work. In particulant posting and event registration.
What type of string interface will be used, and how will this be unified with the database?