<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>https://wiki-ext.aps.anl.gov/epics/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=JeffHill</id>
	<title>EPICSWIKI - User contributions [en]</title>
	<link rel="self" type="application/atom+xml" href="https://wiki-ext.aps.anl.gov/epics/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=JeffHill"/>
	<link rel="alternate" type="text/html" href="https://wiki-ext.aps.anl.gov/epics/index.php?title=Special:Contributions/JeffHill"/>
	<updated>2026-07-14T11:01:41Z</updated>
	<subtitle>User contributions</subtitle>
	<generator>MediaWiki 1.36.1</generator>
	<entry>
		<id>https://wiki-ext.aps.anl.gov/epics/index.php?title=V4_CA_Interfaces&amp;diff=2708</id>
		<title>V4 CA Interfaces</title>
		<link rel="alternate" type="text/html" href="https://wiki-ext.aps.anl.gov/epics/index.php?title=V4_CA_Interfaces&amp;diff=2708"/>
		<updated>2005-07-07T23:16:35Z</updated>

		<summary type="html">&lt;p&gt;JeffHill: /* Channel */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= CA Preliminary 2nd Generation Interfaces =&lt;br /&gt;
&lt;br /&gt;
== C++ Namespace ==&lt;br /&gt;
&lt;br /&gt;
All of the following will be in namespace ??????&lt;br /&gt;
&lt;br /&gt;
== Exceptions ==&lt;br /&gt;
&lt;br /&gt;
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++ &amp;lt;code&amp;gt;dynamic_cast&amp;lt;/code&amp;gt;will be used to test for a particular, concrete condition.&lt;br /&gt;
&lt;br /&gt;
 class diagnostic : public std::exception {&lt;br /&gt;
 public: &lt;br /&gt;
     enum severity_t { &lt;br /&gt;
         sevWarning, sevError, sevFatal };&lt;br /&gt;
     virtual severity_t severity () const = 0;&lt;br /&gt;
     virtual context ( stringSegment &amp;amp; ) const = 0;&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
== Event Specifications ==&lt;br /&gt;
&lt;br /&gt;
This interface will be used to specify a set of events.&lt;br /&gt;
&lt;br /&gt;
 class eventSpec {&lt;br /&gt;
 public:&lt;br /&gt;
     virtual bool operator == ( &lt;br /&gt;
         epicsGuard &amp;amp;, const eventSpec &amp;amp; ) const = 0;    &lt;br /&gt;
     virtual bool compare ( &lt;br /&gt;
         epicsGuard &amp;amp;, &lt;br /&gt;
         const eventSpec &amp;amp; comparand, &lt;br /&gt;
         const eventSpec &amp;amp; select ) const = 0;    &lt;br /&gt;
     virtual bool isEmpty ( &lt;br /&gt;
         epicsGuard &amp;amp; ) const = 0;&lt;br /&gt;
     virtual void show (        &lt;br /&gt;
         epicsGuard &amp;amp;, unsigned level ) const = 0;    &lt;br /&gt;
     virtual void include (&lt;br /&gt;
         epicsGuard &amp;amp;, const eventSpec &amp;amp; ) = 0;    &lt;br /&gt;
     virtual void exclude ( &lt;br /&gt;
         epicsGuard &amp;amp;, const eventSpec &amp;amp; ) = 0;    &lt;br /&gt;
     virtual void excludeAll (      &lt;br /&gt;
         epicsGuard &amp;amp; ) = 0;&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
== Subscription Event Specification ==&lt;br /&gt;
&lt;br /&gt;
This interface is used to specify what events will and will not be present if a subscription update is triggered.&lt;br /&gt;
&lt;br /&gt;
It is hoped that one subscription specification might be shared by several subscriptions in the server.&lt;br /&gt;
&lt;br /&gt;
 class subscrEventSpec {&lt;br /&gt;
 public:  &lt;br /&gt;
     // subscrSpec is by default is a dont care w.r.t&lt;br /&gt;
     // the eventSpec space&lt;br /&gt;
     virtual void require ( &lt;br /&gt;
         epicsGuard &amp;amp;, const eventSpec &amp;amp; ) = 0;&lt;br /&gt;
     virtual void prohibit ( &lt;br /&gt;
         epicsGuard &amp;amp;, const eventSpec &amp;amp; ) = 0;&lt;br /&gt;
     virtual bool isMatch ( &lt;br /&gt;
         epicsGuard &amp;amp;, const eventSpec &amp;amp; ) const = 0;&lt;br /&gt;
     virtual void show ( &lt;br /&gt;
         epicsGuard &amp;amp;, unsigned level ) const = 0;&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
== Subscription Filter Specification ==&lt;br /&gt;
&lt;br /&gt;
It is hoped that one subscription filter might be shared by several subscriptions installed into a service.&lt;br /&gt;
&lt;br /&gt;
Should (can) a subscription spec be a property catalog?&lt;br /&gt;
&lt;br /&gt;
 class subscrFilterSpec {&lt;br /&gt;
 public:&lt;br /&gt;
     // updates no less frequently than specified&lt;br /&gt;
     virtual void setPeriodMinimum (&lt;br /&gt;
         epicsGuard &amp;amp;, double periodInSeconds ) = 0;&lt;br /&gt;
     // updates no more frequently than specified&lt;br /&gt;
     virtual void setPeriodMaximum (&lt;br /&gt;
         epicsGuard &amp;amp;, double periodInSeconds ) = 0;&lt;br /&gt;
     // delta between updates no less than specified&lt;br /&gt;
     virtual void setPercentChangeMinimum ( &lt;br /&gt;
         epicsGuard &amp;amp;, double percentChange ) = 0;&lt;br /&gt;
     // delta between updates no more than specified    &lt;br /&gt;
     virtual void setPercentChangeMaximum ( &lt;br /&gt;
         epicsGuard &amp;amp;, double percentChange ) = 0;&lt;br /&gt;
     // when data acquisition system can pluck data at an offset&lt;br /&gt;
     virtual void setTriggerTimeOffset ( &lt;br /&gt;
         epicsGuard &amp;amp;, double delayInSeconds ) = 0;&lt;br /&gt;
     // number of intermediate values saved when busy&lt;br /&gt;
     // before replacing last entry on queue&lt;br /&gt;
     virtual void setEventQueueLength ( &lt;br /&gt;
         epicsGuard &amp;amp;, unsigned length ) = 0;&lt;br /&gt;
     // when supported by data store, specify&lt;br /&gt;
     // retrieval of values from the past&lt;br /&gt;
     virtual void setTimeWindow ( &lt;br /&gt;
         epicsGuard &amp;amp;, epicsTime &amp;amp; begin, epicsTime &amp;amp; end ) = 0;&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
== Write Request ==&lt;br /&gt;
&lt;br /&gt;
 class writeCompletionNotify { &lt;br /&gt;
 public:&lt;br /&gt;
     virtual void success ( &lt;br /&gt;
         epicsGuard &amp;amp; ) = 0;    &lt;br /&gt;
     virtual void exception (      &lt;br /&gt;
         epicsGuard &amp;amp;, const diagnostic &amp;amp; ) = 0;&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
 class writeRequest {&lt;br /&gt;
 public:&lt;br /&gt;
     virtual void write ( &lt;br /&gt;
         epicsGuard &amp;amp;, const propertyCatalog &amp;amp; ) = 0;&lt;br /&gt;
     virtual void write ( &lt;br /&gt;
         epicsGuard &amp;amp;, const propertyCatalog &amp;amp;, &lt;br /&gt;
         writeCompletionNotify &amp;amp; ) = 0;&lt;br /&gt;
     virtual void cancel ( &lt;br /&gt;
         epicsGuard &amp;amp; ) = 0;&lt;br /&gt;
     virtual void show ( &lt;br /&gt;
         epicsGuard &amp;amp;, unsigned level ) const = 0;&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
== Read Request ==&lt;br /&gt;
&lt;br /&gt;
 class readCompletionNotify {&lt;br /&gt;
 public:&lt;br /&gt;
     virtual void success (       &lt;br /&gt;
         epicsGuard &amp;amp;, const propertyCatalog &amp;amp; ) = 0;&lt;br /&gt;
     virtual void exception (&lt;br /&gt;
         epicsGuard &amp;amp;, const diagnostic &amp;amp; ) = 0;&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
 class readRequest {&lt;br /&gt;
 public:&lt;br /&gt;
     virtual void read (&lt;br /&gt;
         epicsGuard &amp;amp;, readCompletionNotify &amp;amp; ) = 0;&lt;br /&gt;
     virtual void cancel (&lt;br /&gt;
         epicsGuard &amp;amp; ) = 0;&lt;br /&gt;
     virtual void show (&lt;br /&gt;
         epicsGuard &amp;amp;, unsigned level ) const = 0;&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
== Subscription Request ==&lt;br /&gt;
&lt;br /&gt;
 class subscriptionUpdateNotify {&lt;br /&gt;
 public:&lt;br /&gt;
     virtual void update (&lt;br /&gt;
         epicsGuard &amp;amp;, const eventSpec &amp;amp;, &lt;br /&gt;
         const propertyCatalog &amp;amp; ) = 0;    &lt;br /&gt;
     virtual void exception (&lt;br /&gt;
         epicsGuard &amp;amp;, const diagnostic &amp;amp; ) = 0;&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
 class subscriptionRequest {&lt;br /&gt;
     virtual void subscribe ( &lt;br /&gt;
         epicsGuard &amp;amp;, subscriptionUpdateNotify &amp;amp; ) = 0;&lt;br /&gt;
     virtual void cancel ( &lt;br /&gt;
         epicsGuard &amp;amp; ) = 0;&lt;br /&gt;
     virtual void show ( &lt;br /&gt;
         epicsGuard &amp;amp;, unsigned level ) const = 0;&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
== Channel ==&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
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 &amp;quot;dimension&amp;quot;, &amp;quot;bounds&amp;quot;, &amp;quot;valueBehavior&amp;quot;, &amp;quot;readAccess&amp;quot;, &amp;quot;writeAccess&amp;quot;, &amp;quot;confirmationRequested&amp;quot; properties ). This is also related to connect / disconnect notify callbacks specified when creating channel(they can subscribe for &amp;quot;state&amp;quot; property).&lt;br /&gt;
&lt;br /&gt;
 // I am actively considering abandoning this in favor of allowing &lt;br /&gt;
 // them to subscribe when the channel is created.&lt;br /&gt;
 class channelStateNotify {&lt;br /&gt;
 public:&lt;br /&gt;
     virtual void connectNotify () = 0;&lt;br /&gt;
     virtual void responsiveNotify () = 0;&lt;br /&gt;
     virtual void unresponsiveNotify () = 0;&lt;br /&gt;
     virtual void disconnectNotify () = 0;&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
 class channel {&lt;br /&gt;
 public:&lt;br /&gt;
     typedef unsigned priLevel_t;&lt;br /&gt;
     static const priLevel_t priorityMax;&lt;br /&gt;
     static const priLevel_t priorityMin;&lt;br /&gt;
&lt;br /&gt;
     virtual writeRequest &amp;amp; createWriteRequest (&lt;br /&gt;
         epicsGuard &amp;amp;, &lt;br /&gt;
         const propertyCatalogRegistration &amp;amp; ) = 0;&lt;br /&gt;
     virtual void destroyWriteRequest (&lt;br /&gt;
         epicsGuard &amp;amp;, writeRequest &amp;amp; ) = 0;&lt;br /&gt;
     virtual readRequest &amp;amp; createReadRequest (&lt;br /&gt;
         epicsGuard &amp;amp;, const propertyCatalogRegistration &amp;amp; ) = 0;&lt;br /&gt;
     // receive property description list, but not all&lt;br /&gt;
     // property values (avoid large arrays)? Does this identify a&lt;br /&gt;
     // interface defect in data access&lt;br /&gt;
 // does an array of property id's need to be passed here so that &lt;br /&gt;
 // they can specify a starting point in the hierarchy?&lt;br /&gt;
     virtual readRequest &amp;amp; createAllPropertiesReadRequest (&lt;br /&gt;
         epicsGuard &amp;amp; ) = 0;&lt;br /&gt;
     virtual void destroyReadRequest &lt;br /&gt;
         epicsGuard &amp;amp;, readRequest &amp;amp; ) = 0;&lt;br /&gt;
     virtual subscriptionRequest &amp;amp; createSubscriptionRequest (&lt;br /&gt;
         epicsGuard &amp;amp;, const propertyCatalogRegistration &amp;amp; ) = 0;&lt;br /&gt;
     virtual void destroySubscriptionRequest (&lt;br /&gt;
         epicsGuard &amp;amp;, subscriptionRequest &amp;amp; ) = 0;&lt;br /&gt;
     virtual void name (&lt;br /&gt;
         epicsGuard &amp;amp;, stringSegment &amp;amp; ) const = 0;&lt;br /&gt;
     virtual void show (&lt;br /&gt;
         epicsGuard &amp;amp;, unsigned level ) const = 0;&lt;br /&gt;
     virtual bool isConnected (&lt;br /&gt;
         epicsGuard &amp;amp; ) const = 0;&lt;br /&gt;
     virtual unsigned serviceName (&lt;br /&gt;
         epicsGuard &amp;amp;, stringSegment &amp;amp; ) const () = 0;&lt;br /&gt;
     virtual void flush (&lt;br /&gt;
         epicsGuard &amp;amp; ) = 0;&lt;br /&gt;
     // exceptions&lt;br /&gt;
     class badType : public diagnostic {};&lt;br /&gt;
     class propertyValueOutOfBounds {} : public diagnostic {};&lt;br /&gt;
     class invalidEventSelection {} : public diagnostic {};&lt;br /&gt;
     class noWriteAccess {} : public diagnostic {}; &lt;br /&gt;
     class noReadAccess {} : public diagnostic {};&lt;br /&gt;
     class unsupportedByService {} : public diagnostic {};&lt;br /&gt;
     class requestTimedOut {} : public diagnostic {};&lt;br /&gt;
     class unresponsive {} : public diagnostic {};&lt;br /&gt;
     class disconnect {} : public diagnostic {};&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
== Channel Factory ==&lt;br /&gt;
&lt;br /&gt;
 class channelFactory {&lt;br /&gt;
     virtual cacChannel &amp;amp; createChannel (&lt;br /&gt;
         epicsGuard &amp;amp;, const stringSegment &amp;amp; name, channelStateNotify &amp;amp;,&lt;br /&gt;
         cacChannel::priLevel_t = cacChannel::priorityMin ) = 0;&lt;br /&gt;
     virtual cacChannel &amp;amp; destroyChannel (&lt;br /&gt;
         epicsGuard &amp;amp;, cacChannel &amp;amp; ) = 0;&lt;br /&gt;
     // exceptions&lt;br /&gt;
     class priorityOutOfBounds {} : public diagnostic {};&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
== Event Specification Factory ==&lt;br /&gt;
&lt;br /&gt;
 class eventSpecFactory {&lt;br /&gt;
     virtual eventSpec &amp;amp; createEventSpec (&lt;br /&gt;
         epicsGuard &amp;amp;, const stringSegment &amp;amp; eventName ) = 0;&lt;br /&gt;
     virtual eventSpec &amp;amp; createChannelTriggeredEventSpec (&lt;br /&gt;
         epicsGuard &amp;amp;, const stringSegment &amp;amp; triggerExpression ) = 0;&lt;br /&gt;
     virtual void destroyEventSpec (&lt;br /&gt;
         epicsGuard &amp;amp;, eventSpec &amp;amp; ) = 0;&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
 class subscrSpecFactory {    &lt;br /&gt;
     virtual subscrFilterSpec &amp;amp; createSubscrFilterSpec (        &lt;br /&gt;
         epicsGuard &amp;amp; ) = 0;&lt;br /&gt;
     virtual void destroySubscrFilterSpec (&lt;br /&gt;
         epicsGuard &amp;amp;, subscrFilterSpec &amp;amp; ) = 0;&lt;br /&gt;
     virtual subscrEventSpec &amp;amp; createSubscrEventSpec (        &lt;br /&gt;
         epicsGuard &amp;amp; ) = 0;&lt;br /&gt;
     virtual void destroySubscrEventSpec (&lt;br /&gt;
         epicsGuard &amp;amp;, subscrEventSpec &amp;amp; ) = 0;&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
== Property Catalog Registration ==&lt;br /&gt;
&lt;br /&gt;
 class propertyCatalogRegistration;&lt;br /&gt;
&lt;br /&gt;
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 &amp;lt;code&amp;gt;propertyCatalog&amp;lt;/code&amp;gt; have a &amp;quot;traverseStructure()&amp;quot; interface ?&lt;br /&gt;
&lt;br /&gt;
 class propertyCatalogRegistry {&lt;br /&gt;
     virtual class propertyCatalogRegistration &amp;amp; createRegistration (&lt;br /&gt;
         epicsGuard &amp;amp;, const propertyCatalog &amp;amp; ) = 0;&lt;br /&gt;
     virtual void destroyRegistration ( &lt;br /&gt;
         epicsGuard &amp;amp;, propertyCatalogRegistration &amp;amp; ) = 0; &lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
== Name Service Interface ==&lt;br /&gt;
&lt;br /&gt;
A name service might also have subscription capabilities?&lt;br /&gt;
&lt;br /&gt;
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?&lt;br /&gt;
&lt;br /&gt;
 class nameLookupNotify {&lt;br /&gt;
     virtual void success (&lt;br /&gt;
         epicsGuard &amp;amp;, const propertyCatalog &amp;amp; address,&lt;br /&gt;
         const stringSegment &amp;amp; match, bool last ) = 0;&lt;br /&gt;
     virtual void exception (&lt;br /&gt;
         epicsGuard &amp;amp;, const diagnostic &amp;amp; ) = 0;&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
 class nameLookupRequest {&lt;br /&gt;
     virtual void lookup (&lt;br /&gt;
         epicsGuard &amp;amp;, const stringSegment &amp;amp; name,&lt;br /&gt;
         const nameLookupNotify &amp;amp; ) = 0;&lt;br /&gt;
     virtual void cancel (&lt;br /&gt;
         epicsGuard &amp;amp; ) = 0;&lt;br /&gt;
     virtual void show (&lt;br /&gt;
         epicsGuard &amp;amp;, unsigned level ) const;&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
 class nameService {&lt;br /&gt;
     virtual nameLookupRequest &amp;amp; createNameLookupRequest (&lt;br /&gt;
         epicsGuard &amp;amp; ) = 0;&lt;br /&gt;
     // not supported by all name services?&lt;br /&gt;
     virtual nameLookupRequest &amp;amp; &lt;br /&gt;
         createRegularExpressionNameLookupRequest (  &lt;br /&gt;
             epicsGuard &amp;amp; ) = 0;&lt;br /&gt;
     virtual void destroyNameLookupRequest (&lt;br /&gt;
         epicsGuard &amp;amp;, nameRequest &amp;amp; ) = 0;&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
== Client Context ==&lt;br /&gt;
&lt;br /&gt;
The name &amp;quot;clientContext&amp;quot; should possibly be changed.&lt;br /&gt;
&lt;br /&gt;
 class clientContext :&lt;br /&gt;
     public eventSpecFactory,&lt;br /&gt;
     public subscrSpecFactory,&lt;br /&gt;
     public propertyCatalogRegistry {&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
== Service ==&lt;br /&gt;
&lt;br /&gt;
A service might failover to a backup service, but currently there appears to be no need to reveal this in public interfaces?&lt;br /&gt;
&lt;br /&gt;
The relation between a name service, channelFactory, service, and genericService to each other are areas which are under active consideration.&lt;br /&gt;
&lt;br /&gt;
 class service : &lt;br /&gt;
     public channelFactory, &lt;br /&gt;
     public nameService { &lt;br /&gt;
     virtual void flush ( &lt;br /&gt;
         epicsGuard &amp;amp; ) = 0; &lt;br /&gt;
     virtual void show ( &lt;br /&gt;
         epicsGuard &amp;amp;, unsigned level ) const = 0; &lt;br /&gt;
     // exceptions&lt;br /&gt;
     class disconnect {} : public diagnostic {}; &lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
= Server =&lt;br /&gt;
&lt;br /&gt;
This interface is passed to the service factory.&lt;br /&gt;
&lt;br /&gt;
 class server : &lt;br /&gt;
     public eventSpecFactory {&lt;br /&gt;
 public:&lt;br /&gt;
     virtual void serviceExceptionNotify (&lt;br /&gt;
         epicsGuard &amp;amp;, diagnostic &amp;amp; ) = 0;&lt;br /&gt;
     // for attaching thread private variables&lt;br /&gt;
     // in preparation for asynchronous callback&lt;br /&gt;
     // from a service thread&lt;br /&gt;
     virtual void serviceThreadInitiateNotify (&lt;br /&gt;
         epicsGuard &amp;amp; ) = 0;&lt;br /&gt;
     virtual void serviceThreadExitNotify (&lt;br /&gt;
         epicsGuard &amp;amp; ) = 0;&lt;br /&gt;
     // for implementing non-preemptive callback&lt;br /&gt;
     // **** probably not needed if guard is based on a pure virtual mutex interface&lt;br /&gt;
     // **** and given that they can use thread private variables&lt;br /&gt;
     //virtual void serviceCallbackProcessingInitiateNotify (&lt;br /&gt;
     // epicsGuard &amp;amp; ) = 0;&lt;br /&gt;
     //virtual void serviceCallbackProcessingCompleteNotify (&lt;br /&gt;
     // epicsGuard &amp;amp; ) = 0;&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
== Generic Service ==&lt;br /&gt;
&lt;br /&gt;
A &amp;lt;code&amp;gt;genericService&amp;lt;/code&amp;gt; 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 &amp;lt;code&amp;gt;genericService&amp;lt;/code&amp;gt; will attempt to initially locate the appropriate service, and should a connected service disconnect, attempt to transparently find a new one. A &amp;lt;code&amp;gt;genericService&amp;lt;/code&amp;gt; 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.&lt;br /&gt;
&lt;br /&gt;
 class genericServiceFactory {&lt;br /&gt;
 public:&lt;br /&gt;
     virtual service &amp;amp; createGenericService (&lt;br /&gt;
         epicsGuard &amp;amp;, epicsMutex &amp;amp;,&lt;br /&gt;
         serviceStateChangeNotify &amp;amp;,&lt;br /&gt;
         serviceLocator &amp;amp; ) = 0;&lt;br /&gt;
     virtual void destroyGenericService (&lt;br /&gt;
         epicsGuard &amp;amp;, service &amp;amp; ) = 0;&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
== Network Server/Service Interfaces ==&lt;br /&gt;
&lt;br /&gt;
These interfaces may be accessed with the &amp;lt;code&amp;gt;dynamic_cast&amp;lt;/code&amp;gt; operator&lt;br /&gt;
&lt;br /&gt;
 class beaconGenerator {&lt;br /&gt;
 public:&lt;br /&gt;
     virtual void generateBeaconAnomaly (&lt;br /&gt;
         epicsGuard &amp;amp; ) = 0;&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
 class beaconAnomalyDetectorStateChangeNotify {&lt;br /&gt;
 public:&lt;br /&gt;
     virtual unsigned beaconAnomalyDetectNotify (&lt;br /&gt;
         epicsGuard &amp;amp;, const propertyCatalog &amp;amp; ) const = 0;&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
 // only access to this will be using dynamic_cast&lt;br /&gt;
 class networkChannelDiagnostics {&lt;br /&gt;
     virtual unsigned searchAttempts (&lt;br /&gt;
         epicsGuard &amp;amp; ) const = 0;&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
 // only access to this will be using dynamic_cast&lt;br /&gt;
 class networkCircuitDiagnostics {&lt;br /&gt;
     virtual double estimatedBeaconPeriod (&lt;br /&gt;
         epicsGuard &amp;amp; ) const; &lt;br /&gt;
     // negative DBL_MAX if UKN&lt;br /&gt;
     virtual double receiveWatchdogDelayToExperation (&lt;br /&gt;
         epicsGuard &amp;amp; ) const; &lt;br /&gt;
     // negative DBL_MAX if UKN&lt;br /&gt;
     virtual unsigned protocolRevision (&lt;br /&gt;
         epicsGuard &amp;amp; ) const;&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
 // only access to this will be using dynamic_cast&lt;br /&gt;
 class serviceDiagnostics {&lt;br /&gt;
 public:&lt;br /&gt;
     epicsShareFunc unsigned subscriptionEventsPosted () const;&lt;br /&gt;
     epicsShareFunc unsigned subscriptionEventsProcessed () const;&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
 // only access to this will be using dynamic_cast&lt;br /&gt;
 class beaconAnomalyDetectorDiagnostics {&lt;br /&gt;
 public:&lt;br /&gt;
     virtual unsigned beaconAnomaliesDetected (&lt;br /&gt;
         epicsGuard &amp;amp; ) const = 0;&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
== Oustanding Issues ==&lt;br /&gt;
&lt;br /&gt;
Locking issues. To what degree are we forcing everything to use the same lock? What will be the minimal locking granularity?&lt;br /&gt;
&lt;br /&gt;
How much of the class name should be in the pure virtual function name for uniqueness?&lt;br /&gt;
&lt;br /&gt;
Unification with the PCAS interface requires more work. In particulant posting and event registration.&lt;br /&gt;
&lt;br /&gt;
What type of string interface will be used, and how will this be unified with the database?&lt;/div&gt;</summary>
		<author><name>JeffHill</name></author>
	</entry>
	<entry>
		<id>https://wiki-ext.aps.anl.gov/epics/index.php?title=V4_Name_Server&amp;diff=358</id>
		<title>V4 Name Server</title>
		<link rel="alternate" type="text/html" href="https://wiki-ext.aps.anl.gov/epics/index.php?title=V4_Name_Server&amp;diff=358"/>
		<updated>2005-07-06T21:34:31Z</updated>

		<summary type="html">&lt;p&gt;JeffHill: /* JOH: For comparison purposes, here is the performance of CA's built-in name resolution. */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Directory Server ==&lt;br /&gt;
&lt;br /&gt;
EPICS ChannelAccess currently uses a broadcast mechanism for resolving&lt;br /&gt;
channel names.&lt;br /&gt;
Advantages:&lt;br /&gt;
* Minimal if not zero initial setup.&lt;br /&gt;
* At least initially very fast, because a client can send multiple name requests in one network packet, all servers receive it simultaneously and can answer to known names.&lt;br /&gt;
&lt;br /&gt;
Disadvantages:&lt;br /&gt;
* Unclear how to extend this service to redundant servers, archived data, ...&lt;br /&gt;
* Currently, no wildcard searches.&lt;br /&gt;
* Currently, no statistics on available number of channels, types of records, ...&lt;br /&gt;
* Bigger installations run into problems with broadcast traffic:&lt;br /&gt;
** All devices see the requests, even though only one server has a given channel name.&lt;br /&gt;
** Continued searches for unresolved names to overcome UDP limitations.&lt;br /&gt;
&lt;br /&gt;
As Larry Hoff pointed out, we really want a ''Directory'' server for&lt;br /&gt;
EPICS, something beyond a name server. A directory will not only map PV&lt;br /&gt;
names to IP addresses of ChannelAccess servers, but also support&lt;br /&gt;
* wildcard searches, reports on number of channels per IOC etc.&lt;br /&gt;
* redundant servers&lt;br /&gt;
* info about reduntant IOCs with the same PV, archived data for a PV&lt;br /&gt;
* backup/restore locations for a PV&lt;br /&gt;
* PV meta information like engineer-in-charge, CA security rules, ...&lt;br /&gt;
&lt;br /&gt;
== Channels, Records, PVs, Properties ==&lt;br /&gt;
We currently have records with fields and channels with properties.&lt;br /&gt;
Each field of a record can become a channel name,&lt;br /&gt;
the field itself ends up in the 'value' property of the channel,&lt;br /&gt;
and the record decides how to fill the remaining properties.&lt;br /&gt;
&lt;br /&gt;
Will the directory list all record names or all possible channels?&lt;br /&gt;
I think only record names.&lt;br /&gt;
&lt;br /&gt;
Will it include the record type? Not enough information if we add user-defined fields.&lt;br /&gt;
Will it lists all fields of a record?&lt;br /&gt;
&lt;br /&gt;
I think for now that only listing record names is enough in order to allow&lt;br /&gt;
connections.&lt;br /&gt;
&lt;br /&gt;
The CA client would then have to query the CA server for all the available properties&lt;br /&gt;
of a PV, and note that properties might even change at runtime when we allow&lt;br /&gt;
online add &amp;amp; delete.&lt;br /&gt;
&lt;br /&gt;
Whenever a tool like a command-line 'caget' or the 'probe' GUI requires a PV name,&lt;br /&gt;
it needs to be decided what properties &amp;quot;fred&amp;quot; would access. In the past, it was equal&lt;br /&gt;
to &amp;quot;fred.VAL&amp;quot;. There is much more detail in the 'view' section of the&lt;br /&gt;
[[V4 DBD Statement Syntax]].&lt;br /&gt;
&lt;br /&gt;
== LDAP, Directory, RDB, Schema, Entries, dn, cn, dc, ... ==&lt;br /&gt;
&lt;br /&gt;
The ''Lightweight Directory Access Protocol'' (LDAP) is a network protocol.&lt;br /&gt;
It defines how to access data over the network, regardless of language&lt;br /&gt;
or underlying data storage. In contrast, RDBs like Oracle or MySQL define the&lt;br /&gt;
data storage and SQL dialect, while the network access to the data is then&lt;br /&gt;
added almost as an afterthought.&lt;br /&gt;
&lt;br /&gt;
LDAP is meant as a Directory for simple attribute-based information&lt;br /&gt;
for fast, high volume lookup. Simple search filters are supported:&lt;br /&gt;
Patterns, &amp;quot;and&amp;quot;, &amp;quot;or&amp;quot;. In contrast to RDBs, there is no support for&lt;br /&gt;
arbitrary relations between entries, there are no transactions nor rollback.&lt;br /&gt;
&lt;br /&gt;
There are open-source servers for LDAP, and client libraries for&lt;br /&gt;
C, Perl, Java and other languages. MacOSX, Linux, Windows 2000&lt;br /&gt;
already include LDAP clients. MS ActiveDirectory uses LDAP.&lt;br /&gt;
&lt;br /&gt;
LDAP requires the data to be organized into hierarchical ''Entries''.&lt;br /&gt;
Each Entry has a globally unique ''Distinguished Name'' (dn),&lt;br /&gt;
and various ''Attributes'', that is Type/Value pairs.&lt;br /&gt;
The ''Schema'' defines which attributes an entry must have and which ones&lt;br /&gt;
it might have. There are existing schemas for DNS-type data or personell&lt;br /&gt;
information, including types like ''Common Name'' (cn) or ''Domain Component'' (dc),&lt;br /&gt;
but one can add custom schemata. Values might include binary data, e.g. images.&lt;br /&gt;
&lt;br /&gt;
=== Mapping EPICS PV Information to LDAP ===&lt;br /&gt;
&lt;br /&gt;
Each LDAP entry must have a unique name (dn). EPICS PVs must be unique as well,&lt;br /&gt;
but only within the search domain currently defined by the EPICS_CA_ADDR_LIST.&lt;br /&gt;
It might make sense to synchronize LDAP servers across these boundaries,&lt;br /&gt;
in which case the LDAP dn will have to include more than just the PV name.&lt;br /&gt;
For example, one could have a PV &amp;quot;fred&amp;quot; in both the accelerator and office network&lt;br /&gt;
of the SNS, and enter them into an SNS-wide LDAP directory like this:&lt;br /&gt;
&lt;br /&gt;
 fred.linac.sns.epics:  cas=&amp;quot;linacioc1:5065&amp;quot;&lt;br /&gt;
 fred.office.sns.epics: cas=&amp;quot;testioc47.sns.ornl.gov:7987&amp;quot;, description=&amp;quot;Fred's test PV&amp;quot;&lt;br /&gt;
&lt;br /&gt;
In this example, the directory includes the ChannelAccess server for both PVs,&lt;br /&gt;
and in one case also a description.&lt;br /&gt;
&lt;br /&gt;
While an EPICS-specific tool might present the data as shown above,&lt;br /&gt;
most generic LDAP tools and APIs use the ''LDAP Data Interchange Format'' (LDIF).&lt;br /&gt;
In LDIF, part of the above data could look like this:&lt;br /&gt;
&lt;br /&gt;
 dn: dc=epics&lt;br /&gt;
 objectclass: dcObject&lt;br /&gt;
 objectclass: organization&lt;br /&gt;
 o: Root of all EPICS PVs&lt;br /&gt;
 dc: epics&lt;br /&gt;
&lt;br /&gt;
 dn: dc=sns,dc=epics&lt;br /&gt;
 # Details omitted; similar to previous entry&lt;br /&gt;
&lt;br /&gt;
 dn: dc=linac,dc=sns,dc=epics&lt;br /&gt;
 objectclass: dcObject&lt;br /&gt;
 objectclass: organization&lt;br /&gt;
 o: Root of all EPICS PVs in the SNS Linac&lt;br /&gt;
 dc: linac&lt;br /&gt;
&lt;br /&gt;
 dn: cn=fred,dc=linac,dc=sns,dc=epics&lt;br /&gt;
 objectclass: ProcessVariable&lt;br /&gt;
 cn: fred&lt;br /&gt;
 cas: linacioc1:5065 &lt;br /&gt;
&lt;br /&gt;
Some points I had to learn:&lt;br /&gt;
* Each entry has an objectclass. The schema for &amp;quot;ProcessVariable&amp;quot; would for example require a &amp;quot;cn&amp;quot; attribute, with optional &amp;quot;cas&amp;quot;, &amp;quot;description&amp;quot; and maybe other attributes.&amp;lt;br&amp;gt;The schema would also determine if searches for PV names are case-sensitive or not.&lt;br /&gt;
* The hierarchical path &amp;quot;fred.linac.sns.epics&amp;quot; translates into a dn &amp;quot;cn=fred,dc=linac,dc=sns,dc=epics&amp;quot; which lists the relative dn of the entry itself and all path elements.&lt;br /&gt;
* Each path element must exists, so to bootstrap one has to create entries &amp;quot;dc=epics&amp;quot; and &amp;quot;dc=sns,dc=epics&amp;quot; etc., for which I used the pre-defined &amp;quot;organization&amp;quot; schema.&lt;br /&gt;
* To locate the PV 'fred', any of the following LDAP searches would work:&lt;br /&gt;
** Scope &amp;quot;base&amp;quot; with base &amp;quot;cn=fred,dc=linac,dc=sns,dc=epics&amp;quot;.&lt;br /&gt;
** Scope &amp;quot;one&amp;quot; with base &amp;quot;dc=linac,dc=sns,dc=epics&amp;quot; and filter &amp;quot;(cn=fred)&amp;quot;.&lt;br /&gt;
** Scope &amp;quot;one&amp;quot; with base &amp;quot;dc=linac,dc=sns,dc=epics&amp;quot; and filter &amp;quot;(cn=f*d)&amp;quot;,&amp;lt;br&amp;gt;though this might return more records which happen to match the pattern.&lt;br /&gt;
** Scope &amp;quot;sub&amp;quot; with base &amp;quot;dc=sns,dc=epics&amp;quot; and filter &amp;quot;(cn=fred)&amp;quot;,&amp;lt;br&amp;gt;which would also return an entry with dn &amp;quot;cn=fred,dc=office,dc=sns,dc=epics&amp;quot;.&lt;br /&gt;
** There is a filter option &amp;quot;~=&amp;quot; for 'approximately equal'. Unclear what exactly defines approximate, but this might be very handy for detecing typos.&lt;br /&gt;
&lt;br /&gt;
=== OpenLDAP ===&lt;br /&gt;
&lt;br /&gt;
OpenLDAP  [http://www.openldap.org] is an open-source LDAP&lt;br /&gt;
client library for C and an LDAP server which can store the&lt;br /&gt;
actual data in /dev/null, a BerkeleyDB, SQL, Perl, a remote LDAP server.&lt;br /&gt;
&lt;br /&gt;
OpenLDAP includes authentication and encrypted (SSL) transport,&lt;br /&gt;
replication (single master -&amp;gt; multiple slaves),&lt;br /&gt;
and referrals from one server to another one which has more details.&lt;br /&gt;
&lt;br /&gt;
=== EPICS PV Tests ===&lt;br /&gt;
&lt;br /&gt;
Using OpenLDAP-stable-20050429 and perl-ldap-0.3202 on a 1.3 GHz PowerBook G4&lt;br /&gt;
with 780 MB RAM under MacOS X 10.3.8, I used a perl script to create&lt;br /&gt;
PV entries, search them, and remove them.&lt;br /&gt;
In addition, the 'ldapsearch' that comes with RedHat Enterprise AS 3 was&lt;br /&gt;
used to check remote accessibillity.&lt;br /&gt;
&lt;br /&gt;
When trying to list all PVs with an appropriate search pattern,&lt;br /&gt;
the default server configuration limits the response to 500 answers.&lt;br /&gt;
This was changed such that 'paged' searches which keep requesting data&lt;br /&gt;
in increments of e.g. 500 entries are allowed to continue until all data is retrieved.&lt;br /&gt;
From the command-line tool, that's done like this:&lt;br /&gt;
 ldapsearch -x -LLL -E pr=10/noprompt -b 'dc=epics' '(cn=testpv*)'  cas&lt;br /&gt;
&lt;br /&gt;
== Performance ==&lt;br /&gt;
&lt;br /&gt;
Based on the default OpenLDAP server config with an additional&lt;br /&gt;
index &amp;quot;cn pres,eq&amp;quot; on the common name of the PVs,&lt;br /&gt;
PVs with names 'testrec0000000001', 'testrec0000000002' etc.&lt;br /&gt;
were added, then looked up one-by-one via their exact name,&lt;br /&gt;
and finially deleted one by one.&lt;br /&gt;
&lt;br /&gt;
When using a C++ test client based on the OpenLDAP library,&lt;br /&gt;
the results for smaller numbers are:&lt;br /&gt;
 Add         10000 records : 22.76 secs&lt;br /&gt;
 Locate      10000 records : 6.49 secs&lt;br /&gt;
 Delete      10000 records : 22.20 secs&lt;br /&gt;
&lt;br /&gt;
In another test, a very rough estimated PV count of the SNS linac&lt;br /&gt;
was used:&lt;br /&gt;
 Add        200000 records : 675.89 secs (38.74 CPU)&lt;br /&gt;
 Locate     200000 records : 142.85 secs (27.91 CPU)&lt;br /&gt;
 Delete     200000 records : 807.28 secs (37.28 CPU)&lt;br /&gt;
&lt;br /&gt;
Those 200000 records use about 900MB of file space.&lt;br /&gt;
The results indicate that one can add 300 .. 440 records/sec,&lt;br /&gt;
locate 1400.. 1540 records/sec and delete 250..450 records/sec.&lt;br /&gt;
Without an index, the addition and deletion will be faster&lt;br /&gt;
at the expense of lookup times.&lt;br /&gt;
&lt;br /&gt;
A typical SNS LLRF IOCs has 2300 records.&lt;br /&gt;
On startup, sending those to the directory server would take around 7 seconds.&lt;br /&gt;
A typical SNS LLRF overview screen has about 400 PVs,&lt;br /&gt;
and current connection times vary from less than a second to&lt;br /&gt;
several tens of seconds, depending on how well the search requests&lt;br /&gt;
reach the IOCs.&lt;br /&gt;
Resolving their CA servers would take about 0.3 seconds with LDAP,&lt;br /&gt;
which would then be followed by the time required to actually connect&lt;br /&gt;
to those servers.&lt;br /&gt;
&lt;br /&gt;
In previous test using perl, the individual PV search actually used an LDIF&lt;br /&gt;
filter with exact match like 'testrec0000000001'. In addition, all PVs matching&lt;br /&gt;
a filter 'testrec*' were retrieved, and no index was used:&lt;br /&gt;
 Adding   1000 records:  4 wallclock secs ( 2.29 usr +  0.14 sys =  2.43 CPU)&lt;br /&gt;
 Locating 1000 records: 49 wallclock secs ( 4.10 usr +  0.21 sys =  4.31 CPU)&lt;br /&gt;
 Match all        1000:  1 wallclock secs ( 1.18 usr +  0.02 sys =  1.20 CPU)&lt;br /&gt;
 Delete   1000 records:  4 wallclock secs ( 1.35 usr +  0.14 sys =  1.49 CPU)&lt;br /&gt;
&lt;br /&gt;
When locating individual records via the complete LDIF base without a filter,&lt;br /&gt;
the search is much faster:&lt;br /&gt;
Locating 1000 records:  5 wallclock secs ( 3.20 usr +  0.18 sys =  3.38 CPU)&lt;br /&gt;
&lt;br /&gt;
When adding an &amp;quot;index cn pres,eq&amp;quot; to the server config, the results are the&lt;br /&gt;
same for both the filter and the base search case.&lt;br /&gt;
No difference observed when tripling the cachesize from the default of 1000.&lt;br /&gt;
The behavior scales linearly with the number of channels,&lt;br /&gt;
always a little over 200 additions or lookups per second:&lt;br /&gt;
 Adding   10000 records: 47 wallclock secs (21.72 usr +  1.28 sys = 23.00 CPU)&lt;br /&gt;
 Locating 10000 records: 44 wallclock secs (32.20 usr +  1.55 sys = 33.75 CPU)&lt;br /&gt;
 Match all        10000: 15 wallclock secs (12.15 usr +  0.64 sys = 12.79 CPU)&lt;br /&gt;
 Delete   10000 records: 38 wallclock secs (15.41 usr +  1.16 sys = 16.57 CPU)&lt;br /&gt;
&lt;br /&gt;
 Adding   50000 records: 243 wallclock secs (110.36 usr +  7.18 sys = 117.54 CPU)&lt;br /&gt;
 Locating 50000 records: 226 wallclock secs (164.97 usr +  7.67 sys = 172.64 CPU)&lt;br /&gt;
 Match all        50000: 80 wallclock secs (63.09 usr +  3.42 sys = 66.51 CPU)&lt;br /&gt;
 Delete   50000 records: 219 wallclock secs (82.11 usr +  6.61 sys = 88.72 CPU)&lt;br /&gt;
&lt;br /&gt;
 Adding  200000 records: 1293 wallclock secs (483.65 usr + 33.20 sys = 516.85 CPU)&lt;br /&gt;
&lt;br /&gt;
&amp;quot;index cn,dc pres,eq,approx,sub&amp;quot; takes longer to insert/delete&lt;br /&gt;
without improved search performance:&lt;br /&gt;
 Adding   10000 records: 104 wallclock secs (26.25 usr +  1.67 sys = 27.92 CPU)&lt;br /&gt;
 Locating 10000 records: 45 wallclock secs (32.86 usr +  1.55 sys = 34.41 CPU)&lt;br /&gt;
 Match all        10000: 15 wallclock secs (12.31 usr +  0.47 sys = 12.78 CPU)&lt;br /&gt;
 Delete   10000 records: 97 wallclock secs (17.89 usr +  1.34 sys = 19.23 CPU)&lt;br /&gt;
&lt;br /&gt;
The CPU load is a rough 50/50 split between the perl and slapd processes.&lt;br /&gt;
The perl ldap library is 100% perl, including the network handling and&lt;br /&gt;
quite some data conversions from arrays into hashes and back,&lt;br /&gt;
so a pure C client might be a little faster.&lt;br /&gt;
&lt;br /&gt;
Though an index slows down the insertion of PVs, it speeds up certain&lt;br /&gt;
retrieval methods, as probably desired for an EPICS directory server.&lt;br /&gt;
The search mechanism is based on round-trip requests.&lt;br /&gt;
Searching PVs one PV name at a time is slower than requesting all&lt;br /&gt;
PVs that match a pattern. Unfortunately, typical CA clients will&lt;br /&gt;
have to request data for specific PV names, not by pattern.&lt;br /&gt;
&lt;br /&gt;
==== JOH: For comparison purposes, here is the performance of CA's built-in name resolution. ====&lt;br /&gt;
&lt;br /&gt;
 Testing with 100000 channels named joh:bill&lt;br /&gt;
 channel connect test&lt;br /&gt;
 Elapsed Per Item =   0.00001683 sec,    59427.3 Items per sec, 31.4 Mbps&lt;br /&gt;
 Search tries per chan - mean=1.000930 std dev=0.030482 min=1.000000 max=2.000000&lt;br /&gt;
&lt;br /&gt;
=== To be investigated ===&lt;br /&gt;
&lt;br /&gt;
* How to access it from vxWorks&lt;br /&gt;
* How does an LDAP server used for EPICS cooperate with existing LDAP servers for DNS, email etc. Should it be one and the same? Use special port numbers for 'EPICS' LDAP?&lt;br /&gt;
* API: What type of API would EPICS tools use? Whatever LDAP library they use? An 'EPICS wrapper' around LDAP? Gasper suggested to look at the Java JNDI API for inspiration.&lt;br /&gt;
* Common Database headaches:&lt;br /&gt;
** To simply get a  PV into LDAP, one has to check if this PV already exists and then either 'add' or 'modify'.&lt;br /&gt;
** What if a channel is no longer available? An IOC shutting down could remove PVs from the LDAP server, but an IOC that crashes won't.&lt;br /&gt;
* Replication: How to use it, how fast is it etc.&lt;br /&gt;
* Authentication and encryption: How hard is it to configure?&lt;/div&gt;</summary>
		<author><name>JeffHill</name></author>
	</entry>
	<entry>
		<id>https://wiki-ext.aps.anl.gov/epics/index.php?title=V4_Name_Server&amp;diff=355</id>
		<title>V4 Name Server</title>
		<link rel="alternate" type="text/html" href="https://wiki-ext.aps.anl.gov/epics/index.php?title=V4_Name_Server&amp;diff=355"/>
		<updated>2005-07-06T20:12:10Z</updated>

		<summary type="html">&lt;p&gt;JeffHill: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Directory Server ==&lt;br /&gt;
&lt;br /&gt;
EPICS ChannelAccess currently uses a broadcast mechanism for resolving&lt;br /&gt;
channel names.&lt;br /&gt;
Advantages:&lt;br /&gt;
* Minimal if not zero initial setup.&lt;br /&gt;
* At least initially very fast, because a client can send multiple name requests in one network packet, all servers receive it simultaneously and can answer to known names.&lt;br /&gt;
&lt;br /&gt;
Disadvantages:&lt;br /&gt;
* Unclear how to extend this service to redundant servers, archived data, ...&lt;br /&gt;
* Currently, no wildcard searches.&lt;br /&gt;
* Currently, no statistics on available number of channels, types of records, ...&lt;br /&gt;
* Bigger installations run into problems with broadcast traffic:&lt;br /&gt;
** All devices see the requests, even though only one server has a given channel name.&lt;br /&gt;
** Continued searches for unresolved names to overcome UDP limitations.&lt;br /&gt;
&lt;br /&gt;
As Larry Hoff pointed out, we really want a ''Directory'' server for&lt;br /&gt;
EPICS, something beyond a name server. A directory will not only map PV&lt;br /&gt;
names to IP addresses of ChannelAccess servers, but also support&lt;br /&gt;
* wildcard searches, reports on number of channels per IOC etc.&lt;br /&gt;
* redundant servers&lt;br /&gt;
* info about reduntant IOCs with the same PV, archived data for a PV&lt;br /&gt;
* backup/restore locations for a PV&lt;br /&gt;
* PV meta information like engineer-in-charge, CA security rules, ...&lt;br /&gt;
&lt;br /&gt;
== Channels, Records, PVs, Properties ==&lt;br /&gt;
We currently have records with fields and channels with properties.&lt;br /&gt;
Each field of a record can become a channel name,&lt;br /&gt;
the field itself ends up in the 'value' property of the channel,&lt;br /&gt;
and the record decides how to fill the remaining properties.&lt;br /&gt;
&lt;br /&gt;
Will the directory list all record names or all possible channels?&lt;br /&gt;
I think only record names.&lt;br /&gt;
&lt;br /&gt;
Will it include the record type? Not enough information if we add user-defined fields.&lt;br /&gt;
Will it lists all fields of a record?&lt;br /&gt;
&lt;br /&gt;
I think for now that only listing record names is enough in order to allow&lt;br /&gt;
connections.&lt;br /&gt;
&lt;br /&gt;
The CA client would then have to query the CA server for all the available properties&lt;br /&gt;
of a PV, and note that properties might even change at runtime when we allow&lt;br /&gt;
online add &amp;amp; delete.&lt;br /&gt;
&lt;br /&gt;
Whenever a tool like a command-line 'caget' or the 'probe' GUI requires a PV name,&lt;br /&gt;
it needs to be decided what properties &amp;quot;fred&amp;quot; would access. In the past, it was equal&lt;br /&gt;
to &amp;quot;fred.VAL&amp;quot;. There is much more detail in the 'view' section of the&lt;br /&gt;
[[V4 DBD Statement Syntax]].&lt;br /&gt;
&lt;br /&gt;
== LDAP, Directory, RDB, Schema, Entries, dn, cn, dc, ... ==&lt;br /&gt;
&lt;br /&gt;
The ''Lightweight Directory Access Protocol'' (LDAP) is a network protocol.&lt;br /&gt;
It defines how to access data over the network, regardless of language&lt;br /&gt;
or underlying data storage. In contrast, RDBs like Oracle or MySQL define the&lt;br /&gt;
data storage and SQL dialect, while the network access to the data is then&lt;br /&gt;
added almost as an afterthought.&lt;br /&gt;
&lt;br /&gt;
LDAP is meant as a Directory for simple attribute-based information&lt;br /&gt;
for fast, high volume lookup. Simple search filters are supported:&lt;br /&gt;
Patterns, &amp;quot;and&amp;quot;, &amp;quot;or&amp;quot;. In contrast to RDBs, there is no support for&lt;br /&gt;
arbitrary relations between entries, there are no transactions nor rollback.&lt;br /&gt;
&lt;br /&gt;
There are open-source servers for LDAP, and client libraries for&lt;br /&gt;
C, Perl, Java and other languages. MacOSX, Linux, Windows 2000&lt;br /&gt;
already include LDAP clients. MS ActiveDirectory uses LDAP.&lt;br /&gt;
&lt;br /&gt;
LDAP requires the data to be organized into hierarchical ''Entries''.&lt;br /&gt;
Each Entry has a globally unique ''Distinguished Name'' (dn),&lt;br /&gt;
and various ''Attributes'', that is Type/Value pairs.&lt;br /&gt;
The ''Schema'' defines which attributes an entry must have and which ones&lt;br /&gt;
it might have. There are existing schemas for DNS-type data or personell&lt;br /&gt;
information, including types like ''Common Name'' (cn) or ''Domain Component'' (dc),&lt;br /&gt;
but one can add custom schemata. Values might include binary data, e.g. images.&lt;br /&gt;
&lt;br /&gt;
=== Mapping EPICS PV Information to LDAP ===&lt;br /&gt;
&lt;br /&gt;
Each LDAP entry must have a unique name (dn). EPICS PVs must be unique as well,&lt;br /&gt;
but only within the search domain currently defined by the EPICS_CA_ADDR_LIST.&lt;br /&gt;
It might make sense to synchronize LDAP servers across these boundaries,&lt;br /&gt;
in which case the LDAP dn will have to include more than just the PV name.&lt;br /&gt;
For example, one could have a PV &amp;quot;fred&amp;quot; in both the accelerator and office network&lt;br /&gt;
of the SNS, and enter them into an SNS-wide LDAP directory like this:&lt;br /&gt;
&lt;br /&gt;
 fred.linac.sns.epics:  cas=&amp;quot;linacioc1:5065&amp;quot;&lt;br /&gt;
 fred.office.sns.epics: cas=&amp;quot;testioc47.sns.ornl.gov:7987&amp;quot;, description=&amp;quot;Fred's test PV&amp;quot;&lt;br /&gt;
&lt;br /&gt;
In this example, the directory includes the ChannelAccess server for both PVs,&lt;br /&gt;
and in one case also a description.&lt;br /&gt;
&lt;br /&gt;
While an EPICS-specific tool might present the data as shown above,&lt;br /&gt;
most generic LDAP tools and APIs use the ''LDAP Data Interchange Format'' (LDIF).&lt;br /&gt;
In LDIF, part of the above data could look like this:&lt;br /&gt;
&lt;br /&gt;
 dn: dc=epics&lt;br /&gt;
 objectclass: dcObject&lt;br /&gt;
 objectclass: organization&lt;br /&gt;
 o: Root of all EPICS PVs&lt;br /&gt;
 dc: epics&lt;br /&gt;
&lt;br /&gt;
 dn: dc=sns,dc=epics&lt;br /&gt;
 # Details omitted; similar to previous entry&lt;br /&gt;
&lt;br /&gt;
 dn: dc=linac,dc=sns,dc=epics&lt;br /&gt;
 objectclass: dcObject&lt;br /&gt;
 objectclass: organization&lt;br /&gt;
 o: Root of all EPICS PVs in the SNS Linac&lt;br /&gt;
 dc: linac&lt;br /&gt;
&lt;br /&gt;
 dn: cn=fred,dc=linac,dc=sns,dc=epics&lt;br /&gt;
 objectclass: ProcessVariable&lt;br /&gt;
 cn: fred&lt;br /&gt;
 cas: linacioc1:5065 &lt;br /&gt;
&lt;br /&gt;
Some points I had to learn:&lt;br /&gt;
* Each entry has an objectclass. The schema for &amp;quot;ProcessVariable&amp;quot; would for example require a &amp;quot;cn&amp;quot; attribute, with optional &amp;quot;cas&amp;quot;, &amp;quot;description&amp;quot; and maybe other attributes.&amp;lt;br&amp;gt;The schema would also determine if searches for PV names are case-sensitive or not.&lt;br /&gt;
* The hierarchical path &amp;quot;fred.linac.sns.epics&amp;quot; translates into a dn &amp;quot;cn=fred,dc=linac,dc=sns,dc=epics&amp;quot; which lists the relative dn of the entry itself and all path elements.&lt;br /&gt;
* Each path element must exists, so to bootstrap one has to create entries &amp;quot;dc=epics&amp;quot; and &amp;quot;dc=sns,dc=epics&amp;quot; etc., for which I used the pre-defined &amp;quot;organization&amp;quot; schema.&lt;br /&gt;
* To locate the PV 'fred', any of the following LDAP searches would work:&lt;br /&gt;
** Scope &amp;quot;base&amp;quot; with base &amp;quot;cn=fred,dc=linac,dc=sns,dc=epics&amp;quot;.&lt;br /&gt;
** Scope &amp;quot;one&amp;quot; with base &amp;quot;dc=linac,dc=sns,dc=epics&amp;quot; and filter &amp;quot;(cn=fred)&amp;quot;.&lt;br /&gt;
** Scope &amp;quot;one&amp;quot; with base &amp;quot;dc=linac,dc=sns,dc=epics&amp;quot; and filter &amp;quot;(cn=f*d)&amp;quot;,&amp;lt;br&amp;gt;though this might return more records which happen to match the pattern.&lt;br /&gt;
** Scope &amp;quot;sub&amp;quot; with base &amp;quot;dc=sns,dc=epics&amp;quot; and filter &amp;quot;(cn=fred)&amp;quot;,&amp;lt;br&amp;gt;which would also return an entry with dn &amp;quot;cn=fred,dc=office,dc=sns,dc=epics&amp;quot;.&lt;br /&gt;
** There is a filter option &amp;quot;~=&amp;quot; for 'approximately equal'. Unclear what exactly defines approximate, but this might be very handy for detecing typos.&lt;br /&gt;
&lt;br /&gt;
=== OpenLDAP ===&lt;br /&gt;
&lt;br /&gt;
OpenLDAP  [http://www.openldap.org] is an open-source LDAP&lt;br /&gt;
client library for C and an LDAP server which can store the&lt;br /&gt;
actual data in /dev/null, a BerkeleyDB, SQL, Perl, a remote LDAP server.&lt;br /&gt;
&lt;br /&gt;
OpenLDAP includes authentication and encrypted (SSL) transport,&lt;br /&gt;
replication (single master -&amp;gt; multiple slaves),&lt;br /&gt;
and referrals from one server to another one which has more details.&lt;br /&gt;
&lt;br /&gt;
=== EPICS PV Tests ===&lt;br /&gt;
&lt;br /&gt;
Using OpenLDAP-stable-20050429 and perl-ldap-0.3202 on a 1.3 GHz PowerBook G4&lt;br /&gt;
with 780 MB RAM under MacOS X 10.3.8, I used a perl script to create&lt;br /&gt;
PV entries, search them, and remove them.&lt;br /&gt;
In addition, the 'ldapsearch' that comes with RedHat Enterprise AS 3 was&lt;br /&gt;
used to check remote accessibillity.&lt;br /&gt;
&lt;br /&gt;
When trying to list all PVs with an appropriate search pattern,&lt;br /&gt;
the default server configuration limits the response to 500 answers.&lt;br /&gt;
This was changed such that 'paged' searches which keep requesting data&lt;br /&gt;
in increments of e.g. 500 entries are allowed to continue until all data is retrieved.&lt;br /&gt;
From the command-line tool, that's done like this:&lt;br /&gt;
 ldapsearch -x -LLL -E pr=10/noprompt -b 'dc=epics' '(cn=testpv*)'  cas&lt;br /&gt;
&lt;br /&gt;
== Performance ==&lt;br /&gt;
&lt;br /&gt;
Based on the default OpenLDAP server config with an additional&lt;br /&gt;
index &amp;quot;cn pres,eq&amp;quot; on the common name of the PVs,&lt;br /&gt;
PVs with names 'testrec0000000001', 'testrec0000000002' etc.&lt;br /&gt;
were added, then looked up one-by-one via their exact name,&lt;br /&gt;
and finially deleted one by one.&lt;br /&gt;
&lt;br /&gt;
When using a C++ test client based on the OpenLDAP library,&lt;br /&gt;
the results for smaller numbers are:&lt;br /&gt;
 Add         10000 records : 22.76 secs&lt;br /&gt;
 Locate      10000 records : 6.49 secs&lt;br /&gt;
 Delete      10000 records : 22.20 secs&lt;br /&gt;
&lt;br /&gt;
In another test, a very rough estimated PV count of the SNS linac&lt;br /&gt;
was used:&lt;br /&gt;
 Add        200000 records : 675.89 secs (38.74 CPU)&lt;br /&gt;
 Locate     200000 records : 142.85 secs (27.91 CPU)&lt;br /&gt;
 Delete     200000 records : 807.28 secs (37.28 CPU)&lt;br /&gt;
&lt;br /&gt;
Those 200000 records use about 900MB of file space.&lt;br /&gt;
The results indicate that one can add 300 .. 440 records/sec,&lt;br /&gt;
locate 1400.. 1540 records/sec and delete 250..450 records/sec.&lt;br /&gt;
Without an index, the addition and deletion will be faster&lt;br /&gt;
at the expense of lookup times.&lt;br /&gt;
&lt;br /&gt;
A typical SNS LLRF IOCs has 2300 records.&lt;br /&gt;
On startup, sending those to the directory server would take around 7 seconds.&lt;br /&gt;
A typical SNS LLRF overview screen has about 400 PVs,&lt;br /&gt;
and current connection times vary from less than a second to&lt;br /&gt;
several tens of seconds, depending on how well the search requests&lt;br /&gt;
reach the IOCs.&lt;br /&gt;
Resolving their CA servers would take about 0.3 seconds with LDAP,&lt;br /&gt;
which would then be followed by the time required to actually connect&lt;br /&gt;
to those servers.&lt;br /&gt;
&lt;br /&gt;
In previous test using perl, the individual PV search actually used an LDIF&lt;br /&gt;
filter with exact match like 'testrec0000000001'. In addition, all PVs matching&lt;br /&gt;
a filter 'testrec*' were retrieved, and no index was used:&lt;br /&gt;
 Adding   1000 records:  4 wallclock secs ( 2.29 usr +  0.14 sys =  2.43 CPU)&lt;br /&gt;
 Locating 1000 records: 49 wallclock secs ( 4.10 usr +  0.21 sys =  4.31 CPU)&lt;br /&gt;
 Match all        1000:  1 wallclock secs ( 1.18 usr +  0.02 sys =  1.20 CPU)&lt;br /&gt;
 Delete   1000 records:  4 wallclock secs ( 1.35 usr +  0.14 sys =  1.49 CPU)&lt;br /&gt;
&lt;br /&gt;
When locating individual records via the complete LDIF base without a filter,&lt;br /&gt;
the search is much faster:&lt;br /&gt;
Locating 1000 records:  5 wallclock secs ( 3.20 usr +  0.18 sys =  3.38 CPU)&lt;br /&gt;
&lt;br /&gt;
When adding an &amp;quot;index cn pres,eq&amp;quot; to the server config, the results are the&lt;br /&gt;
same for both the filter and the base search case.&lt;br /&gt;
No difference observed when tripling the cachesize from the default of 1000.&lt;br /&gt;
The behavior scales linearly with the number of channels,&lt;br /&gt;
always a little over 200 additions or lookups per second:&lt;br /&gt;
 Adding   10000 records: 47 wallclock secs (21.72 usr +  1.28 sys = 23.00 CPU)&lt;br /&gt;
 Locating 10000 records: 44 wallclock secs (32.20 usr +  1.55 sys = 33.75 CPU)&lt;br /&gt;
 Match all        10000: 15 wallclock secs (12.15 usr +  0.64 sys = 12.79 CPU)&lt;br /&gt;
 Delete   10000 records: 38 wallclock secs (15.41 usr +  1.16 sys = 16.57 CPU)&lt;br /&gt;
&lt;br /&gt;
 Adding   50000 records: 243 wallclock secs (110.36 usr +  7.18 sys = 117.54 CPU)&lt;br /&gt;
 Locating 50000 records: 226 wallclock secs (164.97 usr +  7.67 sys = 172.64 CPU)&lt;br /&gt;
 Match all        50000: 80 wallclock secs (63.09 usr +  3.42 sys = 66.51 CPU)&lt;br /&gt;
 Delete   50000 records: 219 wallclock secs (82.11 usr +  6.61 sys = 88.72 CPU)&lt;br /&gt;
&lt;br /&gt;
 Adding  200000 records: 1293 wallclock secs (483.65 usr + 33.20 sys = 516.85 CPU)&lt;br /&gt;
&lt;br /&gt;
&amp;quot;index cn,dc pres,eq,approx,sub&amp;quot; takes longer to insert/delete&lt;br /&gt;
without improved search performance:&lt;br /&gt;
 Adding   10000 records: 104 wallclock secs (26.25 usr +  1.67 sys = 27.92 CPU)&lt;br /&gt;
 Locating 10000 records: 45 wallclock secs (32.86 usr +  1.55 sys = 34.41 CPU)&lt;br /&gt;
 Match all        10000: 15 wallclock secs (12.31 usr +  0.47 sys = 12.78 CPU)&lt;br /&gt;
 Delete   10000 records: 97 wallclock secs (17.89 usr +  1.34 sys = 19.23 CPU)&lt;br /&gt;
&lt;br /&gt;
The CPU load is a rough 50/50 split between the perl and slapd processes.&lt;br /&gt;
The perl ldap library is 100% perl, including the network handling and&lt;br /&gt;
quite some data conversions from arrays into hashes and back,&lt;br /&gt;
so a pure C client might be a little faster.&lt;br /&gt;
&lt;br /&gt;
Though an index slows down the insertion of PVs, it speeds up certain&lt;br /&gt;
retrieval methods, as probably desired for an EPICS directory server.&lt;br /&gt;
The search mechanism is based on round-trip requests.&lt;br /&gt;
Searching PVs one PV name at a time is slower than requesting all&lt;br /&gt;
PVs that match a pattern. Unfortunately, typical CA clients will&lt;br /&gt;
have to request data for specific PV names, not by pattern.&lt;br /&gt;
&lt;br /&gt;
==== JOH: For comparison purposes, here is the performance of CA's built-in name resolution. ====&lt;br /&gt;
&lt;br /&gt;
 Testing with 10000 channels named joh:bill&lt;br /&gt;
 channel connect test&lt;br /&gt;
 Elapsed Per Item =   0.00002349 sec,    42570.2 Items per sec, 22.5 Mbps&lt;br /&gt;
 Search tries per chan - mean=1.006200 std dev=0.078496 min=1.000000 max=2.000000&lt;br /&gt;
&lt;br /&gt;
=== To be investigated ===&lt;br /&gt;
&lt;br /&gt;
* How to access it from vxWorks&lt;br /&gt;
* How does an LDAP server used for EPICS cooperate with existing LDAP servers for DNS, email etc. Should it be one and the same? Use special port numbers for 'EPICS' LDAP?&lt;br /&gt;
* API: What type of API would EPICS tools use? Whatever LDAP library they use? An 'EPICS wrapper' around LDAP? Gasper suggested to look at the Java JNDI API for inspiration.&lt;br /&gt;
* Common Database headaches:&lt;br /&gt;
** To simply get a  PV into LDAP, one has to check if this PV already exists and then either 'add' or 'modify'.&lt;br /&gt;
** What if a channel is no longer available? An IOC shutting down could remove PVs from the LDAP server, but an IOC that crashes won't.&lt;br /&gt;
* Replication: How to use it, how fast is it etc.&lt;br /&gt;
* Authentication and encryption: How hard is it to configure?&lt;/div&gt;</summary>
		<author><name>JeffHill</name></author>
	</entry>
	<entry>
		<id>https://wiki-ext.aps.anl.gov/epics/index.php?title=V4_Name_Server&amp;diff=354</id>
		<title>V4 Name Server</title>
		<link rel="alternate" type="text/html" href="https://wiki-ext.aps.anl.gov/epics/index.php?title=V4_Name_Server&amp;diff=354"/>
		<updated>2005-07-06T20:07:08Z</updated>

		<summary type="html">&lt;p&gt;JeffHill: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Directory Server ==&lt;br /&gt;
&lt;br /&gt;
EPICS ChannelAccess currently uses a broadcast mechanism for resolving&lt;br /&gt;
channel names.&lt;br /&gt;
Advantages:&lt;br /&gt;
* Minimal if not zero initial setup.&lt;br /&gt;
* At least initially very fast, because a client can send multiple name requests in one network packet, all servers receive it simultaneously and can answer to known names.&lt;br /&gt;
&lt;br /&gt;
Disadvantages:&lt;br /&gt;
* Unclear how to extend this service to redundant servers, archived data, ...&lt;br /&gt;
* Currently, no wildcard searches.&lt;br /&gt;
* Currently, no statistics on available number of channels, types of records, ...&lt;br /&gt;
* Bigger installations run into problems with broadcast traffic:&lt;br /&gt;
** All devices see the requests, even though only one server has a given channel name.&lt;br /&gt;
** Continued searches for unresolved names to overcome UDP limitations.&lt;br /&gt;
&lt;br /&gt;
As Larry Hoff pointed out, we really want a ''Directory'' server for&lt;br /&gt;
EPICS, something beyond a name server. A directory will not only map PV&lt;br /&gt;
names to IP addresses of ChannelAccess servers, but also support&lt;br /&gt;
* wildcard searches, reports on number of channels per IOC etc.&lt;br /&gt;
* redundant servers&lt;br /&gt;
* info about reduntant IOCs with the same PV, archived data for a PV&lt;br /&gt;
* backup/restore locations for a PV&lt;br /&gt;
* PV meta information like engineer-in-charge, CA security rules, ...&lt;br /&gt;
&lt;br /&gt;
== Channels, Records, PVs, Properties ==&lt;br /&gt;
We currently have records with fields and channels with properties.&lt;br /&gt;
Each field of a record can become a channel name,&lt;br /&gt;
the field itself ends up in the 'value' property of the channel,&lt;br /&gt;
and the record decides how to fill the remaining properties.&lt;br /&gt;
&lt;br /&gt;
Will the directory list all record names or all possible channels?&lt;br /&gt;
I think only record names.&lt;br /&gt;
&lt;br /&gt;
Will it include the record type? Not enough information if we add user-defined fields.&lt;br /&gt;
Will it lists all fields of a record?&lt;br /&gt;
&lt;br /&gt;
I think for now that only listing record names is enough in order to allow&lt;br /&gt;
connections.&lt;br /&gt;
&lt;br /&gt;
The CA client would then have to query the CA server for all the available properties&lt;br /&gt;
of a PV, and note that properties might even change at runtime when we allow&lt;br /&gt;
online add &amp;amp; delete.&lt;br /&gt;
&lt;br /&gt;
Whenever a tool like a command-line 'caget' or the 'probe' GUI requires a PV name,&lt;br /&gt;
it needs to be decided what properties &amp;quot;fred&amp;quot; would access. In the past, it was equal&lt;br /&gt;
to &amp;quot;fred.VAL&amp;quot;. There is much more detail in the 'view' section of the&lt;br /&gt;
[[V4 DBD Statement Syntax]].&lt;br /&gt;
&lt;br /&gt;
== LDAP, Directory, RDB, Schema, Entries, dn, cn, dc, ... ==&lt;br /&gt;
&lt;br /&gt;
The ''Lightweight Directory Access Protocol'' (LDAP) is a network protocol.&lt;br /&gt;
It defines how to access data over the network, regardless of language&lt;br /&gt;
or underlying data storage. In contrast, RDBs like Oracle or MySQL define the&lt;br /&gt;
data storage and SQL dialect, while the network access to the data is then&lt;br /&gt;
added almost as an afterthought.&lt;br /&gt;
&lt;br /&gt;
LDAP is meant as a Directory for simple attribute-based information&lt;br /&gt;
for fast, high volume lookup. Simple search filters are supported:&lt;br /&gt;
Patterns, &amp;quot;and&amp;quot;, &amp;quot;or&amp;quot;. In contrast to RDBs, there is no support for&lt;br /&gt;
arbitrary relations between entries, there are no transactions nor rollback.&lt;br /&gt;
&lt;br /&gt;
There are open-source servers for LDAP, and client libraries for&lt;br /&gt;
C, Perl, Java and other languages. MacOSX, Linux, Windows 2000&lt;br /&gt;
already include LDAP clients. MS ActiveDirectory uses LDAP.&lt;br /&gt;
&lt;br /&gt;
LDAP requires the data to be organized into hierarchical ''Entries''.&lt;br /&gt;
Each Entry has a globally unique ''Distinguished Name'' (dn),&lt;br /&gt;
and various ''Attributes'', that is Type/Value pairs.&lt;br /&gt;
The ''Schema'' defines which attributes an entry must have and which ones&lt;br /&gt;
it might have. There are existing schemas for DNS-type data or personell&lt;br /&gt;
information, including types like ''Common Name'' (cn) or ''Domain Component'' (dc),&lt;br /&gt;
but one can add custom schemata. Values might include binary data, e.g. images.&lt;br /&gt;
&lt;br /&gt;
=== Mapping EPICS PV Information to LDAP ===&lt;br /&gt;
&lt;br /&gt;
Each LDAP entry must have a unique name (dn). EPICS PVs must be unique as well,&lt;br /&gt;
but only within the search domain currently defined by the EPICS_CA_ADDR_LIST.&lt;br /&gt;
It might make sense to synchronize LDAP servers across these boundaries,&lt;br /&gt;
in which case the LDAP dn will have to include more than just the PV name.&lt;br /&gt;
For example, one could have a PV &amp;quot;fred&amp;quot; in both the accelerator and office network&lt;br /&gt;
of the SNS, and enter them into an SNS-wide LDAP directory like this:&lt;br /&gt;
&lt;br /&gt;
 fred.linac.sns.epics:  cas=&amp;quot;linacioc1:5065&amp;quot;&lt;br /&gt;
 fred.office.sns.epics: cas=&amp;quot;testioc47.sns.ornl.gov:7987&amp;quot;, description=&amp;quot;Fred's test PV&amp;quot;&lt;br /&gt;
&lt;br /&gt;
In this example, the directory includes the ChannelAccess server for both PVs,&lt;br /&gt;
and in one case also a description.&lt;br /&gt;
&lt;br /&gt;
While an EPICS-specific tool might present the data as shown above,&lt;br /&gt;
most generic LDAP tools and APIs use the ''LDAP Data Interchange Format'' (LDIF).&lt;br /&gt;
In LDIF, part of the above data could look like this:&lt;br /&gt;
&lt;br /&gt;
 dn: dc=epics&lt;br /&gt;
 objectclass: dcObject&lt;br /&gt;
 objectclass: organization&lt;br /&gt;
 o: Root of all EPICS PVs&lt;br /&gt;
 dc: epics&lt;br /&gt;
&lt;br /&gt;
 dn: dc=sns,dc=epics&lt;br /&gt;
 # Details omitted; similar to previous entry&lt;br /&gt;
&lt;br /&gt;
 dn: dc=linac,dc=sns,dc=epics&lt;br /&gt;
 objectclass: dcObject&lt;br /&gt;
 objectclass: organization&lt;br /&gt;
 o: Root of all EPICS PVs in the SNS Linac&lt;br /&gt;
 dc: linac&lt;br /&gt;
&lt;br /&gt;
 dn: cn=fred,dc=linac,dc=sns,dc=epics&lt;br /&gt;
 objectclass: ProcessVariable&lt;br /&gt;
 cn: fred&lt;br /&gt;
 cas: linacioc1:5065 &lt;br /&gt;
&lt;br /&gt;
Some points I had to learn:&lt;br /&gt;
* Each entry has an objectclass. The schema for &amp;quot;ProcessVariable&amp;quot; would for example require a &amp;quot;cn&amp;quot; attribute, with optional &amp;quot;cas&amp;quot;, &amp;quot;description&amp;quot; and maybe other attributes.&amp;lt;br&amp;gt;The schema would also determine if searches for PV names are case-sensitive or not.&lt;br /&gt;
* The hierarchical path &amp;quot;fred.linac.sns.epics&amp;quot; translates into a dn &amp;quot;cn=fred,dc=linac,dc=sns,dc=epics&amp;quot; which lists the relative dn of the entry itself and all path elements.&lt;br /&gt;
* Each path element must exists, so to bootstrap one has to create entries &amp;quot;dc=epics&amp;quot; and &amp;quot;dc=sns,dc=epics&amp;quot; etc., for which I used the pre-defined &amp;quot;organization&amp;quot; schema.&lt;br /&gt;
* To locate the PV 'fred', any of the following LDAP searches would work:&lt;br /&gt;
** Scope &amp;quot;base&amp;quot; with base &amp;quot;cn=fred,dc=linac,dc=sns,dc=epics&amp;quot;.&lt;br /&gt;
** Scope &amp;quot;one&amp;quot; with base &amp;quot;dc=linac,dc=sns,dc=epics&amp;quot; and filter &amp;quot;(cn=fred)&amp;quot;.&lt;br /&gt;
** Scope &amp;quot;one&amp;quot; with base &amp;quot;dc=linac,dc=sns,dc=epics&amp;quot; and filter &amp;quot;(cn=f*d)&amp;quot;,&amp;lt;br&amp;gt;though this might return more records which happen to match the pattern.&lt;br /&gt;
** Scope &amp;quot;sub&amp;quot; with base &amp;quot;dc=sns,dc=epics&amp;quot; and filter &amp;quot;(cn=fred)&amp;quot;,&amp;lt;br&amp;gt;which would also return an entry with dn &amp;quot;cn=fred,dc=office,dc=sns,dc=epics&amp;quot;.&lt;br /&gt;
** There is a filter option &amp;quot;~=&amp;quot; for 'approximately equal'. Unclear what exactly defines approximate, but this might be very handy for detecing typos.&lt;br /&gt;
&lt;br /&gt;
=== OpenLDAP ===&lt;br /&gt;
&lt;br /&gt;
OpenLDAP  [http://www.openldap.org] is an open-source LDAP&lt;br /&gt;
client library for C and an LDAP server which can store the&lt;br /&gt;
actual data in /dev/null, a BerkeleyDB, SQL, Perl, a remote LDAP server.&lt;br /&gt;
&lt;br /&gt;
OpenLDAP includes authentication and encrypted (SSL) transport,&lt;br /&gt;
replication (single master -&amp;gt; multiple slaves),&lt;br /&gt;
and referrals from one server to another one which has more details.&lt;br /&gt;
&lt;br /&gt;
=== EPICS PV Tests ===&lt;br /&gt;
&lt;br /&gt;
Using OpenLDAP-stable-20050429 and perl-ldap-0.3202 on a 1.3 GHz PowerBook G4&lt;br /&gt;
with 780 MB RAM under MacOS X 10.3.8, I used a perl script to create&lt;br /&gt;
PV entries, search them, and remove them.&lt;br /&gt;
In addition, the 'ldapsearch' that comes with RedHat Enterprise AS 3 was&lt;br /&gt;
used to check remote accessibillity.&lt;br /&gt;
&lt;br /&gt;
When trying to list all PVs with an appropriate search pattern,&lt;br /&gt;
the default server configuration limits the response to 500 answers.&lt;br /&gt;
This was changed such that 'paged' searches which keep requesting data&lt;br /&gt;
in increments of e.g. 500 entries are allowed to continue until all data is retrieved.&lt;br /&gt;
From the command-line tool, that's done like this:&lt;br /&gt;
 ldapsearch -x -LLL -E pr=10/noprompt -b 'dc=epics' '(cn=testpv*)'  cas&lt;br /&gt;
&lt;br /&gt;
== Performance ==&lt;br /&gt;
&lt;br /&gt;
Based on the default OpenLDAP server config with an additional&lt;br /&gt;
index &amp;quot;cn pres,eq&amp;quot; on the common name of the PVs,&lt;br /&gt;
PVs with names 'testrec0000000001', 'testrec0000000002' etc.&lt;br /&gt;
were added, then looked up one-by-one via their exact name,&lt;br /&gt;
and finially deleted one by one.&lt;br /&gt;
&lt;br /&gt;
When using a C++ test client based on the OpenLDAP library,&lt;br /&gt;
the results for smaller numbers are:&lt;br /&gt;
 Add         10000 records : 22.76 secs&lt;br /&gt;
 Locate      10000 records : 6.49 secs&lt;br /&gt;
 Delete      10000 records : 22.20 secs&lt;br /&gt;
&lt;br /&gt;
In another test, a very rough estimated PV count of the SNS linac&lt;br /&gt;
was used:&lt;br /&gt;
 Add        200000 records : 675.89 secs (38.74 CPU)&lt;br /&gt;
 Locate     200000 records : 142.85 secs (27.91 CPU)&lt;br /&gt;
 Delete     200000 records : 807.28 secs (37.28 CPU)&lt;br /&gt;
&lt;br /&gt;
Those 200000 records use about 900MB of file space.&lt;br /&gt;
The results indicate that one can add 300 .. 440 records/sec,&lt;br /&gt;
locate 1400.. 1540 records/sec and delete 250..450 records/sec.&lt;br /&gt;
Without an index, the addition and deletion will be faster&lt;br /&gt;
at the expense of lookup times.&lt;br /&gt;
&lt;br /&gt;
A typical SNS LLRF IOCs has 2300 records.&lt;br /&gt;
On startup, sending those to the directory server would take around 7 seconds.&lt;br /&gt;
A typical SNS LLRF overview screen has about 400 PVs,&lt;br /&gt;
and current connection times vary from less than a second to&lt;br /&gt;
several tens of seconds, depending on how well the search requests&lt;br /&gt;
reach the IOCs.&lt;br /&gt;
Resolving their CA servers would take about 0.3 seconds with LDAP,&lt;br /&gt;
which would then be followed by the time required to actually connect&lt;br /&gt;
to those servers.&lt;br /&gt;
&lt;br /&gt;
In previous test using perl, the individual PV search actually used an LDIF&lt;br /&gt;
filter with exact match like 'testrec0000000001'. In addition, all PVs matching&lt;br /&gt;
a filter 'testrec*' were retrieved, and no index was used:&lt;br /&gt;
 Adding   1000 records:  4 wallclock secs ( 2.29 usr +  0.14 sys =  2.43 CPU)&lt;br /&gt;
 Locating 1000 records: 49 wallclock secs ( 4.10 usr +  0.21 sys =  4.31 CPU)&lt;br /&gt;
 Match all        1000:  1 wallclock secs ( 1.18 usr +  0.02 sys =  1.20 CPU)&lt;br /&gt;
 Delete   1000 records:  4 wallclock secs ( 1.35 usr +  0.14 sys =  1.49 CPU)&lt;br /&gt;
&lt;br /&gt;
When locating individual records via the complete LDIF base without a filter,&lt;br /&gt;
the search is much faster:&lt;br /&gt;
Locating 1000 records:  5 wallclock secs ( 3.20 usr +  0.18 sys =  3.38 CPU)&lt;br /&gt;
&lt;br /&gt;
When adding an &amp;quot;index cn pres,eq&amp;quot; to the server config, the results are the&lt;br /&gt;
same for both the filter and the base search case.&lt;br /&gt;
No difference observed when tripling the cachesize from the default of 1000.&lt;br /&gt;
The behavior scales linearly with the number of channels,&lt;br /&gt;
always a little over 200 additions or lookups per second:&lt;br /&gt;
 Adding   10000 records: 47 wallclock secs (21.72 usr +  1.28 sys = 23.00 CPU)&lt;br /&gt;
 Locating 10000 records: 44 wallclock secs (32.20 usr +  1.55 sys = 33.75 CPU)&lt;br /&gt;
 Match all        10000: 15 wallclock secs (12.15 usr +  0.64 sys = 12.79 CPU)&lt;br /&gt;
 Delete   10000 records: 38 wallclock secs (15.41 usr +  1.16 sys = 16.57 CPU)&lt;br /&gt;
&lt;br /&gt;
 Adding   50000 records: 243 wallclock secs (110.36 usr +  7.18 sys = 117.54 CPU)&lt;br /&gt;
 Locating 50000 records: 226 wallclock secs (164.97 usr +  7.67 sys = 172.64 CPU)&lt;br /&gt;
 Match all        50000: 80 wallclock secs (63.09 usr +  3.42 sys = 66.51 CPU)&lt;br /&gt;
 Delete   50000 records: 219 wallclock secs (82.11 usr +  6.61 sys = 88.72 CPU)&lt;br /&gt;
&lt;br /&gt;
 Adding  200000 records: 1293 wallclock secs (483.65 usr + 33.20 sys = 516.85 CPU)&lt;br /&gt;
&lt;br /&gt;
&amp;quot;index cn,dc pres,eq,approx,sub&amp;quot; takes longer to insert/delete&lt;br /&gt;
without improved search performance:&lt;br /&gt;
 Adding   10000 records: 104 wallclock secs (26.25 usr +  1.67 sys = 27.92 CPU)&lt;br /&gt;
 Locating 10000 records: 45 wallclock secs (32.86 usr +  1.55 sys = 34.41 CPU)&lt;br /&gt;
 Match all        10000: 15 wallclock secs (12.31 usr +  0.47 sys = 12.78 CPU)&lt;br /&gt;
 Delete   10000 records: 97 wallclock secs (17.89 usr +  1.34 sys = 19.23 CPU)&lt;br /&gt;
&lt;br /&gt;
The CPU load is a rough 50/50 split between the perl and slapd processes.&lt;br /&gt;
The perl ldap library is 100% perl, including the network handling and&lt;br /&gt;
quite some data conversions from arrays into hashes and back,&lt;br /&gt;
so a pure C client might be a little faster.&lt;br /&gt;
&lt;br /&gt;
Though an index slows down the insertion of PVs, it speeds up certain&lt;br /&gt;
retrieval methods, as probably desired for an EPICS directory server.&lt;br /&gt;
The search mechanism is based on round-trip requests.&lt;br /&gt;
Searching PVs one PV name at a time is slower than requesting all&lt;br /&gt;
PVs that match a pattern. Unfortunately, typical CA clients will&lt;br /&gt;
have to request data for specific PV names, not by pattern.&lt;br /&gt;
&lt;br /&gt;
JOH: For comparison purposes, here is the performance of CA's built-in name resolution. &lt;br /&gt;
&lt;br /&gt;
Testing with 10000 channels named joh:bill&lt;br /&gt;
&lt;br /&gt;
channel connect test&lt;br /&gt;
&lt;br /&gt;
Elapsed Per Item =   0.00002349 sec,    42570.2 Items per sec, 22.5 Mbps&lt;br /&gt;
&lt;br /&gt;
Search tries per chan - mean=1.006200 std dev=0.078496 min=1.000000 max=2.000000&lt;br /&gt;
&lt;br /&gt;
=== To be investigated ===&lt;br /&gt;
&lt;br /&gt;
* How to access it from vxWorks&lt;br /&gt;
* How does an LDAP server used for EPICS cooperate with existing LDAP servers for DNS, email etc. Should it be one and the same? Use special port numbers for 'EPICS' LDAP?&lt;br /&gt;
* API: What type of API would EPICS tools use? Whatever LDAP library they use? An 'EPICS wrapper' around LDAP? Gasper suggested to look at the Java JNDI API for inspiration.&lt;br /&gt;
* Common Database headaches:&lt;br /&gt;
** To simply get a PV into LDAP, one has to check if this PV already exists and then either 'add' or 'modify'.&lt;br /&gt;
** What if a channel is no longer available? An IOC shutting down could remove PVs from the LDAP server, but an IOC that crashes won't.&lt;br /&gt;
* Replication: How to use it, how fast is it etc.&lt;br /&gt;
* Authentication and encryption: How hard is it to configure?&lt;/div&gt;</summary>
		<author><name>JeffHill</name></author>
	</entry>
	<entry>
		<id>https://wiki-ext.aps.anl.gov/epics/index.php?title=Talk:V4_Design:_epicsTypes&amp;diff=2744</id>
		<title>Talk:V4 Design: epicsTypes</title>
		<link rel="alternate" type="text/html" href="https://wiki-ext.aps.anl.gov/epics/index.php?title=Talk:V4_Design:_epicsTypes&amp;diff=2744"/>
		<updated>2005-06-16T16:33:20Z</updated>

		<summary type="html">&lt;p&gt;JeffHill: more comments&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Here are my comments&lt;br /&gt;
&lt;br /&gt;
1) All of the readers here probably already know that I feel that the unsigned types in C are useful. Well written code range checks operands, and unsigned operands typically require less range checking. When problems occur it's because users convert between signed and unsigned types without proper range checking. Since data access has this range checking built in (after considerable effort on mine and Ralph's part I will add) then conversion problems are possibly no longer an issue.&lt;br /&gt;
&lt;br /&gt;
2) You have created interface classes for buffers, arrays, enumerated, strings etc. All of these interfaces are already in data access. Was there a good justification to create new ones? In any case, it seems that we should have the goal of using the same interfaces for each of the fundamental data types?&lt;br /&gt;
&lt;br /&gt;
3) These interfaces seem to require contiguous storage of random sized blocks of characters. Doesn’t this preclude use of fixed length buffer based (free list based) memory allocation, and therefore almost guarantee fragmentation of memory. Note that fragmentation isnt just a binary condition (memory of a particular size is or isnt available). Fragmentation is also an efficency isssue because most random sized block memory allocators require searching for the best sized free block. Note that one of my goals for V4 is to no longer require EPICS_CA_MAX_ARRAY_BYTES.&lt;br /&gt;
&lt;br /&gt;
More comments:&lt;br /&gt;
&lt;br /&gt;
&amp;gt; &amp;gt; In any case, it seems &lt;br /&gt;
&amp;gt; &amp;gt; that we should have the goal of using the same interfaces for each of &lt;br /&gt;
&amp;gt; &amp;gt; the fundamental data types?&lt;br /&gt;
&amp;gt; Agreed about the goal, but your interfaces don't necessarily take into &lt;br /&gt;
&amp;gt; account all of our requirements, and we think some of your interfaces &lt;br /&gt;
&amp;gt; are stricter than they need to be, which harms performance.  I suspect &lt;br /&gt;
&amp;gt; we would have few problems implementing most of your interfaces on top &lt;br /&gt;
&amp;gt; of ours, but adopting ours should be more efficient since you don't have &lt;br /&gt;
&amp;gt; to do everything one character or element at a time - we expose a whole &lt;br /&gt;
&amp;gt; segment at once.&lt;br /&gt;
&lt;br /&gt;
1) I think that the above comment applies only to strings as all other types in data access are accessed in chunks - allowing the highest level of performance. &lt;br /&gt;
&lt;br /&gt;
2) The data access string interface StringSegment certainly does force all string access through a stream interface indexed int wide getChar/putChar. I wanted to support all character widths through one interface. I was inclined to conclude that if they are communicating in strings they can't be too concerned about performance. I was also, I admit, not thinking about UTF-8.&lt;br /&gt;
&lt;br /&gt;
3) Since your interface allows writing multiple characters to the string at a time doesn’t this force a UTF-8 implementation of complex characters (contrary to what I seem to recall reading in your doc)? &lt;br /&gt;
&lt;br /&gt;
4) Forcing UTF-8 probably isn’t a bad idea. I would be amenable to just saying that if we will have wide characters they will be UTF-8. This would be a real nice simplification of course when compressing the data for the CA protocol. The StringSegment interface in data access certainly could be revised to allow blocks of characters to be read/written in UTF-8 format (assuming that all strings are streams of octets).&lt;br /&gt;
&lt;br /&gt;
5) We should carefully consider implementations and interfaces, and how they may become dependent on each other. Of course, for review, interfaces are pure virtual and implementations have data in them. For fundamental types we should be careful about making implementation dependent on implementations because we can end up with code maintenance issues (been there, done that). I notice that EpicsEnum is an implementation and it is based on EpicsString - another implementation. In contrast, the data access StringSegment interface is just an interface. Another example is EpicsArray which is admitted to not be type safe. That might be fine as an internal scaffolding for an array, but when crossing boundaries between components the interface presented by data access might be more appropriate because it *is* type safe.&lt;br /&gt;
&lt;br /&gt;
6) I used a stream type of interface as a foundation for the StringSegment interface. This appears to be a nice approach in my IMHO. By the way, I did look at basing strings on stream strings in the C++ standard library but gave up on that when I realized that most implementations were calling malloc in the stream objects constructor - too much overhead for temporary object mapping protocol streams so that they can cross interfaces. The fundamental problem here by the way is that the standard library made the core stream an implementation, and not an interface.&lt;br /&gt;
&lt;br /&gt;
7) Dejavu. I am always defining interfaces without epics in their name which are subsequently superseded by revised interfaces that do. Who owns this EPICS name anyways? This is vaguely reminiscent of IBM calling there computer the &amp;quot;personal computer&amp;quot; and Microsoft calling there window system &amp;quot;windows&amp;quot; - whoever owns the most generic name wins :-). Is it somewhat redundant to have to type epics every time that I type an interface name? Should there be a C++ namespace called &amp;quot;epics&amp;quot;? Is that too course of a granularity for a name space, and possibly also too limiting for generic things like fundamental types (is this buffer only useable with EPICS)?&lt;br /&gt;
&lt;br /&gt;
8) I notice that some of these classes hand off pointers to internal storage. EpicsBuffer does this of course when we are granted access to a buffer segment, and some of the other do it also when they return a pointer to the buffer creator (it should probably be a reference that is returned). The problem is that users may continue to use handles to internal objects after the object that owns them (and manages there existence) don’t exist. Admittedly, a buffer is a very low level object and you might make exceptions for performance reasons. However, when these C++ systems become large and complex object lifespan mistakes seem to be one of the primary failure modes. In any case I tried to avoid this in data access by making all buffer internal access occur only during the duration of the callback. It's clear in the callback that we can only access the incoming arguments for the duration of the callback. The performance is the same because we still have direct access to large chunks.&lt;br /&gt;
&lt;br /&gt;
9) I really do feel that using unsigned types for integers that should never be negative is best. Oh well, perhaps I am the only one yelling this out from the bottom of a well, and no one is listening anyways.&lt;br /&gt;
&lt;br /&gt;
&amp;gt; Go back and read the section on the EpicsBuffer interface again; &lt;br /&gt;
&amp;gt; none of our classes require contiguous buffer storage.  &lt;br /&gt;
&lt;br /&gt;
Sorry, after reflecting more carefully on the code snippets (yes, I do that too) I now understand what is being done. This buffer thingy is an implementation, and not an interface, and yes it does allow segmented storage.&lt;br /&gt;
&lt;br /&gt;
&amp;gt; Since we never really write down and agree what all the detailed &lt;br /&gt;
&amp;gt; requirements are, but just present each other with code snippets that &lt;br /&gt;
&amp;gt; implement our view of them, I think we're going to continue to have &lt;br /&gt;
&amp;gt; disagreements like these.  It would speed things up immensely if we &lt;br /&gt;
&amp;gt; could first agree in writing on what we are going to accomplish *before* &lt;br /&gt;
&amp;gt; we actually start implementing it (and I plead as guilty as everyone &lt;br /&gt;
&amp;gt; else on that charge).&lt;br /&gt;
&lt;br /&gt;
I think that this is another way of expressing a desire for better coordination of the overall design process. Coordination is good and more of it can't be worse than the current situation (almost none). However, dialog like this shouldn’t be seen as a problem either. Coordination without dialog (multiple voices) would probably be worse.&lt;br /&gt;
&lt;br /&gt;
&amp;gt; The current definition of epicsTypes does NOT include unsigned &lt;br /&gt;
&amp;gt; types. The reason is Java. If we allow unsigned types it makes &lt;br /&gt;
&amp;gt; it very difficult to complely support Java.&lt;br /&gt;
&lt;br /&gt;
There is possibly another way of looking at this. With Java we must use an integer type that has sufficient range to hold the magnitude of the integer number used in C. This statement is true irregardless of whether the C type is a signed or unsigned integer. Data Access will of course detect problems where the integer magnitude in the server does not map to the range of the data type of the client, and report them as exception call backs. We use unsigned integer types because their domain fits better with the arithmetic that is being conducted, and not because of their slightly higher positive range. Relying on the extra range would be flying too close to the trees IMHO. With bit fields if we have the option to address the bit field by its offset and length then we will almost never need to perform arithmetic directly on an unsigned 32 or 64 bit field. That’s a good thing. Otherwise Java might find itself pickled when communicating with hardware ;-)&lt;br /&gt;
&lt;br /&gt;
&amp;gt; I am again haunted by Doug's request for &amp;quot;hello world&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
If we provide some basic types ala db_access.h that are already interfaced by data access then data access shouldn’t need to be seen by naïve users. No doubt that we will layer a caGet and a caPut which will take &amp;quot;hello world&amp;quot; as a parameter.&lt;/div&gt;</summary>
		<author><name>JeffHill</name></author>
	</entry>
	<entry>
		<id>https://wiki-ext.aps.anl.gov/epics/index.php?title=Talk:V4_Design:_epicsTypes&amp;diff=289</id>
		<title>Talk:V4 Design: epicsTypes</title>
		<link rel="alternate" type="text/html" href="https://wiki-ext.aps.anl.gov/epics/index.php?title=Talk:V4_Design:_epicsTypes&amp;diff=289"/>
		<updated>2005-06-15T23:16:43Z</updated>

		<summary type="html">&lt;p&gt;JeffHill: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Here are my comments&lt;br /&gt;
&lt;br /&gt;
1) All of the readers here probably already know that I feel that the unsigned types in C are useful. Well written code range checks operands, and unsigned operands typically require less range checking. When problems occur it's because users convert between signed and unsigned types without proper range checking. Since data access has this range checking built in (after considerable effort on mine and Ralph's part I will add) then conversion problems are possibly no longer an issue.&lt;br /&gt;
&lt;br /&gt;
2) You have created interface classes for buffers, arrays, enumerated, strings etc. All of these interfaces are already in data access. Was there a good justification to create new ones? In any case, it seems that we should have the goal of using the same interfaces for each of the fundamental data types?&lt;br /&gt;
&lt;br /&gt;
3) These interfaces seem to require contiguous storage of random sized blocks of characters. Doesn’t this preclude use of fixed length buffer based (free list based) memory allocation, and therefore almost guarantee fragmentation of memory. Note that fragmentation isnt just a binary condition (memory of a particular size is or isnt available). Fragmentation is also an efficency isssue because most random sized block memory allocators require searching for the best sized free block. Note that one of my goals for V4 is to no longer require EPICS_CA_MAX_ARRAY_BYTES.&lt;br /&gt;
&lt;br /&gt;
More comments:&lt;br /&gt;
&lt;br /&gt;
&amp;gt; &amp;gt; In any case, it seems &lt;br /&gt;
&amp;gt; &amp;gt; that we should have the goal of using the same interfaces for each of &lt;br /&gt;
&amp;gt; &amp;gt; the fundamental data types?&lt;br /&gt;
&amp;gt; Agreed about the goal, but your interfaces don't necessarily take into &lt;br /&gt;
&amp;gt; account all of our requirements, and we think some of your interfaces &lt;br /&gt;
&amp;gt; are stricter than they need to be, which harms performance.  I suspect &lt;br /&gt;
&amp;gt; we would have few problems implementing most of your interfaces on top &lt;br /&gt;
&amp;gt; of ours, but adopting ours should be more efficient since you don't have &lt;br /&gt;
&amp;gt; to do everything one character or element at a time - we expose a whole &lt;br /&gt;
&amp;gt; segment at once.&lt;br /&gt;
&lt;br /&gt;
1) I think that the above comment applies only to strings as all other types in data access are accessed in chunks - allowing the highest level of performance. &lt;br /&gt;
&lt;br /&gt;
2) The data access string interface StringSegment certainly does force all string access through a stream interface indexed int wide getChar/putChar. I wanted to support all character widths through one interface. I was inclined to conclude that if they are communicating in strings they can't be too concerned about performance. I was also, I admit, not thinking about UTF-8.&lt;br /&gt;
&lt;br /&gt;
3) Since your interface allows writing multiple characters to the string at a time doesn’t this force a UTF-8 implementation of complex characters (contrary to what I seem to recall reading in your doc)? &lt;br /&gt;
&lt;br /&gt;
4) Forcing UTF-8 probably isn’t a bad idea. I would be amenable to just saying that if we will have wide characters they will be UTF-8. This would be a real nice simplification of course when compressing the data for the CA protocol. The StringSegment interface in data access certainly could be revised to allow blocks of characters to be read/written in UTF-8 format (assuming that all strings are streams of octets).&lt;br /&gt;
&lt;br /&gt;
5) We should carefully consider implementations and interfaces, and how they may become dependent on each other. Of course, for review, interfaces are pure virtual and implementations have data in them. For fundamental types we should be careful about making implementation dependent on implementations because we can end up with code maintenance issues (been there, done that). I notice that EpicsEnum is an implementation and it is based on EpicsString - another implementation. In contrast, the data access StringSegment interface is just an interface. Another example is EpicsArray which is admitted to not be type safe. That might be fine as an internal scaffolding for an array, but when crossing boundaries between components the interface presented by data access might be more appropriate because it *is* type safe.&lt;br /&gt;
&lt;br /&gt;
6) I used a stream type of interface as a foundation for the StringSegment interface. This appears to be a nice approach in my IMHO. By the way, I did look at basing strings on stream strings in the C++ standard library but gave up on that when I realized that most implementations were calling malloc in the stream objects constructor - too much overhead for temporary object mapping protocol streams so that they can cross interfaces. The fundamental problem here by the way is that the standard library made the core stream an implementation, and not an interface.&lt;br /&gt;
&lt;br /&gt;
7) Dejavu. I am always defining interfaces without epics in their name which are subsequently superseded by revised interfaces that do. Who owns this EPICS name anyways? This is vaguely reminiscent of IBM calling there computer the &amp;quot;personal computer&amp;quot; and Microsoft calling there window system &amp;quot;windows&amp;quot; - whoever owns the most generic name wins :-). Is it somewhat redundant to have to type epics every time that I type an interface name? Should there be a C++ namespace called &amp;quot;epics&amp;quot;? Is that too course of a granularity for a name space, and possibly also too limiting for generic things like fundamental types (is this buffer only useable with EPICS)?&lt;br /&gt;
&lt;br /&gt;
8) I notice that some of these classes hand off pointers to internal storage. EpicsBuffer does this of course when we are granted access to a buffer segment, and some of the other do it also when they return a pointer to the buffer creator (it should probably be a reference that is returned). The problem is that users may continue to use handles to internal objects after the object that owns them (and manages there existence) don’t exist. Admittedly, a buffer is a very low level object and you might make exceptions for performance reasons. However, when these C++ systems become large and complex object lifespan mistakes seem to be one of the primary failure modes. In any case I tried to avoid this in data access by making all buffer internal access occur only during the duration of the callback. It's clear in the callback that we can only access the incoming arguments for the duration of the callback. The performance is the same because we still have direct access to large chunks.&lt;br /&gt;
&lt;br /&gt;
9) I really do feel that using unsigned types for integers that should never be negative is best. Oh well, perhaps I am the only one yelling this out from the bottom of a well, and no one is listening anyways.&lt;br /&gt;
&lt;br /&gt;
&amp;gt; Go back and read the section on the EpicsBuffer interface again; &lt;br /&gt;
&amp;gt; none of our classes require contiguous buffer storage.  &lt;br /&gt;
&lt;br /&gt;
Sorry, after reflecting more carefully on the code snippets (yes, I do that too) I now understand what is being done. This buffer thingy is an implementation, and not an interface, and yes it does allow segmented storage.&lt;br /&gt;
&lt;br /&gt;
&amp;gt; Since we never really write down and agree what all the detailed &lt;br /&gt;
&amp;gt; requirements are, but just present each other with code snippets that &lt;br /&gt;
&amp;gt; implement our view of them, I think we're going to continue to have &lt;br /&gt;
&amp;gt; disagreements like these.  It would speed things up immensely if we &lt;br /&gt;
&amp;gt; could first agree in writing on what we are going to accomplish *before* &lt;br /&gt;
&amp;gt; we actually start implementing it (and I plead as guilty as everyone &lt;br /&gt;
&amp;gt; else on that charge).&lt;br /&gt;
&lt;br /&gt;
I think that this is another way of expressing a desire for better coordination of the overall design process. Coordination is good and more of it can't be worse than the current situation (almost none). However, dialog like this shouldn’t be seen as a problem either. Coordination without dialog (multiple voices) would probably be worse.&lt;/div&gt;</summary>
		<author><name>JeffHill</name></author>
	</entry>
	<entry>
		<id>https://wiki-ext.aps.anl.gov/epics/index.php?title=Talk:V4_Design:_epicsTypes&amp;diff=288</id>
		<title>Talk:V4 Design: epicsTypes</title>
		<link rel="alternate" type="text/html" href="https://wiki-ext.aps.anl.gov/epics/index.php?title=Talk:V4_Design:_epicsTypes&amp;diff=288"/>
		<updated>2005-06-14T22:07:20Z</updated>

		<summary type="html">&lt;p&gt;JeffHill: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Here are my comments&lt;br /&gt;
&lt;br /&gt;
1) All of the readers here probably already know that I feel that the unsigned types in C are useful. Well written code range checks operands, and unsigned operands typically require less range checking. When problems occur it's because users convert between signed and unsigned types without proper range checking. Since data access has this range checking built in (after considerable effort on mine and Ralph's part I will add) then conversion problems are possibly no longer an issue.&lt;br /&gt;
&lt;br /&gt;
2) You have created interface classes for buffers, arrays, enumerated, strings etc. All of these interfaces are already in data access. Was there a good justification to create new ones? In any case, it seems that we should have the goal of using the same interfaces for each of the fundamental data types?&lt;br /&gt;
&lt;br /&gt;
3) These interfaces seem to require contiguous storage of random sized blocks of characters. Doesn’t this preclude use of fixed length buffer based (free list based) memory allocation, and therefore almost guarantee fragmentation of memory. Note that fragmentation isnt just a binary condition (memory of a particular size is or isnt available). Fragmentation is also an efficency isssue because most random sized block memory allocators require searching for the best sized free block. Note that one of my goals for V4 is to no longer require EPICS_CA_MAX_ARRAY_BYTES.&lt;/div&gt;</summary>
		<author><name>JeffHill</name></author>
	</entry>
	<entry>
		<id>https://wiki-ext.aps.anl.gov/epics/index.php?title=Talk:V4_Design:_epicsTypes&amp;diff=282</id>
		<title>Talk:V4 Design: epicsTypes</title>
		<link rel="alternate" type="text/html" href="https://wiki-ext.aps.anl.gov/epics/index.php?title=Talk:V4_Design:_epicsTypes&amp;diff=282"/>
		<updated>2005-06-14T22:06:32Z</updated>

		<summary type="html">&lt;p&gt;JeffHill: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Here are my comments&lt;br /&gt;
&lt;br /&gt;
1) All of the readers here probably already know that I feel that the unsigned types in C are useful. Well written code range checks operands, and unsigned operands typically require less range checking. When problems occur it's because users convert between signed and unsigned types without proper range checking. Since data access has this range checking built in (after considerable effort on mine and Ralph's part I will add) then conversion problems are possibly no longer an issue.&lt;br /&gt;
&lt;br /&gt;
2) You have created interface classes for buffers, arrays, enumerated, strings etc. All of these interfaces are already in data access. Was there a good justification to create new ones? In any case, it seems that we should have the goal of using the same interfaces for each of the fundamental data types?&lt;br /&gt;
&lt;br /&gt;
3) These interfaces seem to require contiguous storage of random sized blocks of characters. Doesn’t this preclude use of fixed length buffer based (free list based) memory allocation, and therefore almost guarantee fragmentation of memory. Note that fragmentation isnt just a binary condition (memory of a particular size is or isnt available). Fragmentation is also an efficency isssue because most random sized block memory allocators require searching for the best sized free block.&lt;/div&gt;</summary>
		<author><name>JeffHill</name></author>
	</entry>
	<entry>
		<id>https://wiki-ext.aps.anl.gov/epics/index.php?title=Talk:V4_Design:_epicsTypes&amp;diff=281</id>
		<title>Talk:V4 Design: epicsTypes</title>
		<link rel="alternate" type="text/html" href="https://wiki-ext.aps.anl.gov/epics/index.php?title=Talk:V4_Design:_epicsTypes&amp;diff=281"/>
		<updated>2005-06-14T21:46:29Z</updated>

		<summary type="html">&lt;p&gt;JeffHill: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Here are my comments&lt;br /&gt;
&lt;br /&gt;
1) As we are all already aware I feel that the unsigned types in C are useful. When problems occur it's because users convert between signed and unsigned types without proper range checking. Since data access has this range checking built in (after considerable effort on mine and Ralph's part I will add) then conversion problems are possibly no longer an issue.&lt;br /&gt;
&lt;br /&gt;
2) You have created interface classes for buffers, arrays, enumerated, strings etc. All of these interfaces are already in data access. Was there a good justification to create new ones? In any case, it seems that we should have the goal of using the same interfaces for each type of commonly used data.&lt;br /&gt;
&lt;br /&gt;
3) These interfaces seem to require contiguous storage of random sized blocks of characters. Doesn’t this preclude use of fixed length buffer based (free list based) memory allocation, and therefore almost guarantee fragmentation of memory.&lt;/div&gt;</summary>
		<author><name>JeffHill</name></author>
	</entry>
	<entry>
		<id>https://wiki-ext.aps.anl.gov/epics/index.php?title=Talk:V4_Design:_epicsTypes&amp;diff=280</id>
		<title>Talk:V4 Design: epicsTypes</title>
		<link rel="alternate" type="text/html" href="https://wiki-ext.aps.anl.gov/epics/index.php?title=Talk:V4_Design:_epicsTypes&amp;diff=280"/>
		<updated>2005-06-14T21:44:48Z</updated>

		<summary type="html">&lt;p&gt;JeffHill: my comments&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Here are my comments&lt;br /&gt;
&lt;br /&gt;
1) As we are all already aware I feel that the unsigned types in C are useful. When problems occur it's because users convert between signed and unsigned types without proper range checking. Since data access has this range checking built in (after considerable effort on mine and Ralph's part I will add) then conversion problems are possibly no longer an issue.&lt;br /&gt;
&lt;br /&gt;
2) You have created interface classes for buffers, arrays, enumerated, strings etc. All of these interfaces are already in data access. Was there a good justification to create new ones? In any case, it seems that we should the goal of using the same interfaces for each type of commonly used data.&lt;br /&gt;
&lt;br /&gt;
3) These interfaces seem to require contiguous storage of random sized blocks of characters. Doesn’t this preclude use of fixed length buffer based (free list based) memory allocation, and therefore almost guarantee fragmentation of memory.&lt;/div&gt;</summary>
		<author><name>JeffHill</name></author>
	</entry>
	<entry>
		<id>https://wiki-ext.aps.anl.gov/epics/index.php?title=Talk:V4_CA_Interfaces&amp;diff=2728</id>
		<title>Talk:V4 CA Interfaces</title>
		<link rel="alternate" type="text/html" href="https://wiki-ext.aps.anl.gov/epics/index.php?title=Talk:V4_CA_Interfaces&amp;diff=2728"/>
		<updated>2005-05-20T19:35:03Z</updated>

		<summary type="html">&lt;p&gt;JeffHill: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Some comments from Andrew Johnson:&lt;br /&gt;
&lt;br /&gt;
In your presentation about CA V4, you included the method &lt;br /&gt;
channel::createAllPropertiesReadRequest().  I agree that we need a way &lt;br /&gt;
to be able to read all of the properties available from the server for a &lt;br /&gt;
particular PV name, but I want more flexibility than just being able to &lt;br /&gt;
put that wild-card at the top of my request.&lt;br /&gt;
&lt;br /&gt;
I think we need the ability to be able to subscribe with a property &lt;br /&gt;
catalog having a specific set of properties at one level but to &lt;br /&gt;
wild-card a sub-property catalog at some level below.  Is this currently &lt;br /&gt;
possible?  If not, please consider this a request to add that &lt;br /&gt;
capability, which might then remove the need for the seperate &lt;br /&gt;
createAllPropertiesReadRequest() method.  I'm only looking for you to &lt;br /&gt;
support &amp;quot;*&amp;quot;, no pattern matching or regex stuff.&lt;br /&gt;
&lt;br /&gt;
Some comments from Jeff Hill:&lt;br /&gt;
&lt;br /&gt;
During our meeting I raised a question; do we may need a Data Access interface allowing traversal of the structure of the property hierarchy, learning the native type of the properties, but not require instances of the properties?&lt;br /&gt;
&lt;br /&gt;
There may be legitimate situations where the property catalog egg must come before the property catalog chicken. Furthermore, it might be inconvenient from a memory management perspective to require an instance of an array before it is really used. I think that this negative could be perhaps minimized if we state in the CA manual that the array bounds alone will be examined, and the array elements will not be traversed, when scanning a property catalog to learn its structure.&lt;br /&gt;
&lt;br /&gt;
Probably the only negative associated with adding a property catalog structure traverse capability to the interface would be that the application would need to provide one additional function. They are already providing an immutable traverse, a mutable traverse function, and an immutable find function. What is vexing is that in many situations all three of the traverse functions are nearly identical. Personally, I don’t like to see common code managed with cut and paste. I am even less fond of that eventuality should it be repeated for many, many data structures in a proliferation of applications. &lt;br /&gt;
&lt;br /&gt;
So I had a look at what level of Data Access library support might be provided so that they need write the guts of the traverse function only once. The following is an example of how they might structure their application. There are still three traverse functions because cross library binding requires the virtual base class interfaced technique, but now they can use a template to implement the traversing only once.&lt;br /&gt;
&lt;br /&gt;
This level of complication appears to be reasonable for end user applications. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
PropertyId propertyX;&lt;br /&gt;
PropertyId propertyY;&lt;br /&gt;
PropertyId propertyZ;&lt;br /&gt;
PropertyId propertyI;&lt;br /&gt;
&lt;br /&gt;
class MyContainer : private PropertyCatalog {&lt;br /&gt;
public:&lt;br /&gt;
&lt;br /&gt;
private:&lt;br /&gt;
    int x;&lt;br /&gt;
    float y;&lt;br /&gt;
    double z;&lt;br /&gt;
    char i;&lt;br /&gt;
    static void traverse ( &lt;br /&gt;
        PropertyDescriptionViewer &amp;amp; );&lt;br /&gt;
    void traverse ( &lt;br /&gt;
        PropertyManipulator &amp;amp; );&lt;br /&gt;
    void traverse ( &lt;br /&gt;
        PropertyViewer &amp;amp; ) const;&lt;br /&gt;
    bool find ( &lt;br /&gt;
        const PropertyId &amp;amp; id, PropertyViewer &amp;amp; ) const;&lt;br /&gt;
    template &amp;lt; class REFERENCE, class MANIPULATOR &amp;gt;&lt;br /&gt;
    static void traverseTempl ( &lt;br /&gt;
        const REFERENCE &amp;amp;, MANIPULATOR &amp;amp; );&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
template &amp;lt; class REFERENCE, class MANIPULATOR &amp;gt;&lt;br /&gt;
inline void MyContainer::traverseTempl ( &lt;br /&gt;
    const REFERENCE &amp;amp; ref, MANIPULATOR &amp;amp; manipulator )&lt;br /&gt;
{&lt;br /&gt;
    ref.reveal ( &lt;br /&gt;
        manipulator, propertyX, &amp;amp; MyContainer::x );&lt;br /&gt;
    ref.reveal ( &lt;br /&gt;
        manipulator, propertyY, &amp;amp; MyContainer::y );&lt;br /&gt;
    ref.reveal ( &lt;br /&gt;
        manipulator, propertyZ, &amp;amp; MyContainer::z );&lt;br /&gt;
    ref.reveal ( &lt;br /&gt;
        manipulator, propertyI, &amp;amp; MyContainer::i );&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void MyContainer::traverse ( &lt;br /&gt;
    PropertyManipulator &amp;amp; manipulator ) &lt;br /&gt;
{&lt;br /&gt;
    MyContainer::traverseTempl ( &lt;br /&gt;
        reference &amp;lt; MyContainer &amp;gt; ( *this ), manipulator );&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void MyContainer::traverse ( &lt;br /&gt;
    PropertyViewer &amp;amp; viewer ) const &lt;br /&gt;
{&lt;br /&gt;
    MyContainer::traverseTempl ( &lt;br /&gt;
        reference &amp;lt; const MyContainer &amp;gt; ( *this ), viewer );&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void MyContainer::traverse ( &lt;br /&gt;
    PropertyDescriptionViewer &amp;amp; viewer )&lt;br /&gt;
{&lt;br /&gt;
    MyContainer::traverseTempl ( reference &amp;lt; void &amp;gt; (), viewer );&lt;br /&gt;
}&lt;br /&gt;
    &lt;br /&gt;
bool MyContainer::find ( &lt;br /&gt;
    const PropertyId &amp;amp; id, &lt;br /&gt;
    PropertyManipulator &amp;lt; Property &amp;gt; &amp;amp; manipulator ) const &lt;br /&gt;
{&lt;br /&gt;
    bool status = false;&lt;br /&gt;
    if ( id == propertyX ) {&lt;br /&gt;
    	manipulator.reveal ( &lt;br /&gt;
    	    Property &amp;lt; const int &amp;gt; ( propertyX, this-&amp;gt;x ) );&lt;br /&gt;
        status = true;&lt;br /&gt;
    }&lt;br /&gt;
    else ( id == propertyY ) {&lt;br /&gt;
    	manipulator.reveal ( &lt;br /&gt;
    	    Property &amp;lt; const int &amp;gt; ( propertyY, this-&amp;gt;y ) );&lt;br /&gt;
        status = true;&lt;br /&gt;
    }&lt;br /&gt;
    return status;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;/div&gt;</summary>
		<author><name>JeffHill</name></author>
	</entry>
	<entry>
		<id>https://wiki-ext.aps.anl.gov/epics/index.php?title=Talk:V4_CA_Interfaces&amp;diff=187</id>
		<title>Talk:V4 CA Interfaces</title>
		<link rel="alternate" type="text/html" href="https://wiki-ext.aps.anl.gov/epics/index.php?title=Talk:V4_CA_Interfaces&amp;diff=187"/>
		<updated>2005-05-20T19:32:31Z</updated>

		<summary type="html">&lt;p&gt;JeffHill: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Some comments from Andrew Johnson:&lt;br /&gt;
&lt;br /&gt;
In your presentation about CA V4, you included the method &lt;br /&gt;
channel::createAllPropertiesReadRequest().  I agree that we need a way &lt;br /&gt;
to be able to read all of the properties available from the server for a &lt;br /&gt;
particular PV name, but I want more flexibility than just being able to &lt;br /&gt;
put that wild-card at the top of my request.&lt;br /&gt;
&lt;br /&gt;
I think we need the ability to be able to subscribe with a property &lt;br /&gt;
catalog having a specific set of properties at one level but to &lt;br /&gt;
wild-card a sub-property catalog at some level below.  Is this currently &lt;br /&gt;
possible?  If not, please consider this a request to add that &lt;br /&gt;
capability, which might then remove the need for the seperate &lt;br /&gt;
createAllPropertiesReadRequest() method.  I'm only looking for you to &lt;br /&gt;
support &amp;quot;*&amp;quot;, no pattern matching or regex stuff.&lt;br /&gt;
&lt;br /&gt;
Some comments from Jeff Hill:&lt;br /&gt;
&lt;br /&gt;
During our meeting I raised a question; do we may need a Data Access interface allowing traversal of the structure of the property hierarchy, learning the native type of the properties, but not require instances of the properties?&lt;br /&gt;
&lt;br /&gt;
There may be legitimate situations where the property catalog egg must come before the property catalog chicken. Furthermore, it might be inconvenient from a memory management perspective to require an instance of an array before it is really used. I think that this negative could be perhaps minimized if we state in the CA manual that the array bounds alone will be examined, and the array elements will not be traversed, when scanning a property catalog to learn its structure.&lt;br /&gt;
&lt;br /&gt;
Probably the only negative associated with adding a property catalog structure traverse capability to the interface would be that the application would need to provide one additional function. They are already providing an immutable traverse, a mutable traverse function, and an immutable find function. What is vexing is that in many situations all three of the traverse functions are nearly identical. Personally, I don’t like to see common code managed with cut and paste. I am even less fond of that eventuality should it be repeated for many, many data structures in a proliferation of applications. &lt;br /&gt;
&lt;br /&gt;
So I had a look at what level of Data Access library support might be provided so that they need write the guts of the traverse function only once. The following is an example of how they might structure their application. There are still three traverse functions because cross library binding requires the virtual base class interfaced technique, but now they can use a template to implement the traversing only once.&lt;br /&gt;
&lt;br /&gt;
This level of complication appears to be reasonable for end user applications. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
PropertyId propertyX;&lt;br /&gt;
PropertyId propertyY;&lt;br /&gt;
PropertyId propertyZ;&lt;br /&gt;
PropertyId propertyI;&lt;br /&gt;
&lt;br /&gt;
class MyContainer : private PropertyCatalog {&lt;br /&gt;
public:&lt;br /&gt;
&lt;br /&gt;
private:&lt;br /&gt;
    int x;&lt;br /&gt;
    float y;&lt;br /&gt;
    double z;&lt;br /&gt;
    char i;&lt;br /&gt;
    static void traverse ( &lt;br /&gt;
        PropertyDescriptionViewer &amp;amp; );&lt;br /&gt;
    void traverse ( &lt;br /&gt;
        PropertyManipulator &amp;amp; );&lt;br /&gt;
    void traverse ( &lt;br /&gt;
        PropertyViewer &amp;amp; ) const;&lt;br /&gt;
    bool find ( &lt;br /&gt;
        const PropertyId &amp;amp; id, PropertyViewer &amp;amp; ) const;&lt;br /&gt;
    template &amp;lt; class REFERENCE, class MANIPULATOR &amp;gt;&lt;br /&gt;
    static void traverseTempl ( &lt;br /&gt;
        const REFERENCE &amp;amp;, MANIPULATOR &amp;amp; );&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
template &amp;lt; class REFERENCE, class MANIPULATOR &amp;gt;&lt;br /&gt;
inline void MyContainer::traverseTempl ( &lt;br /&gt;
    const REFERENCE &amp;amp; ref, MANIPULATOR &amp;amp; manipulator )&lt;br /&gt;
{&lt;br /&gt;
    ref.reveal ( &lt;br /&gt;
        manipulator, propertyX, &amp;amp; MyContainer::x );&lt;br /&gt;
    ref.reveal ( &lt;br /&gt;
        manipulator, propertyY, &amp;amp; MyContainer::y );&lt;br /&gt;
    ref.reveal ( &lt;br /&gt;
        manipulator, propertyZ, &amp;amp; MyContainer::x );&lt;br /&gt;
    ref.reveal ( &lt;br /&gt;
        manipulator, propertyI, &amp;amp; MyContainer::i );&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void MyContainer::traverse ( &lt;br /&gt;
    PropertyManipulator &amp;amp; manipulator ) &lt;br /&gt;
{&lt;br /&gt;
    MyContainer::traverseTempl ( &lt;br /&gt;
        reference &amp;lt; MyContainer &amp;gt; ( *this ), manipulator );&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void MyContainer::traverse ( &lt;br /&gt;
    PropertyViewer &amp;amp; viewer ) const &lt;br /&gt;
{&lt;br /&gt;
    MyContainer::traverseTempl ( &lt;br /&gt;
        reference &amp;lt; const MyContainer &amp;gt; ( *this ), viewer );&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void MyContainer::traverse ( &lt;br /&gt;
    PropertyDescriptionViewer &amp;amp; viewer )&lt;br /&gt;
{&lt;br /&gt;
    MyContainer::traverseTempl ( reference &amp;lt; void &amp;gt; (), viewer );&lt;br /&gt;
}&lt;br /&gt;
    &lt;br /&gt;
bool MyContainer::find ( &lt;br /&gt;
    const PropertyId &amp;amp; id, &lt;br /&gt;
    PropertyManipulator &amp;lt; Property &amp;gt; &amp;amp; manipulator ) const &lt;br /&gt;
{&lt;br /&gt;
    bool status = false;&lt;br /&gt;
    if ( id == propertyX ) {&lt;br /&gt;
    	manipulator.reveal ( &lt;br /&gt;
    	    Property &amp;lt; const int &amp;gt; ( propertyX, this-&amp;gt;x ) );&lt;br /&gt;
        status = true;&lt;br /&gt;
    }&lt;br /&gt;
    else ( id == propertyY ) {&lt;br /&gt;
    	manipulator.reveal ( &lt;br /&gt;
    	    Property &amp;lt; const int &amp;gt; ( propertyY, this-&amp;gt;y ) );&lt;br /&gt;
        status = true;&lt;br /&gt;
    }&lt;br /&gt;
    return status;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;/div&gt;</summary>
		<author><name>JeffHill</name></author>
	</entry>
	<entry>
		<id>https://wiki-ext.aps.anl.gov/epics/index.php?title=Talk:V4_CA_Interfaces&amp;diff=186</id>
		<title>Talk:V4 CA Interfaces</title>
		<link rel="alternate" type="text/html" href="https://wiki-ext.aps.anl.gov/epics/index.php?title=Talk:V4_CA_Interfaces&amp;diff=186"/>
		<updated>2005-05-20T19:31:05Z</updated>

		<summary type="html">&lt;p&gt;JeffHill: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Some comments from Andrew Johnson:&lt;br /&gt;
&lt;br /&gt;
In your presentation about CA V4, you included the method &lt;br /&gt;
channel::createAllPropertiesReadRequest().  I agree that we need a way &lt;br /&gt;
to be able to read all of the properties available from the server for a &lt;br /&gt;
particular PV name, but I want more flexibility than just being able to &lt;br /&gt;
put that wild-card at the top of my request.&lt;br /&gt;
&lt;br /&gt;
I think we need the ability to be able to subscribe with a property &lt;br /&gt;
catalog having a specific set of properties at one level but to &lt;br /&gt;
wild-card a sub-property catalog at some level below.  Is this currently &lt;br /&gt;
possible?  If not, please consider this a request to add that &lt;br /&gt;
capability, which might then remove the need for the seperate &lt;br /&gt;
createAllPropertiesReadRequest() method.  I'm only looking for you to &lt;br /&gt;
support &amp;quot;*&amp;quot;, no pattern matching or regex stuff.&lt;br /&gt;
&lt;br /&gt;
Some comments from Jeff Hill:&lt;br /&gt;
&lt;br /&gt;
During our meeting I raised a question; do we may need a Data Access interface allowing traversal of the structure of the property hierarchy, learning the native type of the properties, but not require instances of the properties?&lt;br /&gt;
&lt;br /&gt;
There may be legitimate situations where the property catalog egg must come before the property catalog chicken. Furthermore, it might be quite inconvenient from a memory management perspective to require an instance of an array before it is really used. I think that this negative could be perhaps minimized if we state in the CA manual that the array bounds alone will be examined, and the array elements will not be traversed, when scanning a property catalog to learn its structure.&lt;br /&gt;
&lt;br /&gt;
Probably the only negative associated with adding a property catalog structure traverse capability to the interface would be that the application would need to provide one additional function. They are already providing an immutable traverse, a mutable traverse function, and an immutable find function. What is vexing is that in many situations all three of the traverse functions are nearly identical. Personally, I don’t like to see common code managed with cut and paste. I am even less fond of that eventuality should it be repeated for many, many data structures in a proliferation of applications. &lt;br /&gt;
&lt;br /&gt;
So I had a look at what level of Data Access library support might be provided so that they need write the guts of the traverse function only once. The following is an example of how they might structure their application. There are still three traverse functions because cross library binding requires the virtual base class interfaced technique, but now they can use a template to implement the traversing only once.&lt;br /&gt;
&lt;br /&gt;
This level of complication appears to be reasonable for end user applications. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
PropertyId propertyX;&lt;br /&gt;
PropertyId propertyY;&lt;br /&gt;
PropertyId propertyZ;&lt;br /&gt;
PropertyId propertyI;&lt;br /&gt;
&lt;br /&gt;
class MyContainer : private PropertyCatalog {&lt;br /&gt;
public:&lt;br /&gt;
&lt;br /&gt;
private:&lt;br /&gt;
    int x;&lt;br /&gt;
    float y;&lt;br /&gt;
    double z;&lt;br /&gt;
    char i;&lt;br /&gt;
    static void traverse ( &lt;br /&gt;
        PropertyDescriptionViewer &amp;amp; );&lt;br /&gt;
    void traverse ( &lt;br /&gt;
        PropertyManipulator &amp;amp; );&lt;br /&gt;
    void traverse ( &lt;br /&gt;
        PropertyViewer &amp;amp; ) const;&lt;br /&gt;
    bool find ( &lt;br /&gt;
        const PropertyId &amp;amp; id, PropertyViewer &amp;amp; ) const;&lt;br /&gt;
    template &amp;lt; class REFERENCE, class MANIPULATOR &amp;gt;&lt;br /&gt;
    static void traverseTempl ( &lt;br /&gt;
        const REFERENCE &amp;amp;, MANIPULATOR &amp;amp; );&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
template &amp;lt; class REFERENCE, class MANIPULATOR &amp;gt;&lt;br /&gt;
inline void MyContainer::traverseTempl ( &lt;br /&gt;
    const REFERENCE &amp;amp; ref, MANIPULATOR &amp;amp; manipulator )&lt;br /&gt;
{&lt;br /&gt;
    ref.reveal ( &lt;br /&gt;
        manipulator, propertyX, &amp;amp; MyContainer::x );&lt;br /&gt;
    ref.reveal ( &lt;br /&gt;
        manipulator, propertyY, &amp;amp; MyContainer::y );&lt;br /&gt;
    ref.reveal ( &lt;br /&gt;
        manipulator, propertyZ, &amp;amp; MyContainer::x );&lt;br /&gt;
    ref.reveal ( &lt;br /&gt;
        manipulator, propertyI, &amp;amp; MyContainer::i );&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void MyContainer::traverse ( &lt;br /&gt;
    PropertyManipulator &amp;amp; manipulator ) &lt;br /&gt;
{&lt;br /&gt;
    MyContainer::traverseTempl ( &lt;br /&gt;
        reference &amp;lt; MyContainer &amp;gt; ( *this ), manipulator );&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void MyContainer::traverse ( &lt;br /&gt;
    PropertyViewer &amp;amp; viewer ) const &lt;br /&gt;
{&lt;br /&gt;
    MyContainer::traverseTempl ( &lt;br /&gt;
        reference &amp;lt; const MyContainer &amp;gt; ( *this ), viewer );&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void MyContainer::traverse ( &lt;br /&gt;
    PropertyDescriptionViewer &amp;amp; viewer )&lt;br /&gt;
{&lt;br /&gt;
    MyContainer::traverseTempl ( reference &amp;lt; void &amp;gt; (), viewer );&lt;br /&gt;
}&lt;br /&gt;
    &lt;br /&gt;
bool MyContainer::find ( &lt;br /&gt;
    const PropertyId &amp;amp; id, &lt;br /&gt;
    PropertyManipulator &amp;lt; Property &amp;gt; &amp;amp; manipulator ) const &lt;br /&gt;
{&lt;br /&gt;
    bool status = false;&lt;br /&gt;
    if ( id == propertyX ) {&lt;br /&gt;
    	manipulator.reveal ( &lt;br /&gt;
    	    Property &amp;lt; const int &amp;gt; ( propertyX, this-&amp;gt;x ) );&lt;br /&gt;
        status = true;&lt;br /&gt;
    }&lt;br /&gt;
    else ( id == propertyY ) {&lt;br /&gt;
    	manipulator.reveal ( &lt;br /&gt;
    	    Property &amp;lt; const int &amp;gt; ( propertyY, this-&amp;gt;y ) );&lt;br /&gt;
        status = true;&lt;br /&gt;
    }&lt;br /&gt;
    return status;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;/div&gt;</summary>
		<author><name>JeffHill</name></author>
	</entry>
	<entry>
		<id>https://wiki-ext.aps.anl.gov/epics/index.php?title=Talk:V4_CA_Interfaces&amp;diff=185</id>
		<title>Talk:V4 CA Interfaces</title>
		<link rel="alternate" type="text/html" href="https://wiki-ext.aps.anl.gov/epics/index.php?title=Talk:V4_CA_Interfaces&amp;diff=185"/>
		<updated>2005-05-20T19:25:05Z</updated>

		<summary type="html">&lt;p&gt;JeffHill: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Some comments from Andrew Johnson:&lt;br /&gt;
&lt;br /&gt;
In your presentation about CA V4, you included the method &lt;br /&gt;
channel::createAllPropertiesReadRequest().  I agree that we need a way &lt;br /&gt;
to be able to read all of the properties available from the server for a &lt;br /&gt;
particular PV name, but I want more flexibility than just being able to &lt;br /&gt;
put that wild-card at the top of my request.&lt;br /&gt;
&lt;br /&gt;
I think we need the ability to be able to subscribe with a property &lt;br /&gt;
catalog having a specific set of properties at one level but to &lt;br /&gt;
wild-card a sub-property catalog at some level below.  Is this currently &lt;br /&gt;
possible?  If not, please consider this a request to add that &lt;br /&gt;
capability, which might then remove the need for the seperate &lt;br /&gt;
createAllPropertiesReadRequest() method.  I'm only looking for you to &lt;br /&gt;
support &amp;quot;*&amp;quot;, no pattern matching or regex stuff.&lt;br /&gt;
&lt;br /&gt;
Some comments from Jeff Hill:&lt;br /&gt;
&lt;br /&gt;
During our meeting I raised a question; do we may need a Data Access interface allowing traversal of the structure of the property hierarchy, learning the native type of the properties, but not require instances of the properties?&lt;br /&gt;
&lt;br /&gt;
There may be legitimate situations where the property catalog egg must come before the property catalog chicken. Furthermore, it might be quite inconvenient from a memory management perspective to require an instance of an array before it is really used. I think that this negative could be perhaps minimized if we state in the CA manual that the array bounds alone will be examined, and the array elements will not be traversed, when scanning a property catalog to learn its structure.&lt;br /&gt;
&lt;br /&gt;
Probably the only negative associated with adding a property catalog structure traverse capability to the interface would be that the application would need to provide one additional function. They are already providing an immutable traverse, a mutable traverse function, and an immutable find function. What is vexing is that in many situations all three of the traverse functions are nearly identical. Personally, I don’t like to see common code managed with cut and paste. I am even less fond of that eventuality should it be repeated for many, many data structures in a proliferation of applications. &lt;br /&gt;
&lt;br /&gt;
So I had a look at what level of Data Access library support might be provided so that they need write the guts of the traverse function once. The following is an example of how they might structure their application. There are still three traverse functions because cross library binding requires the virtual base class interfaced technique, but now they can use a template to implement the traversing only once.&lt;br /&gt;
&lt;br /&gt;
This level of complication appears to be reasonable for end user applications. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
PropertyId propertyX;&lt;br /&gt;
PropertyId propertyY;&lt;br /&gt;
PropertyId propertyZ;&lt;br /&gt;
PropertyId propertyI;&lt;br /&gt;
&lt;br /&gt;
class MyContainer : private PropertyCatalog {&lt;br /&gt;
public:&lt;br /&gt;
&lt;br /&gt;
private:&lt;br /&gt;
    int x;&lt;br /&gt;
    float y;&lt;br /&gt;
    double z;&lt;br /&gt;
    char i;&lt;br /&gt;
    static void traverse ( &lt;br /&gt;
        PropertyDescriptionViewer &amp;amp; );&lt;br /&gt;
    void traverse ( &lt;br /&gt;
        PropertyManipulator &amp;amp; );&lt;br /&gt;
    void traverse ( &lt;br /&gt;
        PropertyViewer &amp;amp; ) const;&lt;br /&gt;
    bool find ( &lt;br /&gt;
        const PropertyId &amp;amp; id, PropertyViewer &amp;amp; ) const;&lt;br /&gt;
    template &amp;lt; class REFERENCE, class MANIPULATOR &amp;gt;&lt;br /&gt;
    static void traverseTempl ( &lt;br /&gt;
        const REFERENCE &amp;amp;, MANIPULATOR &amp;amp; );&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
template &amp;lt; class REFERENCE, class MANIPULATOR &amp;gt;&lt;br /&gt;
inline void MyContainer::traverseTempl ( &lt;br /&gt;
    const REFERENCE &amp;amp; ref, MANIPULATOR &amp;amp; manipulator )&lt;br /&gt;
{&lt;br /&gt;
    ref.reveal ( &lt;br /&gt;
        manipulator, propertyX, &amp;amp; MyContainer::x );&lt;br /&gt;
    ref.reveal ( &lt;br /&gt;
        manipulator, propertyY, &amp;amp; MyContainer::y );&lt;br /&gt;
    ref.reveal ( &lt;br /&gt;
        manipulator, propertyZ, &amp;amp; MyContainer::x );&lt;br /&gt;
    ref.reveal ( &lt;br /&gt;
        manipulator, propertyI, &amp;amp; MyContainer::i );&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void MyContainer::traverse ( &lt;br /&gt;
    PropertyManipulator &amp;amp; manipulator ) &lt;br /&gt;
{&lt;br /&gt;
    MyContainer::traverseTempl ( &lt;br /&gt;
        reference &amp;lt; MyContainer &amp;gt; ( *this ), manipulator );&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void MyContainer::traverse ( &lt;br /&gt;
    PropertyViewer &amp;amp; viewer ) const &lt;br /&gt;
{&lt;br /&gt;
    MyContainer::traverseTempl ( &lt;br /&gt;
        reference &amp;lt; const MyContainer &amp;gt; ( *this ), viewer );&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void MyContainer::traverse ( &lt;br /&gt;
    PropertyDescriptionViewer &amp;amp; viewer )&lt;br /&gt;
{&lt;br /&gt;
    MyContainer::traverseTempl ( reference &amp;lt; void &amp;gt; (), viewer );&lt;br /&gt;
}&lt;br /&gt;
    &lt;br /&gt;
bool MyContainer::find ( &lt;br /&gt;
    const PropertyId &amp;amp; id, &lt;br /&gt;
    PropertyManipulator &amp;lt; Property &amp;gt; &amp;amp; manipulator ) const &lt;br /&gt;
{&lt;br /&gt;
    bool status = false;&lt;br /&gt;
    if ( id == propertyX ) {&lt;br /&gt;
    	manipulator.reveal ( &lt;br /&gt;
    	    Property &amp;lt; const int &amp;gt; ( propertyX, this-&amp;gt;x ) );&lt;br /&gt;
        status = true;&lt;br /&gt;
    }&lt;br /&gt;
    else ( id == propertyY ) {&lt;br /&gt;
    	manipulator.reveal ( &lt;br /&gt;
    	    Property &amp;lt; const int &amp;gt; ( propertyY, this-&amp;gt;y ) );&lt;br /&gt;
        status = true;&lt;br /&gt;
    }&lt;br /&gt;
    return status;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;/div&gt;</summary>
		<author><name>JeffHill</name></author>
	</entry>
	<entry>
		<id>https://wiki-ext.aps.anl.gov/epics/index.php?title=Talk:V4_CA_Interfaces&amp;diff=184</id>
		<title>Talk:V4 CA Interfaces</title>
		<link rel="alternate" type="text/html" href="https://wiki-ext.aps.anl.gov/epics/index.php?title=Talk:V4_CA_Interfaces&amp;diff=184"/>
		<updated>2005-05-20T19:22:50Z</updated>

		<summary type="html">&lt;p&gt;JeffHill: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Some comments from Andrew Johnson:&lt;br /&gt;
&lt;br /&gt;
In your presentation about CA V4, you included the method &lt;br /&gt;
channel::createAllPropertiesReadRequest().  I agree that we need a way &lt;br /&gt;
to be able to read all of the properties available from the server for a &lt;br /&gt;
particular PV name, but I want more flexibility than just being able to &lt;br /&gt;
put that wild-card at the top of my request.&lt;br /&gt;
&lt;br /&gt;
I think we need the ability to be able to subscribe with a property &lt;br /&gt;
catalog having a specific set of properties at one level but to &lt;br /&gt;
wild-card a sub-property catalog at some level below.  Is this currently &lt;br /&gt;
possible?  If not, please consider this a request to add that &lt;br /&gt;
capability, which might then remove the need for the seperate &lt;br /&gt;
createAllPropertiesReadRequest() method.  I'm only looking for you to &lt;br /&gt;
support &amp;quot;*&amp;quot;, no pattern matching or regex stuff.&lt;br /&gt;
&lt;br /&gt;
Some comments from Jeff Hill:&lt;br /&gt;
&lt;br /&gt;
During our meeting I raised a question; do we may need a Data Access interface allowing traversal of the structure of the property hierarchy, learning the native type of the properties, but not require instances of the properties?&lt;br /&gt;
&lt;br /&gt;
There may be legitimate situations where the property catalog egg must come before the property catalog chicken. Furthermore, it might be quite inconvenient from a memory management perspective to require an instance of an array before it is really used. I think that this negative could be perhaps minimized if we state in the CA manual that the array bounds alone will be examined, and the array elements will not be traversed, when scanning a property catalog to learn its structure.&lt;br /&gt;
&lt;br /&gt;
Probably the only negative associated with adding a property catalog structure traverse capability to the interface would be that the application would need to provide one additional function. They are already providing an immutable traverse, a mutable traverse function, and an immutable find function. What is vexing is that all three of the traverse functions are nearly identical. Personally, I don’t like to see common code managed with cut and paste. I am even less fond of that eventuality should it be repeated for many, many data structures in a proliferation of applications. &lt;br /&gt;
&lt;br /&gt;
So I had a look at what level of Data Access library support might be provided so that they need write the guts of the traverse function once. The following is an example of how they might structure their application. There are still three traverse functions because cross library binding requires the virtual base class interfaced technique, but now they can use a template to implement the traversing only once.&lt;br /&gt;
&lt;br /&gt;
This level of complication appears to be reasonable for end user applications. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
PropertyId propertyX;&lt;br /&gt;
PropertyId propertyY;&lt;br /&gt;
PropertyId propertyZ;&lt;br /&gt;
PropertyId propertyI;&lt;br /&gt;
&lt;br /&gt;
class MyContainer : private PropertyCatalog {&lt;br /&gt;
public:&lt;br /&gt;
&lt;br /&gt;
private:&lt;br /&gt;
    int x;&lt;br /&gt;
    float y;&lt;br /&gt;
    double z;&lt;br /&gt;
    char i;&lt;br /&gt;
    static void traverse ( &lt;br /&gt;
        PropertyDescriptionViewer &amp;amp; );&lt;br /&gt;
    void traverse ( &lt;br /&gt;
        PropertyManipulator &amp;amp; );&lt;br /&gt;
    void traverse ( &lt;br /&gt;
        PropertyViewer &amp;amp; ) const;&lt;br /&gt;
    bool find ( &lt;br /&gt;
        const PropertyId &amp;amp; id, PropertyViewer &amp;amp; ) const;&lt;br /&gt;
    template &amp;lt; class REFERENCE, class MANIPULATOR &amp;gt;&lt;br /&gt;
    static void traverseTempl ( &lt;br /&gt;
        const REFERENCE &amp;amp;, MANIPULATOR &amp;amp; );&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
template &amp;lt; class REFERENCE, class MANIPULATOR &amp;gt;&lt;br /&gt;
inline void MyContainer::traverseTempl ( &lt;br /&gt;
    const REFERENCE &amp;amp; ref, MANIPULATOR &amp;amp; manipulator )&lt;br /&gt;
{&lt;br /&gt;
    ref.reveal ( &lt;br /&gt;
        manipulator, propertyX, &amp;amp; MyContainer::x );&lt;br /&gt;
    ref.reveal ( &lt;br /&gt;
        manipulator, propertyY, &amp;amp; MyContainer::y );&lt;br /&gt;
    ref.reveal ( &lt;br /&gt;
        manipulator, propertyZ, &amp;amp; MyContainer::x );&lt;br /&gt;
    ref.reveal ( &lt;br /&gt;
        manipulator, propertyI, &amp;amp; MyContainer::i );&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void MyContainer::traverse ( &lt;br /&gt;
    PropertyManipulator &amp;amp; manipulator ) &lt;br /&gt;
{&lt;br /&gt;
    MyContainer::traverseTempl ( &lt;br /&gt;
        reference &amp;lt; MyContainer &amp;gt; ( *this ), manipulator );&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void MyContainer::traverse ( &lt;br /&gt;
    PropertyViewer &amp;amp; viewer ) const &lt;br /&gt;
{&lt;br /&gt;
    MyContainer::traverseTempl ( &lt;br /&gt;
        reference &amp;lt; const MyContainer &amp;gt; ( *this ), viewer );&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void MyContainer::traverse ( &lt;br /&gt;
    PropertyDescriptionViewer &amp;amp; viewer )&lt;br /&gt;
{&lt;br /&gt;
    MyContainer::traverseTempl ( reference &amp;lt; void &amp;gt; (), viewer );&lt;br /&gt;
}&lt;br /&gt;
    &lt;br /&gt;
bool MyContainer::find ( &lt;br /&gt;
    const PropertyId &amp;amp; id, &lt;br /&gt;
    PropertyManipulator &amp;lt; Property &amp;gt; &amp;amp; manipulator ) const &lt;br /&gt;
{&lt;br /&gt;
    bool status = false;&lt;br /&gt;
    if ( id == propertyX ) {&lt;br /&gt;
    	manipulator.reveal ( &lt;br /&gt;
    	    Property &amp;lt; const int &amp;gt; ( propertyX, this-&amp;gt;x ) );&lt;br /&gt;
        status = true;&lt;br /&gt;
    }&lt;br /&gt;
    else ( id == propertyY ) {&lt;br /&gt;
    	manipulator.reveal ( &lt;br /&gt;
    	    Property &amp;lt; const int &amp;gt; ( propertyY, this-&amp;gt;y ) );&lt;br /&gt;
        status = true;&lt;br /&gt;
    }&lt;br /&gt;
    return status;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;/div&gt;</summary>
		<author><name>JeffHill</name></author>
	</entry>
	<entry>
		<id>https://wiki-ext.aps.anl.gov/epics/index.php?title=Talk:V4_CA_Interfaces&amp;diff=183</id>
		<title>Talk:V4 CA Interfaces</title>
		<link rel="alternate" type="text/html" href="https://wiki-ext.aps.anl.gov/epics/index.php?title=Talk:V4_CA_Interfaces&amp;diff=183"/>
		<updated>2005-05-20T19:21:18Z</updated>

		<summary type="html">&lt;p&gt;JeffHill: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Some comments from Andrew Johnson:&lt;br /&gt;
&lt;br /&gt;
In your presentation about CA V4, you included the method &lt;br /&gt;
channel::createAllPropertiesReadRequest().  I agree that we need a way &lt;br /&gt;
to be able to read all of the properties available from the server for a &lt;br /&gt;
particular PV name, but I want more flexibility than just being able to &lt;br /&gt;
put that wild-card at the top of my request.&lt;br /&gt;
&lt;br /&gt;
I think we need the ability to be able to subscribe with a property &lt;br /&gt;
catalog having a specific set of properties at one level but to &lt;br /&gt;
wild-card a sub-property catalog at some level below.  Is this currently &lt;br /&gt;
possible?  If not, please consider this a request to add that &lt;br /&gt;
capability, which might then remove the need for the seperate &lt;br /&gt;
createAllPropertiesReadRequest() method.  I'm only looking for you to &lt;br /&gt;
support &amp;quot;*&amp;quot;, no pattern matching or regex stuff.&lt;br /&gt;
&lt;br /&gt;
Some comments from Jeff Hill:&lt;br /&gt;
&lt;br /&gt;
During our meeting I raised a question; do we may need a Data Access interface allowing traversal of the structure of the property hierarchy, learning the native type of the properties, but not require instances of the properties?&lt;br /&gt;
&lt;br /&gt;
There may be legitimate situations where the property catalog egg must come before the property catalog chicken. Furthermore, it might be quite inconvenient from a memory management perspective to require an instance of an array before it is really used. I think that this negative could be perhaps minimized if we state in the CA manual that the array bounds alone will be examined, and the array elements will not be traversed, when scanning a property catalog to learn its structure.&lt;br /&gt;
&lt;br /&gt;
Probably the only negative associated with adding a property catalog structure traverse capability to the interface would be that the application would need to provide one additional function. They are already providing an immutable traverse, a mutable traverse function, and an immutable find function. What is vexing is that all three of the traverse functions are nearly identical. Personally, I don’t like to see common code managed with cut and paste. I am even less fond of that eventuality should it be repeated for many, many data structures in a proliferation of applications. &lt;br /&gt;
&lt;br /&gt;
So I had a look at what level of Data Access library support might be provided so that they need write the guts of the traverse function once. The following is an example of how they might structure their application. There are still three traverse functions because cross library binding requires the virtual base class interfaced technique, but now they can use a template to implement the traversing only once.&lt;br /&gt;
&lt;br /&gt;
This level of complication appears to be reasonable for end user applications. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
PropertyId propertyX;&lt;br /&gt;
PropertyId propertyY;&lt;br /&gt;
PropertyId propertyZ;&lt;br /&gt;
PropertyId propertyI;&lt;br /&gt;
&lt;br /&gt;
class MyContainer : private PropertyCatalog {&lt;br /&gt;
public:&lt;br /&gt;
&lt;br /&gt;
private:&lt;br /&gt;
    int x;&lt;br /&gt;
    float y;&lt;br /&gt;
    double z;&lt;br /&gt;
    char i;&lt;br /&gt;
    static void traverse ( &lt;br /&gt;
        PropertyDescriptionViewer &amp;amp; );&lt;br /&gt;
    void traverse ( &lt;br /&gt;
        PropertyManipulator &amp;amp; );&lt;br /&gt;
    void traverse ( &lt;br /&gt;
        PropertyViewer &amp;amp; ) const;&lt;br /&gt;
    bool find ( &lt;br /&gt;
        const PropertyId &amp;amp; id, PropertyViewer &amp;amp; ) const;&lt;br /&gt;
    template &amp;lt; class REFERENCE, class MANIPULATOR &amp;gt;&lt;br /&gt;
    static void traverseTempl ( &lt;br /&gt;
        const REFERENCE &amp;amp;, MANIPULATOR &amp;amp; );&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
template &amp;lt; class REFERENCE, class MANIPULATOR &amp;gt;&lt;br /&gt;
inline void MyContainer::traverseTempl ( &lt;br /&gt;
    const REFERENCE &amp;amp; ref, MANIPULATOR &amp;amp; manipulator )&lt;br /&gt;
{&lt;br /&gt;
    ref.reveal ( &lt;br /&gt;
        manipulator, propertyX, &amp;amp; MyContainer::x );&lt;br /&gt;
    ref.reveal ( &lt;br /&gt;
        manipulator, propertyY, &amp;amp; MyContainer::y );&lt;br /&gt;
    ref.reveal ( &lt;br /&gt;
        manipulator, propertyZ, &amp;amp; MyContainer::x );&lt;br /&gt;
    ref.reveal ( &lt;br /&gt;
        manipulator, propertyI, &amp;amp; MyContainer::i );&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void MyContainer::traverse ( &lt;br /&gt;
    PropertyManipulator &amp;amp; manipulator ) &lt;br /&gt;
{&lt;br /&gt;
    MyContainer::traverseTempl ( &lt;br /&gt;
        reference &amp;lt; MyContainer &amp;gt; ( *this ), manipulator );&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void MyContainer::traverse ( &lt;br /&gt;
    PropertyViewer &amp;amp; viewer ) const &lt;br /&gt;
{&lt;br /&gt;
    MyContainer::traverseTempl ( &lt;br /&gt;
        reference &amp;lt; const MyContainer &amp;gt; ( *this ), viewer );&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void MyContainer::traverse ( &lt;br /&gt;
    PropertyDescriptionViewer &amp;amp; viewer )&lt;br /&gt;
{&lt;br /&gt;
    MyContainer::traverseTempl ( reference &amp;lt; void &amp;gt; (), viewer );&lt;br /&gt;
}&lt;br /&gt;
    &lt;br /&gt;
bool MyContainer::find ( &lt;br /&gt;
    const PropertyId &amp;amp; id, &lt;br /&gt;
    PropertyManipulator &amp;lt; Property &amp;gt; &amp;amp; manipulator ) const &lt;br /&gt;
{&lt;br /&gt;
    bool status = false;&lt;br /&gt;
    if ( id == propertyX ) {&lt;br /&gt;
    	manipulator.reveal ( &lt;br /&gt;
    	    Property &amp;lt; const int &amp;gt; ( propertyX, this-&amp;gt;x ) );&lt;br /&gt;
        status = true;&lt;br /&gt;
    }&lt;br /&gt;
    else ( id == propertyY ) {&lt;br /&gt;
    	manipulator.reveal ( &lt;br /&gt;
    	    Property &amp;lt; const int &amp;gt; ( propertyY, this-&amp;gt;y ) );&lt;br /&gt;
        status = true;&lt;br /&gt;
    }&lt;br /&gt;
    return status;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Here are the interface details.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
class PropertyId;&lt;br /&gt;
class ArraySegment;&lt;br /&gt;
class StringSegment;&lt;br /&gt;
class EnumStateSet;&lt;br /&gt;
class PropertyCatalog;&lt;br /&gt;
class PropertyCatalog;&lt;br /&gt;
class Time;&lt;br /&gt;
&lt;br /&gt;
class PropertyId {&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
extern class PropertyCatalog &amp;amp; voidCatalog;&lt;br /&gt;
&lt;br /&gt;
class PropertyViewer {&lt;br /&gt;
public:&lt;br /&gt;
    virtual void reveal ( const PropertyId &amp;amp;, &lt;br /&gt;
        const double &amp;amp;, const PropertyCatalog &amp;amp; = voidCatalog )  = 0;&lt;br /&gt;
    virtual void reveal ( const PropertyId &amp;amp;, &lt;br /&gt;
        const int &amp;amp;, const PropertyCatalog &amp;amp; = voidCatalog )  = 0;&lt;br /&gt;
    virtual void reveal ( const PropertyId &amp;amp;, &lt;br /&gt;
        const unsigned int &amp;amp;, const PropertyCatalog &amp;amp; = voidCatalog )  = 0;&lt;br /&gt;
    virtual void reveal ( const PropertyId &amp;amp;, &lt;br /&gt;
        const long &amp;amp;, const PropertyCatalog &amp;amp; = voidCatalog )  = 0;&lt;br /&gt;
    virtual void reveal ( const PropertyId &amp;amp;, &lt;br /&gt;
        const unsigned long &amp;amp;, const PropertyCatalog &amp;amp; = voidCatalog )  = 0;&lt;br /&gt;
    virtual void reveal ( const PropertyId &amp;amp;, &lt;br /&gt;
        const Time &amp;amp;, const PropertyCatalog &amp;amp; = voidCatalog )  = 0;&lt;br /&gt;
    virtual void reveal ( const PropertyId &amp;amp;, &lt;br /&gt;
        const StringSegment &amp;amp;, const PropertyCatalog &amp;amp; = voidCatalog )  = 0;&lt;br /&gt;
    virtual void reveal ( const PropertyId &amp;amp;, &lt;br /&gt;
        const EnumStateSet &amp;amp; )  = 0;&lt;br /&gt;
    virtual void reveal ( const PropertyId &amp;amp;, &lt;br /&gt;
        const ArraySegment &amp;amp;, const PropertyCatalog &amp;amp; = voidCatalog )  = 0;&lt;br /&gt;
    virtual void reveal ( const PropertyId &amp;amp;, &lt;br /&gt;
        const PropertyCatalog &amp;amp; )  = 0;&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
template &amp;lt; class T &amp;gt;&lt;br /&gt;
class TypedVoid {&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
class PropertyDescriptionViewer {&lt;br /&gt;
public:&lt;br /&gt;
    virtual void reveal ( const PropertyId &amp;amp;, &lt;br /&gt;
        TypedVoid &amp;lt; float &amp;gt; &amp;amp;, const PropertyCatalog &amp;amp; = voidCatalog )  = 0;&lt;br /&gt;
    virtual void reveal ( const PropertyId &amp;amp;, &lt;br /&gt;
        TypedVoid &amp;lt; double &amp;gt; &amp;amp;, const PropertyCatalog &amp;amp; = voidCatalog )  = 0;&lt;br /&gt;
    virtual void reveal ( const PropertyId &amp;amp;, &lt;br /&gt;
        TypedVoid &amp;lt; char &amp;gt; &amp;amp;, const PropertyCatalog &amp;amp; = voidCatalog )  = 0;&lt;br /&gt;
    virtual void reveal ( const PropertyId &amp;amp;, &lt;br /&gt;
        TypedVoid &amp;lt; signed char &amp;gt; &amp;amp;, const PropertyCatalog &amp;amp; = voidCatalog )  = 0;&lt;br /&gt;
    virtual void reveal ( const PropertyId &amp;amp;, &lt;br /&gt;
        TypedVoid &amp;lt; unsigned char &amp;gt; &amp;amp;, const PropertyCatalog &amp;amp; = voidCatalog )  = 0;&lt;br /&gt;
    virtual void reveal ( const PropertyId &amp;amp;, &lt;br /&gt;
        TypedVoid &amp;lt; short &amp;gt; &amp;amp;, const PropertyCatalog &amp;amp; = voidCatalog )  = 0;&lt;br /&gt;
    virtual void reveal ( const PropertyId &amp;amp;, &lt;br /&gt;
        TypedVoid &amp;lt; unsigned short &amp;gt; &amp;amp;, const PropertyCatalog &amp;amp; = voidCatalog )  = 0;&lt;br /&gt;
    virtual void reveal ( const PropertyId &amp;amp;, &lt;br /&gt;
        TypedVoid &amp;lt; int &amp;gt; &amp;amp;, const PropertyCatalog &amp;amp; = voidCatalog )  = 0;&lt;br /&gt;
    virtual void reveal ( const PropertyId &amp;amp;, &lt;br /&gt;
        TypedVoid &amp;lt; unsigned int &amp;gt; &amp;amp;, const PropertyCatalog &amp;amp; = voidCatalog )  = 0;&lt;br /&gt;
    virtual void reveal ( const PropertyId &amp;amp;, &lt;br /&gt;
        TypedVoid &amp;lt; long &amp;gt; &amp;amp;, const PropertyCatalog &amp;amp; = voidCatalog )  = 0;&lt;br /&gt;
    virtual void reveal ( const PropertyId &amp;amp;, &lt;br /&gt;
        TypedVoid &amp;lt; unsigned long &amp;gt; &amp;amp;, const PropertyCatalog &amp;amp; = voidCatalog )  = 0;&lt;br /&gt;
    virtual void reveal ( const PropertyId &amp;amp;, &lt;br /&gt;
        TypedVoid &amp;lt; Time &amp;gt; &amp;amp;, const PropertyCatalog &amp;amp; = voidCatalog )  = 0;&lt;br /&gt;
    virtual void reveal ( const PropertyId &amp;amp;, &lt;br /&gt;
        TypedVoid &amp;lt; StringSegment &amp;gt; &amp;amp;, const PropertyCatalog &amp;amp; = voidCatalog )  = 0;&lt;br /&gt;
    virtual void reveal ( const PropertyId &amp;amp;, &lt;br /&gt;
        TypedVoid &amp;lt; EnumStateSet &amp;gt; &amp;amp; )  = 0;&lt;br /&gt;
    virtual void reveal ( const PropertyId &amp;amp;, &lt;br /&gt;
        TypedVoid &amp;lt; ArraySegment &amp;gt; &amp;amp;, const PropertyCatalog &amp;amp; = voidCatalog )  = 0;&lt;br /&gt;
    virtual void reveal ( const PropertyId &amp;amp;, &lt;br /&gt;
        TypedVoid &amp;lt; PropertyCatalog &amp;gt; &amp;amp; )  = 0;&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
class PropertyManipulator {&lt;br /&gt;
public:&lt;br /&gt;
    virtual void reveal ( const PropertyId &amp;amp;, &lt;br /&gt;
        float &amp;amp;, const PropertyCatalog &amp;amp; = voidCatalog )  = 0;&lt;br /&gt;
    virtual void reveal ( const PropertyId &amp;amp;, &lt;br /&gt;
        double &amp;amp;, const PropertyCatalog &amp;amp; = voidCatalog )  = 0;&lt;br /&gt;
    virtual void reveal ( const PropertyId &amp;amp;, &lt;br /&gt;
        char &amp;amp;, const PropertyCatalog &amp;amp; = voidCatalog )  = 0;&lt;br /&gt;
    virtual void reveal ( const PropertyId &amp;amp;, &lt;br /&gt;
        signed char &amp;amp;, const PropertyCatalog &amp;amp; = voidCatalog )  = 0;&lt;br /&gt;
    virtual void reveal ( const PropertyId &amp;amp;, &lt;br /&gt;
        unsigned char &amp;amp;, const PropertyCatalog &amp;amp; = voidCatalog )  = 0;&lt;br /&gt;
    virtual void reveal ( const PropertyId &amp;amp;, &lt;br /&gt;
        short &amp;amp;, const PropertyCatalog &amp;amp; = voidCatalog )  = 0;&lt;br /&gt;
    virtual void reveal ( const PropertyId &amp;amp;, &lt;br /&gt;
        unsigned short &amp;amp;, const PropertyCatalog &amp;amp; = voidCatalog )  = 0;&lt;br /&gt;
    virtual void reveal ( const PropertyId &amp;amp;, &lt;br /&gt;
        int &amp;amp;, const PropertyCatalog &amp;amp; = voidCatalog )  = 0;&lt;br /&gt;
    virtual void reveal ( const PropertyId &amp;amp;, &lt;br /&gt;
        unsigned int &amp;amp;, const PropertyCatalog &amp;amp; = voidCatalog )  = 0;&lt;br /&gt;
    virtual void reveal ( const PropertyId &amp;amp;, &lt;br /&gt;
        long &amp;amp;, const PropertyCatalog &amp;amp; = voidCatalog )  = 0;&lt;br /&gt;
    virtual void reveal ( const PropertyId &amp;amp;, &lt;br /&gt;
        unsigned long &amp;amp;, const PropertyCatalog &amp;amp; = voidCatalog )  = 0;&lt;br /&gt;
    virtual void reveal ( const PropertyId &amp;amp;, &lt;br /&gt;
        Time &amp;amp;, const PropertyCatalog &amp;amp; = voidCatalog )  = 0;&lt;br /&gt;
    virtual void reveal ( const PropertyId &amp;amp;, &lt;br /&gt;
        StringSegment &amp;amp;, const PropertyCatalog &amp;amp; = voidCatalog )  = 0;&lt;br /&gt;
    virtual void reveal ( const PropertyId &amp;amp;, &lt;br /&gt;
        EnumStateSet &amp;amp; )  = 0;&lt;br /&gt;
    virtual void reveal ( const PropertyId &amp;amp;, &lt;br /&gt;
        ArraySegment &amp;amp;, const PropertyCatalog &amp;amp; = voidCatalog )  = 0;&lt;br /&gt;
    virtual void reveal ( const PropertyId &amp;amp;, &lt;br /&gt;
        PropertyCatalog &amp;amp; )  = 0;&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
class PropertyCatalog {&lt;br /&gt;
public:&lt;br /&gt;
    virtual void traverse ( &lt;br /&gt;
        PropertyManipulator &amp;amp; ) = 0;&lt;br /&gt;
    virtual void traverse ( &lt;br /&gt;
        PropertyViewer &amp;amp; ) const = 0;&lt;br /&gt;
    // false returned when the property does not exist, otherwise true&lt;br /&gt;
    virtual bool find ( &lt;br /&gt;
        const PropertyId &amp;amp; id, PropertyViewer &amp;amp; ) const = 0;&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
// ----------------- void property catalog implementation ---------------------------&lt;br /&gt;
&lt;br /&gt;
class VoidContainer : public PropertyCatalog {&lt;br /&gt;
    void traverse ( &lt;br /&gt;
        PropertyManipulator &amp;amp; ) {}&lt;br /&gt;
    void traverse ( &lt;br /&gt;
        PropertyViewer &amp;amp; ) const {}&lt;br /&gt;
    // false returned when the property does not exist, otherwise true&lt;br /&gt;
    bool find ( &lt;br /&gt;
        const PropertyId &amp;amp; id, PropertyViewer &amp;amp; ) const &lt;br /&gt;
    {&lt;br /&gt;
        return false;&lt;br /&gt;
    }&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
VoidContainer aVoidContainer;&lt;br /&gt;
class PropertyCatalog &amp;amp; voidCatalog = aVoidContainer;&lt;br /&gt;
&lt;br /&gt;
// --------------------------- begin reference implemenation --------------------------&lt;br /&gt;
&lt;br /&gt;
template &amp;lt; class T &amp;gt;&lt;br /&gt;
class reference&lt;br /&gt;
{&lt;br /&gt;
public:&lt;br /&gt;
    reference ( T &amp;amp; ref ) : &lt;br /&gt;
      _ref ( ref ) &lt;br /&gt;
    {&lt;br /&gt;
    }&lt;br /&gt;
    template &amp;lt; class M &amp;gt;&lt;br /&gt;
    void reveal ( &lt;br /&gt;
        PropertyManipulator &amp;amp; manipulator,&lt;br /&gt;
        const PropertyId &amp;amp; id, M ( T :: * p ), &lt;br /&gt;
        PropertyCatalog &amp;amp; subordinates = voidCatalog ) const&lt;br /&gt;
    {&lt;br /&gt;
        manipulator.reveal (&lt;br /&gt;
            id, _ref.*p, subordinates );&lt;br /&gt;
    }&lt;br /&gt;
private:&lt;br /&gt;
    T &amp;amp; _ref;&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
template &amp;lt; class T &amp;gt;&lt;br /&gt;
class reference &amp;lt; const T &amp;gt;&lt;br /&gt;
{&lt;br /&gt;
public:&lt;br /&gt;
    reference ( const T &amp;amp; ref ) : &lt;br /&gt;
      _ref ( ref ) &lt;br /&gt;
    {&lt;br /&gt;
    }&lt;br /&gt;
    template &amp;lt; class M &amp;gt;&lt;br /&gt;
    void reveal ( &lt;br /&gt;
        PropertyViewer &amp;amp; viewer,&lt;br /&gt;
        const PropertyId &amp;amp; id, M ( T :: * p ), &lt;br /&gt;
        const PropertyCatalog &amp;amp; subordinates = voidCatalog ) const&lt;br /&gt;
    {&lt;br /&gt;
        viewer.reveal (&lt;br /&gt;
            id, _ref.*p, subordinates );&lt;br /&gt;
    }&lt;br /&gt;
private:&lt;br /&gt;
    const T &amp;amp; _ref;&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
template &amp;lt;&amp;gt;&lt;br /&gt;
class reference &amp;lt; void &amp;gt;&lt;br /&gt;
{&lt;br /&gt;
public:&lt;br /&gt;
    template &amp;lt; class T, class M &amp;gt;&lt;br /&gt;
    void reveal ( &lt;br /&gt;
        PropertyDescriptionViewer &amp;amp; viewer,&lt;br /&gt;
        const PropertyId &amp;amp; id, M ( T :: * p ), &lt;br /&gt;
        const PropertyCatalog &amp;amp; subordinates = voidCatalog ) const&lt;br /&gt;
    {&lt;br /&gt;
        viewer.reveal (&lt;br /&gt;
            id, TypedVoid &amp;lt; M &amp;gt; (), subordinates );&lt;br /&gt;
    }&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;/div&gt;</summary>
		<author><name>JeffHill</name></author>
	</entry>
	<entry>
		<id>https://wiki-ext.aps.anl.gov/epics/index.php?title=Talk:V4_CA_Interfaces&amp;diff=182</id>
		<title>Talk:V4 CA Interfaces</title>
		<link rel="alternate" type="text/html" href="https://wiki-ext.aps.anl.gov/epics/index.php?title=Talk:V4_CA_Interfaces&amp;diff=182"/>
		<updated>2005-05-20T17:01:21Z</updated>

		<summary type="html">&lt;p&gt;JeffHill: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Some comments from Andrew Johnson:&lt;br /&gt;
&lt;br /&gt;
In your presentation about CA V4, you included the method &lt;br /&gt;
channel::createAllPropertiesReadRequest().  I agree that we need a way &lt;br /&gt;
to be able to read all of the properties available from the server for a &lt;br /&gt;
particular PV name, but I want more flexibility than just being able to &lt;br /&gt;
put that wild-card at the top of my request.&lt;br /&gt;
&lt;br /&gt;
I think we need the ability to be able to subscribe with a property &lt;br /&gt;
catalog having a specific set of properties at one level but to &lt;br /&gt;
wild-card a sub-property catalog at some level below.  Is this currently &lt;br /&gt;
possible?  If not, please consider this a request to add that &lt;br /&gt;
capability, which might then remove the need for the seperate &lt;br /&gt;
createAllPropertiesReadRequest() method.  I'm only looking for you to &lt;br /&gt;
support &amp;quot;*&amp;quot;, no pattern matching or regex stuff.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Some comments from Jeff Hill:&lt;br /&gt;
&lt;br /&gt;
During our meeting I raised a question; do we may need a Data Access interface allowing traversal of the structure of the property hierarchy, learning the native type of the properties, but not require instances of the properties?&lt;br /&gt;
&lt;br /&gt;
There may be legitimate situations where the property catalog egg must come before the property catalog chicken. Furthermore, it might be quite inconvenient from a memory management perspective to require an instance of an array before it is really used. I think that this negative could be perhaps minimized if we state in the CA manual that the array bounds alone will be examined, and the array elements will not be traversed, when scanning a property catalog to learn its structure.&lt;br /&gt;
&lt;br /&gt;
Probably the only negative associated with adding a property catalog structure traverse capability to the interface would be that the application would need to provide one additional function. They are already providing an immutable traverse, a mutable traverse function, and an immutable find function. What is not really right is that all three of the traverse functions are nearly identical. Personally, I don’t like to see common code managed with cut and paste.&lt;br /&gt;
&lt;br /&gt;
So I had a look at what level of Data Access library support might be provided so that they might avoid needing to write three traverse functions. The following is an example of how they might structure their application. This level of complication appears to be reasonable for end user applications. &lt;br /&gt;
&lt;br /&gt;
PropertyId propertyX;&lt;br /&gt;
PropertyId propertyY;&lt;br /&gt;
&lt;br /&gt;
class MyContainer : &lt;br /&gt;
    private PropertyCatalog {&lt;br /&gt;
    int x;&lt;br /&gt;
    float y;&lt;br /&gt;
    static void traverse ( &lt;br /&gt;
        PropertyDescriptionViewer &amp;amp; );&lt;br /&gt;
    void traverse ( &lt;br /&gt;
        PropertyManipulator &amp;amp; );&lt;br /&gt;
    void traverse ( &lt;br /&gt;
        PropertyViewer &amp;amp; ) const;&lt;br /&gt;
    bool find ( &lt;br /&gt;
        const PropertyId &amp;amp; id, PropertyViewer &amp;amp; ) const;&lt;br /&gt;
    template &amp;lt; class REFERENCE, class MANIPULATOR &amp;gt;&lt;br /&gt;
    static void traverseTempl ( &lt;br /&gt;
        const REFERENCE &amp;amp;, MANIPULATOR &amp;amp; );&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
template &amp;lt; class REFERENCE, class MANIPULATOR &amp;gt;&lt;br /&gt;
void MyContainer::traverseTempl ( &lt;br /&gt;
    const REFERENCE &amp;amp; ref, MANIPULATOR &amp;amp; manipulator )&lt;br /&gt;
{&lt;br /&gt;
    manipulator.reveal ( &lt;br /&gt;
        ref.propertyFactory ( propertyX, &amp;amp; MyContainer::x ) );&lt;br /&gt;
    manipulator.reveal ( &lt;br /&gt;
        ref.propertyFactory ( propertyY, &amp;amp; MyContainer::y ) );&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void MyContainer::traverse ( &lt;br /&gt;
    PropertyManipulator &amp;amp; manipulator ) &lt;br /&gt;
{&lt;br /&gt;
    MyContainer::traverseTempl ( &lt;br /&gt;
        reference &amp;lt; MyContainer &amp;gt; ( *this ), manipulator );&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void MyContainer::traverse ( &lt;br /&gt;
    PropertyViewer &amp;amp; viewer ) const &lt;br /&gt;
{&lt;br /&gt;
    MyContainer::traverseTempl ( &lt;br /&gt;
        reference &amp;lt; const MyContainer &amp;gt; ( *this ), viewer );&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void MyContainer::traverse ( &lt;br /&gt;
    PropertyDescriptionViewer &amp;amp; viewer )&lt;br /&gt;
{&lt;br /&gt;
    MyContainer::traverseTempl ( reference &amp;lt; void &amp;gt; (), viewer );&lt;br /&gt;
}&lt;br /&gt;
    &lt;br /&gt;
bool MyContainer::find ( &lt;br /&gt;
    const PropertyId &amp;amp; id, &lt;br /&gt;
    PropertyManipulator &amp;lt; Property &amp;gt; &amp;amp; manipulator ) const &lt;br /&gt;
{&lt;br /&gt;
    bool status = false;&lt;br /&gt;
    if ( id == propertyX ) {&lt;br /&gt;
    	manipulator.reveal ( &lt;br /&gt;
    	    Property &amp;lt; const int &amp;gt; ( propertyX, this-&amp;gt;x ) );&lt;br /&gt;
        status = true;&lt;br /&gt;
    }&lt;br /&gt;
    else ( id == propertyY ) {&lt;br /&gt;
    	manipulator.reveal ( &lt;br /&gt;
    	    Property &amp;lt; const int &amp;gt; ( propertyY, this-&amp;gt;y ) );&lt;br /&gt;
        status = true;&lt;br /&gt;
    }&lt;br /&gt;
    return status;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Here is a summary of the changes:&lt;br /&gt;
* A new &amp;quot;static void traverse ( PropertyDescriptionViewer &amp;amp; );&amp;quot; in the application. This interface might be bound at run time with an ordinary function pointer, and not bound through a pure virtual base. Since data description is accessed through a static member function then ordinary function pointers appear to be a plausible way to bind to this interface. There may not be justification to juxtapose an additional layer of overhead for a virtual interface. That might be necessary only if there was more than one function of this type.&lt;br /&gt;
&lt;br /&gt;
* To allow all three traverse functions to be implemented with a template the properties are revealed using three new property handle types corresponding to the three types of traversal supported. &lt;br /&gt;
&lt;br /&gt;
Here are the slightly revised Data Access interfaces. &lt;br /&gt;
&lt;br /&gt;
enum propertyHandleType {&lt;br /&gt;
    phMutable,&lt;br /&gt;
    phImmutable,&lt;br /&gt;
    phDescription&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
template &amp;lt; propertyHandleType PHT, class T &amp;gt; &lt;br /&gt;
class PropertyHandle;&lt;br /&gt;
&lt;br /&gt;
template &amp;lt; class T &amp;gt; &lt;br /&gt;
class PropertyHandle &amp;lt; phMutable, T &amp;gt; {&lt;br /&gt;
public:&lt;br /&gt;
    PropertyHandle ( &lt;br /&gt;
        const PropertyId &amp;amp; id, T &amp;amp; value,  &lt;br /&gt;
        PropertyCatalog &amp;amp; subordinate = voidContainer );&lt;br /&gt;
    T &amp;amp; value () const;&lt;br /&gt;
    const PropertyId &amp;amp; id () const;&lt;br /&gt;
    PropertyCatalog &amp;amp; subordinate () const;&lt;br /&gt;
private:&lt;br /&gt;
    T &amp;amp; _scalar;&lt;br /&gt;
    const PropertyId &amp;amp; _id;&lt;br /&gt;
    PropertyCatalog &amp;amp; _subordinateProperties;&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
template &amp;lt; class T &amp;gt; &lt;br /&gt;
class PropertyHandle &amp;lt; phImmutable, T &amp;gt; {&lt;br /&gt;
public:&lt;br /&gt;
    PropertyHandle ( &lt;br /&gt;
        const PropertyId &amp;amp; id, const T &amp;amp; value,  &lt;br /&gt;
        const PropertyCatalog &amp;amp; subordinate = voidContainer );&lt;br /&gt;
    const T &amp;amp; value () const;&lt;br /&gt;
    const PropertyId &amp;amp; id () const;&lt;br /&gt;
    const PropertyCatalog &amp;amp; subordinate () const;&lt;br /&gt;
private:&lt;br /&gt;
    const T &amp;amp; _scalar;&lt;br /&gt;
    const PropertyId &amp;amp; _id;&lt;br /&gt;
    const PropertyCatalog &amp;amp; _subordinateProperties;&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
template &amp;lt; class T &amp;gt; &lt;br /&gt;
class PropertyHandle &amp;lt; phDescription, T &amp;gt; {&lt;br /&gt;
public:&lt;br /&gt;
    PropertyHandle ( const PropertyId &amp;amp; id,  &lt;br /&gt;
        const PropertyCatalog &amp;amp; = voidContainer );&lt;br /&gt;
    const PropertyId &amp;amp; id () const;&lt;br /&gt;
    const PropertyCatalog &amp;amp; subordinate () const;&lt;br /&gt;
private:&lt;br /&gt;
    const PropertyId &amp;amp; _id;&lt;br /&gt;
    const PropertyCatalog &amp;amp; _subordinateProperties;&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
template &amp;lt; &lt;br /&gt;
    propertyHandleType PHT, &lt;br /&gt;
    template &amp;lt; propertyHandleType PHT, class T &amp;gt; class PROP_HANDLE &amp;gt;&lt;br /&gt;
class PropertyManipulatorBase {&lt;br /&gt;
public:&lt;br /&gt;
    virtual void reveal ( const PROP_HANDLE &amp;lt; PHT, float &amp;gt; &amp;amp; )  = 0;&lt;br /&gt;
    virtual void reveal ( const PROP_HANDLE &amp;lt; PHT, double &amp;gt; &amp;amp; )  = 0;&lt;br /&gt;
    virtual void reveal ( const PROP_HANDLE &amp;lt; PHT, char &amp;gt; &amp;amp; ) = 0; &lt;br /&gt;
    virtual void reveal ( const PROP_HANDLE &amp;lt; PHT, signed char &amp;gt; &amp;amp; ) = 0; &lt;br /&gt;
    virtual void reveal ( const PROP_HANDLE &amp;lt; PHT, unsigned char &amp;gt; &amp;amp; ) = 0; &lt;br /&gt;
    virtual void reveal ( const PROP_HANDLE &amp;lt; PHT, short &amp;gt; &amp;amp; ) = 0; &lt;br /&gt;
    virtual void reveal ( const PROP_HANDLE &amp;lt; PHT, unsigned short &amp;gt; &amp;amp; ) = 0; &lt;br /&gt;
    virtual void reveal ( const PROP_HANDLE &amp;lt; PHT, int &amp;gt; &amp;amp; ) = 0; &lt;br /&gt;
    virtual void reveal ( const PROP_HANDLE &amp;lt; PHT, unsigned int &amp;gt; &amp;amp; ) = 0; &lt;br /&gt;
    virtual void reveal ( const PROP_HANDLE &amp;lt; PHT, long &amp;gt; &amp;amp; ) = 0; &lt;br /&gt;
    virtual void reveal ( const PROP_HANDLE &amp;lt; PHT, unsigned long &amp;gt; &amp;amp; ) = 0; &lt;br /&gt;
    virtual void reveal ( const PROP_HANDLE &amp;lt; PHT, Time &amp;gt; &amp;amp; ) = 0; &lt;br /&gt;
    virtual void reveal ( const PROP_HANDLE &amp;lt; PHT, StringSegment &amp;gt; &amp;amp; ) = 0; &lt;br /&gt;
    virtual void reveal ( const PROP_HANDLE &amp;lt; PHT, EnumStateSet &amp;gt; &amp;amp; ) = 0; &lt;br /&gt;
    virtual void reveal ( const PROP_HANDLE &amp;lt; PHT, ArraySegment &amp;gt; &amp;amp; ) = 0; &lt;br /&gt;
    virtual void reveal ( const PROP_HANDLE &amp;lt; PHT, PropertyCatalog &amp;gt; &amp;amp; ) = 0; &lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
class PropertyManipulator :&lt;br /&gt;
    public PropertyManipulatorBase &amp;lt; phMutable, PropertyHandle &amp;gt; {&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
class PropertyViewer :&lt;br /&gt;
    public PropertyManipulatorBase &amp;lt; phImmutable, PropertyHandle &amp;gt; {&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
class PropertyDescriptionViewer :&lt;br /&gt;
    public PropertyManipulatorBase &amp;lt; phDescription, PropertyHandle &amp;gt; {&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
class PropertyCatalog {&lt;br /&gt;
public:&lt;br /&gt;
    virtual void traverse ( &lt;br /&gt;
        PropertyManipulator &amp;amp; ) = 0;&lt;br /&gt;
    virtual void traverse ( &lt;br /&gt;
        PropertyViewer &amp;amp; ) const = 0;&lt;br /&gt;
    // false returned when the property does not exist, otherwise true&lt;br /&gt;
    virtual bool find ( &lt;br /&gt;
        const PropertyId &amp;amp; id, PropertyViewer &amp;amp; ) const = 0;&lt;br /&gt;
};&lt;/div&gt;</summary>
		<author><name>JeffHill</name></author>
	</entry>
	<entry>
		<id>https://wiki-ext.aps.anl.gov/epics/index.php?title=User:JeffHill&amp;diff=2729</id>
		<title>User:JeffHill</title>
		<link rel="alternate" type="text/html" href="https://wiki-ext.aps.anl.gov/epics/index.php?title=User:JeffHill&amp;diff=2729"/>
		<updated>2005-05-17T17:46:45Z</updated>

		<summary type="html">&lt;p&gt;JeffHill: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[V4_CA_Interfaces]]&lt;/div&gt;</summary>
		<author><name>JeffHill</name></author>
	</entry>
	<entry>
		<id>https://wiki-ext.aps.anl.gov/epics/index.php?title=Talk:V4_CA_Interfaces&amp;diff=147</id>
		<title>Talk:V4 CA Interfaces</title>
		<link rel="alternate" type="text/html" href="https://wiki-ext.aps.anl.gov/epics/index.php?title=Talk:V4_CA_Interfaces&amp;diff=147"/>
		<updated>2005-05-17T17:32:52Z</updated>

		<summary type="html">&lt;p&gt;JeffHill: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;From Andrew Johnson:&lt;br /&gt;
&lt;br /&gt;
In your presentation about CA V4, you included the method &lt;br /&gt;
channel::createAllPropertiesReadRequest().  I agree that we need a way &lt;br /&gt;
to be able to read all of the properties available from the server for a &lt;br /&gt;
particular PV name, but I want more flexibility than just being able to &lt;br /&gt;
put that wild-cared at the top of my request.&lt;br /&gt;
&lt;br /&gt;
I think we need the ability to be able to subscribe with a property &lt;br /&gt;
catalog having a specific set of properties at the top level but to &lt;br /&gt;
wild-card a sub-property catalog at the level below.  Is this currently &lt;br /&gt;
possible?  If not, please consider this a request to add that &lt;br /&gt;
capability, which might then remove the need for the seperate &lt;br /&gt;
createAllPropertiesReadRequest() method.  I'm only looking for you to &lt;br /&gt;
support &amp;quot;*&amp;quot;, no pattern matching or regex stuff.&lt;/div&gt;</summary>
		<author><name>JeffHill</name></author>
	</entry>
	<entry>
		<id>https://wiki-ext.aps.anl.gov/epics/index.php?title=Talk:V4_Standard_Properties_and_Events&amp;diff=2727</id>
		<title>Talk:V4 Standard Properties and Events</title>
		<link rel="alternate" type="text/html" href="https://wiki-ext.aps.anl.gov/epics/index.php?title=Talk:V4_Standard_Properties_and_Events&amp;diff=2727"/>
		<updated>2005-05-17T17:14:09Z</updated>

		<summary type="html">&lt;p&gt;JeffHill: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;# I think that it is important from the start to clearly define the timestamp, alarmSeverity, alarmStatus, units etc to be subordinates of the value property. Therefore they would be one level further down in the hierarchy. Specifically, if value is 1.1 then timestamp should be 1.1.1 and alarmSeverity should be 1.1.2 etc. Same thing with bullet delineated lists - the value property might be further over to the left and things below it should be on tab stop to the right. This approach allows multiple values to be in the same record. For example, we might have an &amp;quot;xPosition&amp;quot; and a &amp;quot;yPosition&amp;quot;. The paradigm where the limits and the value are at the same level in the hierarchy fits from a C programmers perspective because that is how one tends to make u p structures, but it tends to break down when designing external interfaces for the system. For example, one might have a single property named &amp;quot;xPosition&amp;quot; that is a double. Later, when adding limits for &amp;quot;xPosition&amp;quot;, a backwards incompatible property hierarchy change has to occur when this double is changed to an &amp;quot;xPosition&amp;quot; container that has a double in it who's property name is &amp;quot;value&amp;quot;. &lt;br /&gt;
# Hopefully, we can avoid having to place &amp;quot;value&amp;quot;, which does not convey any additional meaning, in any V4 channel name. For example we might have channel names like the following.&lt;br /&gt;
#* single value channel names&lt;br /&gt;
#** analogDevice10&lt;br /&gt;
#** analogDevice10/timestamp&lt;br /&gt;
#** analogDevice10/diplayLimits/high&lt;br /&gt;
#* dual value channel names&lt;br /&gt;
#** axisDevice10/xPosition&lt;br /&gt;
#** axisDevice10/yPosition&lt;br /&gt;
#** axisDevice10/xPosition/timestamp&lt;br /&gt;
#** axisDevice10/xPosition/diplayLimits/high&lt;br /&gt;
#*Should a user supply any of the following channel names they would not find a matching service to connect to (hopefully there would be an error message identifying the available choices when they specify a leaf missing from the hierarchy).&lt;br /&gt;
#** axisDevice10&lt;br /&gt;
#** axisDevice10/timestamp&lt;br /&gt;
# Perhaps we should use &amp;quot;.&amp;quot; (a dot) only for backwards compatibility and use a &amp;quot;/&amp;quot; (slash) to denote 4.0 hierarchy? For example a CA channel name might look like &amp;quot;myChannel/timeStamp&amp;quot;, &amp;quot;myChannel/xPosition/diplayLimits/high&amp;quot;, or &amp;quot;myChannel.HOPR&amp;quot;. Just thinking out loud here.&lt;br /&gt;
# I'm not sure how hierarchies of properties interact with this concept of a view. I see that a view is intended to be a very general approach with the option for an application specific plug in interpreting the view parameters so I should probably wait to see what you will define in the doc later. Nevertheless, I am still wondering if you will allow hierarchy in the channel name prior to specifying the view for the end leaf?&lt;br /&gt;
# The need for a list of fields appears to be driven by (A) backwards compatibility (see comment about &amp;quot;.&amp;quot; above) and (B) the need to have an unambiguous list of all properties necessary to maintain a backup of the state of a record with the option of restoring it later. Related to (B) I certainly do understand the issue that portions of the records state could show up multiple times in the generalized property hierarchy. A negative related to placing the concept of fields in public interfaces is of course additional complexity and with complexity confusion, potential for code bloat, and training class bloat. Perhaps one solution would be to add a capability to make an &amp;quot;all properties read&amp;quot; request that is further constrained to send internal state only once, and thereby eliminate leaves in the property hierarchy that might be redundant when expressing the internal state. Just thinking out loud again here.&lt;br /&gt;
# It might be best to avoid more than four properties at any given level in the hierarchy. There can be important performance advantages associated with that organization from a dataAccess interfacing perspective, and perhaps this will make the code, and documentation, more modular as well.&lt;/div&gt;</summary>
		<author><name>JeffHill</name></author>
	</entry>
	<entry>
		<id>https://wiki-ext.aps.anl.gov/epics/index.php?title=Talk:V4_Standard_Properties_and_Events&amp;diff=136</id>
		<title>Talk:V4 Standard Properties and Events</title>
		<link rel="alternate" type="text/html" href="https://wiki-ext.aps.anl.gov/epics/index.php?title=Talk:V4_Standard_Properties_and_Events&amp;diff=136"/>
		<updated>2005-05-17T17:10:42Z</updated>

		<summary type="html">&lt;p&gt;JeffHill: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;# I think that it is important from the start to clearly define the timestamp, alarmSeverity, alarmStatus, units etc to be subordinates of the value property. Therefore they would be one level further down in the hierarchy. Specifically, if value is 1.1 then timestamp should be 1.1.1 and alarmSeverity should be 1.1.2 etc. Same thing with bullet delineated lists - the value property might be further over to the left and things below it should be on tab stop to the right. This approach allows multiple values to be in the same record. For example, we might have an &amp;quot;xPosition&amp;quot; and a &amp;quot;yPosition&amp;quot;. The paradigm where the limits and the value are at the same level in the hierarchy fits from a C programmers perspective because that is how one tends to make u p structures, but it tends to break down when designing external interfaces for the system. For example, one might have a single property named &amp;quot;xPosition&amp;quot; that is a double. Later, when adding limits for &amp;quot;xPosition&amp;quot;, a backwards incompatible property hierarchy change has to occur when this double is changed to an &amp;quot;xPosition&amp;quot; container that has a double in it who's property name is &amp;quot;value&amp;quot;. &lt;br /&gt;
# Hopefully, we can avoid having to place &amp;quot;value&amp;quot;, which does not convey any additional meaning, in any V4 channel name. For example we might have channel names like the following.&lt;br /&gt;
* single value channel names&lt;br /&gt;
** analogDevice10&lt;br /&gt;
** analogDevice10/timestamp&lt;br /&gt;
** analogDevice10/diplayLimits/high&lt;br /&gt;
* dual value channel names&lt;br /&gt;
** axisDevice10/xPosition&lt;br /&gt;
** axisDevice10/yPosition&lt;br /&gt;
** axisDevice10/xPosition/timestamp&lt;br /&gt;
** axisDevice10/xPosition/diplayLimits/high&lt;br /&gt;
*Should a user supply any of the following channel names they would not find a matching service to connect to (hopefully there would be an error message identifying the available choices when they specify a leaf missing from the hierarchy).&lt;br /&gt;
** axisDevice10&lt;br /&gt;
** axisDevice10/timestamp&lt;br /&gt;
# Perhaps we should use &amp;quot;.&amp;quot; (a dot) only for backwards compatibility and use a &amp;quot;/&amp;quot; (slash) to denote 4.0 hierarchy? For example a CA channel name might look like &amp;quot;myChannel/timeStamp&amp;quot;, &amp;quot;myChannel/xPosition/diplayLimits/high&amp;quot;, or &amp;quot;myChannel.HOPR&amp;quot;. Just thinking out loud here.&lt;br /&gt;
# I'm not sure how hierarchies of properties interact with this concept of a view. I see that a view is intended to be a very general approach with the option for an application specific plug in interpreting the view parameters so I should probably wait to see what you will define in the doc later. Nevertheless, I am still wondering if you will allow hierarchy in the channel name prior to specifying the view for the end leaf?&lt;br /&gt;
# The need for a list of fields appears to be driven by (A) backwards compatibility (see comment about &amp;quot;.&amp;quot; above) and (B) the need to have an unambiguous list of all properties necessary to maintain a backup of the state of a record with the option of restoring it later. Related to (B) I certainly do understand the issue that portions of the records state could show up multiple times in the generalized property hierarchy. A negative related to placing the concept of fields in public interfaces is of course additional complexity and with complexity confusion, potential for code bloat, and training class bloat. Perhaps one solution would be to add a capability to make an &amp;quot;all properties read&amp;quot; request that is further constrained to send internal state only once, and thereby eliminate leaves in the property hierarchy that might be redundant when expressing the internal state. Just thinking out loud again here.&lt;br /&gt;
# It might be best to avoid more than four properties at any given level in the hierarchy. There can be important performance advantages associated with that organization from a dataAccess interfacing perspective, and perhaps this will make the code, and documentation, more modular as well.&lt;/div&gt;</summary>
		<author><name>JeffHill</name></author>
	</entry>
	<entry>
		<id>https://wiki-ext.aps.anl.gov/epics/index.php?title=Talk:V4_Standard_Properties_and_Events&amp;diff=135</id>
		<title>Talk:V4 Standard Properties and Events</title>
		<link rel="alternate" type="text/html" href="https://wiki-ext.aps.anl.gov/epics/index.php?title=Talk:V4_Standard_Properties_and_Events&amp;diff=135"/>
		<updated>2005-05-17T17:00:56Z</updated>

		<summary type="html">&lt;p&gt;JeffHill: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;1) I think that it is important from the start to clearly define the timestamp, alarmSeverity, alarmStatus, units etc to be subordinates of the value property. Therefore they would be one level further down in the hierarchy. Specifically, if value is 1.1 then timestamp should be 1.1.1 and alarmSeverity should be 1.1.2 etc. Same thing with bullet delineated lists - the value property might be further over to the left and things below it should be on tab stop to the right. This approach allows multiple values to be in the same record. For example, we might have an &amp;quot;xPosition&amp;quot; and a &amp;quot;yPosition&amp;quot;. The paradigm where the limits and the value are at the same level in the hierarchy fits from a C programmers perspective because that is how one tends to make u p structures, but it tends to break down when designing external interfaces for the system. For example, one might have a single property named &amp;quot;xPosition&amp;quot; that is a double. Later, when adding limits for &amp;quot;xPosition&amp;quot;, a backwards incompatible property hierarchy change has to occur when this double is changed to an &amp;quot;xPosition&amp;quot; container that has a double in it who's property name is &amp;quot;value&amp;quot;. &lt;br /&gt;
&lt;br /&gt;
2) Hopefully, we can avoid having to place &amp;quot;value&amp;quot;, which does not convey any additional meaning, in any V4 channel name. For example we might have channel names like &lt;br /&gt;
&lt;br /&gt;
* analogDevice10&lt;br /&gt;
* analogDevice10/timestamp&lt;br /&gt;
* analogDevice10/diplayLimits/high&lt;br /&gt;
&lt;br /&gt;
* axisDevice10/xPosition&lt;br /&gt;
* axisDevice10/xPosition/timestamp&lt;br /&gt;
* axisDevice10/xPosition/diplayLimits/high&lt;br /&gt;
&lt;br /&gt;
Should a user supply any of the following channel names they would not find a matching service to connect to (hopefully there would be an error message identifying the available choices when they specify a leaf missing from the hierarchy).&lt;br /&gt;
&lt;br /&gt;
* axisDevice10&lt;br /&gt;
* axisDevice10/timestamp&lt;br /&gt;
&lt;br /&gt;
3) Perhaps we should use &amp;quot;.&amp;quot; (a dot) only for backwards compatibility and use a &amp;quot;/&amp;quot; (slash) to denote 4.0 hierarchy? For example a CA channel name might look like &amp;quot;myChannel/timeStamp&amp;quot;, &amp;quot;myChannel/xPosition/diplayLimits/high&amp;quot;, or &amp;quot;myChannel.HOPR&amp;quot;. Just thinking out loud here.&lt;br /&gt;
&lt;br /&gt;
4) I'm not sure how hierarchies of properties interact with this concept of a view. I see that a view is intended to be a very general approach with the option for an application specific plug in interpreting the view parameters so I should probably wait to see what you will define in the doc later. Nevertheless, I am still wondering if you will allow hierarchy in the channel name prior to specifying the view for the end leaf?&lt;br /&gt;
&lt;br /&gt;
4) The need for a list of fields appears to be driven by (A) backwards compatibility (see comment about &amp;quot;.&amp;quot; above) and (B) the need to have an unambiguous list of all properties necessary to maintain a backup of the state of a record with the option of restoring it later. Related to (B) I certainly do understand the issue that portions of the records state could show up multiple times in the generalized property hierarchy. A negative related to placing the concept of fields in public interfaces is of course additional complexity and with complexity confusion, potential for code bloat, and training class bloat. Perhaps one solution would be to add a capability to make an &amp;quot;all properties read&amp;quot; request that is further constrained to send internal state only once, and thereby eliminate leaves in the property hierarchy that might be redundant when expressing the internal state. Just thinking out loud again here.&lt;br /&gt;
&lt;br /&gt;
5) It might be best to avoid more than four properties at any given level in the hierarchy. There can be important performance advantages associated with that organization from a dataAccess interfacing perspective, and perhaps this will make the code, and documentation, more modular as well.&lt;/div&gt;</summary>
		<author><name>JeffHill</name></author>
	</entry>
	<entry>
		<id>https://wiki-ext.aps.anl.gov/epics/index.php?title=Talk:V4_Standard_Properties_and_Events&amp;diff=134</id>
		<title>Talk:V4 Standard Properties and Events</title>
		<link rel="alternate" type="text/html" href="https://wiki-ext.aps.anl.gov/epics/index.php?title=Talk:V4_Standard_Properties_and_Events&amp;diff=134"/>
		<updated>2005-05-17T16:56:30Z</updated>

		<summary type="html">&lt;p&gt;JeffHill: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;1) I think that it is important from the start to clearly define the timestamp, alarmSeverity, alarmStatus, units etc to be subordinates of the value property. Therefore they would be one level further down in the hierarchy. Specifically, if value is 1.1 then timestamp should be 1.1.1 and alarmSeverity should be 1.1.2 etc. Same thing with bullet delineated lists - the value property might be further over to the left and things below it should be on tab stop to the right. This approach allows multiple values to be in the same record. For example, we might have an &amp;quot;xPosition&amp;quot; and a &amp;quot;yPosition&amp;quot;. The paradigm where the limits and the value are at the same level in the hierarchy fits from a C programmers perspective because that is how one tends to make u p structures, but it tends to break down when designing external interfaces for the system. For example, one might have a single property named &amp;quot;xPosition&amp;quot; that is a double. Later, when adding limits for &amp;quot;xPosition&amp;quot;, a backwards incompatible property hierarchy change has to occur when this double is changed to an &amp;quot;xPosition&amp;quot; container that has a double in it who's property name is &amp;quot;value&amp;quot;. &lt;br /&gt;
&lt;br /&gt;
2) Hopefully, we can avoid having to place &amp;quot;value&amp;quot;, which does not convey any additional meaning, in any V4 channel name. For example we might have channel names like &lt;br /&gt;
&lt;br /&gt;
analogDevice10&lt;br /&gt;
analogDevice10/timestamp&lt;br /&gt;
analogDevice10/diplayLimits/high&lt;br /&gt;
&lt;br /&gt;
axisDevice10/xPosition&lt;br /&gt;
axisDevice10/xPosition/timestamp&lt;br /&gt;
axisDevice10/xPosition/diplayLimits/high&lt;br /&gt;
&lt;br /&gt;
Should a user supply any of the following channel names they would not find a matching service to connect to (hopefully there would be an error message identifying the available choices when they specify a leaf missing from the hierarchy).&lt;br /&gt;
&lt;br /&gt;
axisDevice10&lt;br /&gt;
axisDevice10/timestamp&lt;br /&gt;
&lt;br /&gt;
3) Perhaps we should use &amp;quot;.&amp;quot; (a dot) only for backwards compatibility and use a &amp;quot;/&amp;quot; (slash) to denote 4.0 hierarchy? For example a CA channel name might look like &amp;quot;myChannel/timeStamp&amp;quot;, &amp;quot;myChannel/xPosition/diplayLimits/high&amp;quot;, or &amp;quot;myChannel.HOPR&amp;quot;. Just thinking out loud here.&lt;br /&gt;
&lt;br /&gt;
4) I'm not sure how hierarchies of properties interact with this concept of a view. I see that a view is intended to be a very general approach with the option for an application specific plug in interpreting the view parameters so I should probably wait to see what you will define in the doc later. Nevertheless, I am still wondering if you will allow hierarchy in the channel name prior to specifying the view for the end leaf?&lt;br /&gt;
&lt;br /&gt;
4) The need for a list of fields appears to be driven by (A) backwards compatibility (see comment about &amp;quot;.&amp;quot; above) and (B) the need to have an unambiguous list of all properties necessary to maintain a backup of the state of a record with the option of restoring it later. Related to (B) I certainly do understand the issue that portions of the records state could show up multiple times in the generalized property hierarchy. A negative related to placing the concept of fields in public interfaces is of course additional complexity and with complexity confusion, potential for code bloat, and training class bloat. Perhaps one solution would be to add a capability to make an &amp;quot;all properties read&amp;quot; request that is further constrained to send internal state only once, and thereby eliminate leaves in the property hierarchy that might be redundant when expressing the internal state. Just thinking out loud again here.&lt;br /&gt;
&lt;br /&gt;
5) It might be best to avoid more than four properties at any given level in the hierarchy. There can be important performance advantages associated with that organization from a dataAccess interfacing perspective, and perhaps this will make the code, and documentation, more modular as well.&lt;/div&gt;</summary>
		<author><name>JeffHill</name></author>
	</entry>
	<entry>
		<id>https://wiki-ext.aps.anl.gov/epics/index.php?title=Evolution_of_EPICS_Core&amp;diff=1348</id>
		<title>Evolution of EPICS Core</title>
		<link rel="alternate" type="text/html" href="https://wiki-ext.aps.anl.gov/epics/index.php?title=Evolution_of_EPICS_Core&amp;diff=1348"/>
		<updated>2005-05-10T23:56:49Z</updated>

		<summary type="html">&lt;p&gt;JeffHill: /* '''V???? – Avccess Security Upgrades''' */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== '''V4 – Executive Summary''' ==&lt;br /&gt;
*Provide online add/delete of I/O to support continuous operation.&lt;br /&gt;
*Provide redundant control of remote I/O to support improved reliability.&lt;br /&gt;
*Provide name introspection and domain control in support of seamless *integration of large control systems&lt;br /&gt;
*Provide triggers, filters, and rate limits to improve resource use of network and client side processing&lt;br /&gt;
*Provide hierarchical devices to support higher level view of application in the front-end processors.&lt;br /&gt;
*Provide automatic backup and restore to support bump-less reboot and synchronization of redundant controllers.&lt;br /&gt;
*Provide atomic read, write, and write with read-back to multiple channels to support synchronized access of arbitrary sets of channels.&lt;br /&gt;
*Support international users with uni-code and time.&lt;br /&gt;
*Remove limitations on string lengths, device states, number of input links to support arbitrary sizes.&lt;br /&gt;
*Internationalize Time Stamps&lt;br /&gt;
&lt;br /&gt;
== '''V4 – Structure and Array Support''' ==&lt;br /&gt;
*Allows definition and access to complex devices and multi-dimensional arrays&lt;br /&gt;
*Name hierarchy in Channel Access&lt;br /&gt;
**&amp;lt;arbitrary string&amp;gt;.structure. Element[n]&lt;br /&gt;
**e.g. Arc3PwrSupply.readback.status, ArcPwrSupply.readback.value&lt;br /&gt;
*Device description in database&lt;br /&gt;
*Support arbitrary number of inputs to calculations and subroutines.&lt;br /&gt;
*Support multi-state devices of an arbitrary number of states&lt;br /&gt;
&lt;br /&gt;
== '''V4 – Data Acquisition Capabilities''' ==&lt;br /&gt;
*New subscription parameters&lt;br /&gt;
**Rate limit&lt;br /&gt;
**Value changes (as before but also % change)&lt;br /&gt;
**Triggers&lt;br /&gt;
**Filters&lt;br /&gt;
**Examples&lt;br /&gt;
**Send BPM at 1 Hz (where 1 Hz across IOCs is the same)&lt;br /&gt;
**Send BPM when trigger specifies that this pulse is e-&lt;br /&gt;
**Send RF reading when filter says that vacuum is higher than 10e-6 torr&lt;br /&gt;
*Allows more accurate requests for data on client applications &lt;br /&gt;
*Reduces the amount of network and client CPU usage&lt;br /&gt;
*Specify priority for circuit - QOS&lt;br /&gt;
&lt;br /&gt;
== '''V4 – Device Read/Write Operations''' ==&lt;br /&gt;
*Allows multiple fields to be read/written as an atomic operation &lt;br /&gt;
*Reads/Writes can be triggered&lt;br /&gt;
**e.g. Put( Corr1.K, Corr2.K, Corr3.K, on trigger event)&lt;br /&gt;
**All puts take place when the trigger event occurs&lt;br /&gt;
*Write with return data support (Command/Response)&lt;br /&gt;
*Ramping/arb function outputs – given two end points&lt;br /&gt;
&lt;br /&gt;
== '''V4 – Name Resolution Extensions''' ==&lt;br /&gt;
*Allow wildcard searches &lt;br /&gt;
*Allow request to send all names supported in the IOC&lt;br /&gt;
*Support redundancy by allowing connections to specify that they are not active&lt;br /&gt;
*Support multiple name servers by allowing connections to specify how close to the source they are.&lt;br /&gt;
*Name aliasing supported.&lt;br /&gt;
&lt;br /&gt;
== '''V4 – Online Add / Delete''' ==&lt;br /&gt;
*Support hardware address change during operation &lt;br /&gt;
*Allow new record instances to be loaded at any time&lt;br /&gt;
*Support addition of hardware of an already supported type (64x)&lt;br /&gt;
*Support addition of new hardware during operation.&lt;br /&gt;
*Remove records during operation.&lt;br /&gt;
&lt;br /&gt;
== '''V4 – Redundancy: Multiple masters of remote I/O''' ==&lt;br /&gt;
*Support name responses from multiple controllers of the same database.&lt;br /&gt;
*Support request for all fields from a primary database to its backup.&lt;br /&gt;
*Support a request for all fields that have changed since the last synchronization of the backup to the primary.&lt;br /&gt;
*Support a mechanism for switching from the primary to the backup.&lt;br /&gt;
*Provide a mechanism for synchronizing primary and the backup.&lt;br /&gt;
*Support multiple communication paths that provide&lt;br /&gt;
**an isolated network for synchronization traffic&lt;br /&gt;
**redundant checks to synchronize switch over behavior.&lt;br /&gt;
*Provide a mechanism to start/stop scanning&lt;br /&gt;
*Provide a mechanism to start/stop sequences&lt;br /&gt;
*Provide a mechanism to start/stop drivers from scanning&lt;br /&gt;
&lt;br /&gt;
== '''V4 – Support Large / Multi-segmented Control System''' ==&lt;br /&gt;
*Support load balancing between multiple data sources (1st order gateway, 2nd order gateway, IOC, and load).&lt;br /&gt;
*Support domain control independent of network topology&lt;br /&gt;
**Beamline data is not available to the control room&lt;br /&gt;
**Only insertion gap and beam quality information is available to the beamline controls from the ring control room.&lt;br /&gt;
&lt;br /&gt;
=='''V4 – Extendable Metadata / Properties''' ==&lt;br /&gt;
*Metadata can be extendable –&lt;br /&gt;
**Add array dimensions&lt;br /&gt;
**Add time base to an array&lt;br /&gt;
**Application programmers can add metadata&lt;br /&gt;
*Specify metadata by field rather than record&lt;br /&gt;
**Only get metadata when it is meaningful&lt;br /&gt;
**No display limits for the high display limit&lt;br /&gt;
*Calc and subroutine records have arrays of inputs&lt;br /&gt;
**No limit to the number of variables&lt;br /&gt;
&lt;br /&gt;
=='''V4 – Channel Access Diagnostics'''==&lt;br /&gt;
*Server Diagnostics&lt;br /&gt;
**Connections&lt;br /&gt;
**Channels&lt;br /&gt;
**Events per second&lt;br /&gt;
**State of Health&lt;br /&gt;
**Beacon Periodicity&lt;br /&gt;
**Etc…&lt;br /&gt;
*Client Diagnostics&lt;br /&gt;
**Number of connections/server per client&lt;br /&gt;
**Number of channels&lt;br /&gt;
**Events per second&lt;br /&gt;
**State of connection&lt;br /&gt;
**Etc…..&lt;br /&gt;
&lt;br /&gt;
=='''V4 – Limitations Remediation'''==&lt;br /&gt;
*Multi-line text &lt;br /&gt;
*Variable length strings&lt;br /&gt;
**Removes current limitations of 40 characters&lt;br /&gt;
**Reduces size of memory use in most cases&lt;br /&gt;
**Reduces network traffic in most cases&lt;br /&gt;
*Unicode&lt;br /&gt;
**Support alternate character sets&lt;br /&gt;
*Multidimensional arrays&lt;br /&gt;
*Variable size arrays&lt;br /&gt;
&lt;br /&gt;
=='''V4 – Time Stamp Internationalization'''==&lt;br /&gt;
*Support ISO 8601 Format&lt;br /&gt;
**Year-month-date-hours-minutes-seconds-fractional seconds&lt;br /&gt;
**Country specific time stamps&lt;br /&gt;
*Support Locale Settings for conversions&lt;br /&gt;
**,02 as 2 hundreds of a second&lt;br /&gt;
&lt;br /&gt;
=='''V???? – Access Security Upgrades'''==&lt;br /&gt;
*Kerberos style authentication&lt;br /&gt;
*User specific CA client resource consumption quotas in access security system&lt;br /&gt;
*Confirmation requested hint (no mods w/o poping an are-you-sure dialog box)&lt;/div&gt;</summary>
		<author><name>JeffHill</name></author>
	</entry>
	<entry>
		<id>https://wiki-ext.aps.anl.gov/epics/index.php?title=Evolution_of_EPICS_Core&amp;diff=76</id>
		<title>Evolution of EPICS Core</title>
		<link rel="alternate" type="text/html" href="https://wiki-ext.aps.anl.gov/epics/index.php?title=Evolution_of_EPICS_Core&amp;diff=76"/>
		<updated>2005-05-10T23:55:04Z</updated>

		<summary type="html">&lt;p&gt;JeffHill: /* '''V???? – Resource Consumption Quotas''' */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== '''V4 – Executive Summary''' ==&lt;br /&gt;
*Provide online add/delete of I/O to support continuous operation.&lt;br /&gt;
*Provide redundant control of remote I/O to support improved reliability.&lt;br /&gt;
*Provide name introspection and domain control in support of seamless *integration of large control systems&lt;br /&gt;
*Provide triggers, filters, and rate limits to improve resource use of network and client side processing&lt;br /&gt;
*Provide hierarchical devices to support higher level view of application in the front-end processors.&lt;br /&gt;
*Provide automatic backup and restore to support bump-less reboot and synchronization of redundant controllers.&lt;br /&gt;
*Provide atomic read, write, and write with read-back to multiple channels to support synchronized access of arbitrary sets of channels.&lt;br /&gt;
*Support international users with uni-code and time.&lt;br /&gt;
*Remove limitations on string lengths, device states, number of input links to support arbitrary sizes.&lt;br /&gt;
*Internationalize Time Stamps&lt;br /&gt;
&lt;br /&gt;
== '''V4 – Structure and Array Support''' ==&lt;br /&gt;
*Allows definition and access to complex devices and multi-dimensional arrays&lt;br /&gt;
*Name hierarchy in Channel Access&lt;br /&gt;
**&amp;lt;arbitrary string&amp;gt;.structure. Element[n]&lt;br /&gt;
**e.g. Arc3PwrSupply.readback.status, ArcPwrSupply.readback.value&lt;br /&gt;
*Device description in database&lt;br /&gt;
*Support arbitrary number of inputs to calculations and subroutines.&lt;br /&gt;
*Support multi-state devices of an arbitrary number of states&lt;br /&gt;
&lt;br /&gt;
== '''V4 – Data Acquisition Capabilities''' ==&lt;br /&gt;
*New subscription parameters&lt;br /&gt;
**Rate limit&lt;br /&gt;
**Value changes (as before but also % change)&lt;br /&gt;
**Triggers&lt;br /&gt;
**Filters&lt;br /&gt;
**Examples&lt;br /&gt;
**Send BPM at 1 Hz (where 1 Hz across IOCs is the same)&lt;br /&gt;
**Send BPM when trigger specifies that this pulse is e-&lt;br /&gt;
**Send RF reading when filter says that vacuum is higher than 10e-6 torr&lt;br /&gt;
*Allows more accurate requests for data on client applications &lt;br /&gt;
*Reduces the amount of network and client CPU usage&lt;br /&gt;
*Specify priority for circuit - QOS&lt;br /&gt;
&lt;br /&gt;
== '''V4 – Device Read/Write Operations''' ==&lt;br /&gt;
*Allows multiple fields to be read/written as an atomic operation &lt;br /&gt;
*Reads/Writes can be triggered&lt;br /&gt;
**e.g. Put( Corr1.K, Corr2.K, Corr3.K, on trigger event)&lt;br /&gt;
**All puts take place when the trigger event occurs&lt;br /&gt;
*Write with return data support (Command/Response)&lt;br /&gt;
*Ramping/arb function outputs – given two end points&lt;br /&gt;
&lt;br /&gt;
== '''V4 – Name Resolution Extensions''' ==&lt;br /&gt;
*Allow wildcard searches &lt;br /&gt;
*Allow request to send all names supported in the IOC&lt;br /&gt;
*Support redundancy by allowing connections to specify that they are not active&lt;br /&gt;
*Support multiple name servers by allowing connections to specify how close to the source they are.&lt;br /&gt;
*Name aliasing supported.&lt;br /&gt;
&lt;br /&gt;
== '''V4 – Online Add / Delete''' ==&lt;br /&gt;
*Support hardware address change during operation &lt;br /&gt;
*Allow new record instances to be loaded at any time&lt;br /&gt;
*Support addition of hardware of an already supported type (64x)&lt;br /&gt;
*Support addition of new hardware during operation.&lt;br /&gt;
*Remove records during operation.&lt;br /&gt;
&lt;br /&gt;
== '''V4 – Redundancy: Multiple masters of remote I/O''' ==&lt;br /&gt;
*Support name responses from multiple controllers of the same database.&lt;br /&gt;
*Support request for all fields from a primary database to its backup.&lt;br /&gt;
*Support a request for all fields that have changed since the last synchronization of the backup to the primary.&lt;br /&gt;
*Support a mechanism for switching from the primary to the backup.&lt;br /&gt;
*Provide a mechanism for synchronizing primary and the backup.&lt;br /&gt;
*Support multiple communication paths that provide&lt;br /&gt;
**an isolated network for synchronization traffic&lt;br /&gt;
**redundant checks to synchronize switch over behavior.&lt;br /&gt;
*Provide a mechanism to start/stop scanning&lt;br /&gt;
*Provide a mechanism to start/stop sequences&lt;br /&gt;
*Provide a mechanism to start/stop drivers from scanning&lt;br /&gt;
&lt;br /&gt;
== '''V4 – Support Large / Multi-segmented Control System''' ==&lt;br /&gt;
*Support load balancing between multiple data sources (1st order gateway, 2nd order gateway, IOC, and load).&lt;br /&gt;
*Support domain control independent of network topology&lt;br /&gt;
**Beamline data is not available to the control room&lt;br /&gt;
**Only insertion gap and beam quality information is available to the beamline controls from the ring control room.&lt;br /&gt;
&lt;br /&gt;
=='''V4 – Extendable Metadata / Properties''' ==&lt;br /&gt;
*Metadata can be extendable –&lt;br /&gt;
**Add array dimensions&lt;br /&gt;
**Add time base to an array&lt;br /&gt;
**Application programmers can add metadata&lt;br /&gt;
*Specify metadata by field rather than record&lt;br /&gt;
**Only get metadata when it is meaningful&lt;br /&gt;
**No display limits for the high display limit&lt;br /&gt;
*Calc and subroutine records have arrays of inputs&lt;br /&gt;
**No limit to the number of variables&lt;br /&gt;
&lt;br /&gt;
=='''V4 – Channel Access Diagnostics'''==&lt;br /&gt;
*Server Diagnostics&lt;br /&gt;
**Connections&lt;br /&gt;
**Channels&lt;br /&gt;
**Events per second&lt;br /&gt;
**State of Health&lt;br /&gt;
**Beacon Periodicity&lt;br /&gt;
**Etc…&lt;br /&gt;
*Client Diagnostics&lt;br /&gt;
**Number of connections/server per client&lt;br /&gt;
**Number of channels&lt;br /&gt;
**Events per second&lt;br /&gt;
**State of connection&lt;br /&gt;
**Etc…..&lt;br /&gt;
&lt;br /&gt;
=='''V4 – Limitations Remediation'''==&lt;br /&gt;
*Multi-line text &lt;br /&gt;
*Variable length strings&lt;br /&gt;
**Removes current limitations of 40 characters&lt;br /&gt;
**Reduces size of memory use in most cases&lt;br /&gt;
**Reduces network traffic in most cases&lt;br /&gt;
*Unicode&lt;br /&gt;
**Support alternate character sets&lt;br /&gt;
*Multidimensional arrays&lt;br /&gt;
*Variable size arrays&lt;br /&gt;
&lt;br /&gt;
=='''V4 – Time Stamp Internationalization'''==&lt;br /&gt;
*Support ISO 8601 Format&lt;br /&gt;
**Year-month-date-hours-minutes-seconds-fractional seconds&lt;br /&gt;
**Country specific time stamps&lt;br /&gt;
*Support Locale Settings for conversions&lt;br /&gt;
**,02 as 2 hundreds of a second&lt;br /&gt;
&lt;br /&gt;
=='''V???? – Avccess Security Upgrades'''==&lt;br /&gt;
*Kerberos style authentication&lt;br /&gt;
*User specific CA client resource consumption quotas in access security system&lt;br /&gt;
*Confirmation requested hint (no mods w/o poping an are-you-sure dialog box)&lt;/div&gt;</summary>
		<author><name>JeffHill</name></author>
	</entry>
	<entry>
		<id>https://wiki-ext.aps.anl.gov/epics/index.php?title=Evolution_of_EPICS_Core&amp;diff=75</id>
		<title>Evolution of EPICS Core</title>
		<link rel="alternate" type="text/html" href="https://wiki-ext.aps.anl.gov/epics/index.php?title=Evolution_of_EPICS_Core&amp;diff=75"/>
		<updated>2005-05-10T23:25:50Z</updated>

		<summary type="html">&lt;p&gt;JeffHill: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== '''V4 – Executive Summary''' ==&lt;br /&gt;
*Provide online add/delete of I/O to support continuous operation.&lt;br /&gt;
*Provide redundant control of remote I/O to support improved reliability.&lt;br /&gt;
*Provide name introspection and domain control in support of seamless *integration of large control systems&lt;br /&gt;
*Provide triggers, filters, and rate limits to improve resource use of network and client side processing&lt;br /&gt;
*Provide hierarchical devices to support higher level view of application in the front-end processors.&lt;br /&gt;
*Provide automatic backup and restore to support bump-less reboot and synchronization of redundant controllers.&lt;br /&gt;
*Provide atomic read, write, and write with read-back to multiple channels to support synchronized access of arbitrary sets of channels.&lt;br /&gt;
*Support international users with uni-code and time.&lt;br /&gt;
*Remove limitations on string lengths, device states, number of input links to support arbitrary sizes.&lt;br /&gt;
*Internationalize Time Stamps&lt;br /&gt;
&lt;br /&gt;
== '''V4 – Structure and Array Support''' ==&lt;br /&gt;
*Allows definition and access to complex devices and multi-dimensional arrays&lt;br /&gt;
*Name hierarchy in Channel Access&lt;br /&gt;
**&amp;lt;arbitrary string&amp;gt;.structure. Element[n]&lt;br /&gt;
**e.g. Arc3PwrSupply.readback.status, ArcPwrSupply.readback.value&lt;br /&gt;
*Device description in database&lt;br /&gt;
*Support arbitrary number of inputs to calculations and subroutines.&lt;br /&gt;
*Support multi-state devices of an arbitrary number of states&lt;br /&gt;
&lt;br /&gt;
== '''V4 – Data Acquisition Capabilities''' ==&lt;br /&gt;
*New subscription parameters&lt;br /&gt;
**Rate limit&lt;br /&gt;
**Value changes (as before but also % change)&lt;br /&gt;
**Triggers&lt;br /&gt;
**Filters&lt;br /&gt;
**Examples&lt;br /&gt;
**Send BPM at 1 Hz (where 1 Hz across IOCs is the same)&lt;br /&gt;
**Send BPM when trigger specifies that this pulse is e-&lt;br /&gt;
**Send RF reading when filter says that vacuum is higher than 10e-6 torr&lt;br /&gt;
*Allows more accurate requests for data on client applications &lt;br /&gt;
*Reduces the amount of network and client CPU usage&lt;br /&gt;
*Specify priority for circuit - QOS&lt;br /&gt;
&lt;br /&gt;
== '''V4 – Device Read/Write Operations''' ==&lt;br /&gt;
*Allows multiple fields to be read/written as an atomic operation &lt;br /&gt;
*Reads/Writes can be triggered&lt;br /&gt;
**e.g. Put( Corr1.K, Corr2.K, Corr3.K, on trigger event)&lt;br /&gt;
**All puts take place when the trigger event occurs&lt;br /&gt;
*Write with return data support (Command/Response)&lt;br /&gt;
*Ramping/arb function outputs – given two end points&lt;br /&gt;
&lt;br /&gt;
== '''V4 – Name Resolution Extensions''' ==&lt;br /&gt;
*Allow wildcard searches &lt;br /&gt;
*Allow request to send all names supported in the IOC&lt;br /&gt;
*Support redundancy by allowing connections to specify that they are not active&lt;br /&gt;
*Support multiple name servers by allowing connections to specify how close to the source they are.&lt;br /&gt;
*Name aliasing supported.&lt;br /&gt;
&lt;br /&gt;
== '''V4 – Online Add / Delete''' ==&lt;br /&gt;
*Support hardware address change during operation &lt;br /&gt;
*Allow new record instances to be loaded at any time&lt;br /&gt;
*Support addition of hardware of an already supported type (64x)&lt;br /&gt;
*Support addition of new hardware during operation.&lt;br /&gt;
*Remove records during operation.&lt;br /&gt;
&lt;br /&gt;
== '''V4 – Redundancy: Multiple masters of remote I/O''' ==&lt;br /&gt;
*Support name responses from multiple controllers of the same database.&lt;br /&gt;
*Support request for all fields from a primary database to its backup.&lt;br /&gt;
*Support a request for all fields that have changed since the last synchronization of the backup to the primary.&lt;br /&gt;
*Support a mechanism for switching from the primary to the backup.&lt;br /&gt;
*Provide a mechanism for synchronizing primary and the backup.&lt;br /&gt;
*Support multiple communication paths that provide&lt;br /&gt;
**an isolated network for synchronization traffic&lt;br /&gt;
**redundant checks to synchronize switch over behavior.&lt;br /&gt;
*Provide a mechanism to start/stop scanning&lt;br /&gt;
*Provide a mechanism to start/stop sequences&lt;br /&gt;
*Provide a mechanism to start/stop drivers from scanning&lt;br /&gt;
&lt;br /&gt;
== '''V4 – Support Large / Multi-segmented Control System''' ==&lt;br /&gt;
*Support load balancing between multiple data sources (1st order gateway, 2nd order gateway, IOC, and load).&lt;br /&gt;
*Support domain control independent of network topology&lt;br /&gt;
**Beamline data is not available to the control room&lt;br /&gt;
**Only insertion gap and beam quality information is available to the beamline controls from the ring control room.&lt;br /&gt;
&lt;br /&gt;
=='''V4 – Extendable Metadata / Properties''' ==&lt;br /&gt;
*Metadata can be extendable –&lt;br /&gt;
**Add array dimensions&lt;br /&gt;
**Add time base to an array&lt;br /&gt;
**Application programmers can add metadata&lt;br /&gt;
*Specify metadata by field rather than record&lt;br /&gt;
**Only get metadata when it is meaningful&lt;br /&gt;
**No display limits for the high display limit&lt;br /&gt;
*Calc and subroutine records have arrays of inputs&lt;br /&gt;
**No limit to the number of variables&lt;br /&gt;
&lt;br /&gt;
=='''V4 – Channel Access Diagnostics'''==&lt;br /&gt;
*Server Diagnostics&lt;br /&gt;
**Connections&lt;br /&gt;
**Channels&lt;br /&gt;
**Events per second&lt;br /&gt;
**State of Health&lt;br /&gt;
**Beacon Periodicity&lt;br /&gt;
**Etc…&lt;br /&gt;
*Client Diagnostics&lt;br /&gt;
**Number of connections/server per client&lt;br /&gt;
**Number of channels&lt;br /&gt;
**Events per second&lt;br /&gt;
**State of connection&lt;br /&gt;
**Etc…..&lt;br /&gt;
&lt;br /&gt;
=='''V4 – Limitations Remediation'''==&lt;br /&gt;
*Multi-line text &lt;br /&gt;
*Variable length strings&lt;br /&gt;
**Removes current limitations of 40 characters&lt;br /&gt;
**Reduces size of memory use in most cases&lt;br /&gt;
**Reduces network traffic in most cases&lt;br /&gt;
*Unicode&lt;br /&gt;
**Support alternate character sets&lt;br /&gt;
*Multidimensional arrays&lt;br /&gt;
*Variable size arrays&lt;br /&gt;
&lt;br /&gt;
=='''V4 – Time Stamp Internationalization'''==&lt;br /&gt;
*Support ISO 8601 Format&lt;br /&gt;
**Year-month-date-hours-minutes-seconds-fractional seconds&lt;br /&gt;
**Country specific time stamps&lt;br /&gt;
*Support Locale Settings for conversions&lt;br /&gt;
**,02 as 2 hundreds of a second&lt;br /&gt;
&lt;br /&gt;
=='''V???? – Resource Consumption Quotas'''==&lt;br /&gt;
*User specific CA client resource consumption quotas in access security system&lt;/div&gt;</summary>
		<author><name>JeffHill</name></author>
	</entry>
</feed>