merge branch release/4.0

This commit is contained in:
Marty Kraimer
2014-12-04 09:22:25 -05:00
13 changed files with 146 additions and 124 deletions

View File

@ -1,3 +1,9 @@
bba6a2491bdf73681cef01caf0bd89c87d7989cd 0.9.1
abdc90bf52a0c31e24e2f9a079ef72350ee31686 before_merge_changesAfter3_0_2
395f48d5196dde5bf7f24a1849aee3f8d92e91b8 3.1.0
e2e041fa7d04a37836a4343589077001588ae031 4.0.0
e2e041fa7d04a37836a4343589077001588ae031 4.0.0
42dbe8a17f851861a16be7d426ef1206324aa197 4.0.0
42dbe8a17f851861a16be7d426ef1206324aa197 4.0.0
85d46a2614f925ccb423d6abd5dfe20d42fb5099 4.0.0
541b0a7a645c63d136e397994ed0ab7178cf02cf 4.0.1

View File

@ -2,7 +2,7 @@
Copyright (c) 2008 Martin R. Kraimer
Copyright (c) 2006 The University of Chicago, as Operator of Argonne
National Laboratory.
Copyright (c) 2006 Deutsches Elektronen-Synchroton,
Copyright (c) 2006 Deutsches Elektronen-Synchrotron,
Member of the Helmholtz Association, (DESY), HAMBURG, GERMANY.
Copyright (c) 2007 Control System Laboratory,
(COSYLAB) Ljubljana Slovenia

View File

@ -35,5 +35,5 @@
INSTALL_INCLUDE = $(INSTALL_LOCATION)/include/pv
USR_INCLUDES += -I $(INSTALL_LOCATION)/include
-include $(TOP)/../../CONFIG_SITE.local
-include $(TOP)/../configure/CONFIG_SITE.local
-include $(TOP)/../../CONFIG.local

View File

@ -23,5 +23,5 @@
INSTALL_INCLUDE = $(INSTALL_LOCATION)/include/pv
USR_INCLUDES += -I $(INSTALL_LOCATION)/include
-include $(TOP)/../CONFIG.local
-include $(TOP)/../CONFIG_SITE.local
-include $(TOP)/configure/CONFIG_SITE.local

View File

@ -1,8 +1,13 @@
<h1>TODO</h1>
<h2>recordList</h2>
<p>This is putGet support that provides a list of all the records in an IOC.
Since pvAccess implements pvlist this is no longer needed.
Remove it from pvDatabaseCPP and pvIOCCPP.
Also remove channelList from swtshell.</p>
<h2>monitorPlugin</h2>
<p>A debate is on-going about what semantics should be.</p>
<h2>Must test record delete.</h2>
<p>Must test removing a record from the PVDatabase while a pvAccess client
is attached. Also why do both unlisten and detach exists?</p>
<h2>create more regresion tests</h2>
<h2>create more regression tests</h2>
<p>Currently only some simple tests exist. Most of the testing has been via the examples</p>

View File

@ -1,6 +1,15 @@
TODO
===========
recordList
----------
This is putGet support that provides a list of all the records in an IOC.
Since pvAccess implements pvlist this is no longer needed.
Remove it from pvDatabaseCPP and pvIOCCPP.
Also remove channelList from swtshell.
monitorPlugin
-------------
@ -13,7 +22,7 @@ Must test removing a record from the PVDatabase while a pvAccess client
is attached. Also why do both unlisten and detach exists?
create more regresion tests
create more regression tests
----------------
Currently only some simple tests exist. Most of the testing has been via the examples

View File

@ -38,7 +38,7 @@
<h1>pvDatabaseCPP</h1>
<!-- Maturity: Working Draft or Request for Comments, or Recommendation, and date. -->
<h2 class="nocount">EPICS v4 Working Group, Working Draft, 11-August-2014</h2>
<h2 class="nocount">EPICS v4 Working Group, Working Draft, 09-Oct-2014</h2>
<dl>
<dt>Latest version:</dt>
<dd><a
@ -63,11 +63,11 @@ href="http://epics-pvdata.sourceforge.net/LICENSE.html">EPICS open source licens
<h2 class="nocount">Abstract</h2>
<p>This document describes pvDatabaseCPP,
which is a framework for implementing a network accessable database of smart memory resident
which is a framework for implementing a network accessible database of smart memory resident
records. Network access is via pvAccess. The data in each record is a top level PVStructure as defined by
pvData. The framework includes a complete implementation of ChannelProvider as defined by pvAccess.
The framework can be extended in order to create record instances that implements services.
The minimum that an extenson must provide is a top level PVStructure and a process method.
The minimum that an extension must provide is a top level PVStructure and a process method.
</p>
<p>EPICS version 4 is a set of related products in the EPICS
@ -78,9 +78,9 @@ V4 control system programming environment:<br />
<h2 class="nocount">Status of this Document</h2>
<p>This is the 11-August-2014 version of of pvDatabaseCPP.</p>
</p>
<p>This is the 09-Oct-2014 version of of pvDatabaseCPP.</p>
<p>This version is a complete implementation of what is described in this manual.
</p>
</div>
<div id="toc">
@ -92,7 +92,7 @@ V4 control system programming environment:<br />
<h2>Introduction</h2>
<h3>Overview</h3>
<p>The main purpose of this project to make it easier to implement services that are accessed via pvAccess.
This project supplies is a complete implementation of the server side of pvAccess.
This project supplies a complete implementation of the server side of pvAccess.
All that a service has to provide is a top level PVStructure and a process method.
A service can be run as a main process or can be part of a V3 IOC.
Thus services can be developed that interact with V3 records, asynDriver,
@ -109,25 +109,25 @@ The local provider provides access to the records in the pvDatabase.
This local provider is accessed by the remote pvAccess server.
A record is smart because code can be attached to a record, which is accessed via a method named process.</p>
<p>This document describes components that provide the following features:
<p>This document describes components that provide the following features:</p>
<dl>
<dt>database<dt>
<dt>database</dt>
<dd>This encapsulates the concept of a database of memory resident smart records.
The two main components are:
<dl>
<dt>pvRecord</dt>
<dd>This encapsulates the concept of a smart record. It can be processed.
Changes to field values can be trapped. A record can be locked.</dd>
<dt>pvDatabase<dt>
<dt>pvDatabase</dt>
<dd>This is a database of pvRecords.
Records can be added and removed from a database.</dd>
</dl>
</dd>
<dt>pvAccess</dt>
<dd>This is a complete implementation of ChannelProvider and Channel
as defined by pvAccess.
It is used by the server side of pvAccess to attach to pvRecords.
This component also provides a C++ implementation
of the monitor and pvCopy components from pvIOCJava</dd>
</dd>
<dt>Main and V3IOC</dt>
<dd>The pvDatabase can be provided via a Main program or can be part
of a V3IOC. In the later case the IOC has both a database of V3 Records
@ -153,7 +153,7 @@ href="./html/index.html">doxygenDoc</a></p>
<p>The first step is to build pvDatabaseCPP as described in the next section.</p>
<p>One of the examples is exampleServer.
It can be started either via a main program or as part of a V3 IOC.
<p>
</p>
<p>To start it as a main program do the following:</p>
<pre>
mrk&gt; pwd
@ -251,7 +251,7 @@ arrays. It is also described in a later section.</p>
to learn how to implement a service.</p>
<h3>Relationship with pvIOCJava.</h3>
<p>This document descibes a C++ implementation of some of the components in pvIOCJava,
<p>This document describes a C++ implementation of some of the components in pvIOCJava,
which also implements a pvDatabase.
PVDatabaseCPP implements the core components required to create a network accessible database of smart
memory resident records.
@ -266,17 +266,17 @@ Until a need is demonstrated this will remain true.
The main user of a pvDatabase is pvAccess, and in particular, remote pvAccess.
The server side of remote pvAccess creates two threads for each client and always accesses
a record via these threads.
It is expected that these threads will be sufficient to efficently handle all channel methods except
It is expected that these threads will be sufficient to efficiently handle all channel methods except
channelRPC. For channelRPC pvAccess provides (or will provide) a thread pool for channelRPC requests.
If, in the future, a scanning facility is provided by pvDatabaseCPP or some other facility,
then the scanning facility will have to provide some way of handling process requests that block.</p>
</p>
<h3>Phased Development</h3>
<p>This documentation describes the first phase of a phased implementation of pvDatabaseCPP:</pp>
<p>This documentation describes the first phase of a phased implementation
of pvDatabaseCPP:</p>
<dl>
<dt>pvRecord</d>
<dt>pvRecord</dt>
<dd>Wrapper on PVStructure that implements methods required by Local Channel Provider.</dd>
<dt>pvDatabase</d>
<dt>pvDatabase</dt>
<dd>Database of PVRecords. Has methods find, add, and remove.</dd>
<dt>Local Channel Provider</dt>
<dd>Complete implementation of ChannelProvider and Channel.
@ -294,10 +294,11 @@ then the scanning facility will have to provide some way of handling process req
<dd>Add the ability to optionally add support to fields.
In addition some of the basic support defined in pvIOCJava could also be implemented.</dd>
<dt>XML parser</dt>
<dd>This provides the ability to create record instances without writing any code.</dd>
<dd>This provides the ability to create record instances without
writing any code.</dd>
</dl>
<p>The completion of each phase provides useful features that can be used without waiting for the
completion of later phases.
<p>The completion of each phase provides useful features that can be used
without waiting for the completion of later phases.
The rest of this document discusses only the first phase.</p>
<h3>Features Required for localChannelProvider</h3>
<dl>
@ -314,16 +315,19 @@ The rest of this document discusses only the first phase.</p>
<dt>The localChannelProvider itself</dt>
<dd>This is the C++ implementation of package pvAccess in pvIOCJava.
The localChannelProvider accesses data from PVRecords.
It implements all channel methods except channelRPC, which is implemented by pvAccessCPP.</dd>
It implements all channel methods except channelRPC,
which is implemented by pvAccessCPP.
</dd>
</dl>
<h3>Minumum Features Required for pvRecord</h3>
<h3>Minimum Features Required for pvRecord</h3>
<p>The first phase will only implement record processing, i. e.
the process method has to do everything itself without any generic field support.
This will be sufficient for implementing many services.
The following are the minimium features required</p>
The following are the minimum features required</p>
<dl>
<dt>PVDatabase</dt>
<dd>This holds a set of PVRecords. It has methods to find, add, and remove records.</dd>
<dd>This holds a set of PVRecords.
It has methods to find, add, and remove records.</dd>
<dt>PVRecord</dt>
<dd>This, and a set of related interfaces, provides the following:
<dl>
@ -331,9 +335,11 @@ The following are the minimium features required</p>
<dd>PVRecord is a wrapper on a top level pvStructure.</dd>
<dt>Record locking</dt>
<dd>A record can be locked and unlocked.
A record must be locked whenever data in the pvStructure is accessed.</dd>
A record must be locked whenever data in the pvStructure is accessed.
</dd>
<dt>Trapping data changes</dt>
<dd>A client can request to be notified when data in the pvStructure is modified.
<dd>A client can request to be notified when data in the pvStructure
is modified.
It can do this on a field by field basis.</dd>
</dl>
</dd>
@ -421,11 +427,11 @@ of how an application can make the shell commands available.
<dt>stopPVAClient</dt>
<dd>Stops pvAccess.</dd>
<dt>startPVAServer</dt>
<dd>Starts the local channel provider</p>
<dd>Starts the local channel provider</dd>
<dt>stopPVAServer</dt>
<dd>Stop the local channel provider</dd>
</dl>
</p>
<h3>Commands implemented by pvDatabaseCPP</h3>
<p>The following iocsh commands are provided for a V3IOC:</p>
<dl>
@ -433,16 +439,16 @@ of how an application can make the shell commands available.
<dd>Provides a list of all the pvRecords in database <b>master</b>
</dd>
</dl>
<p>In addition any code that implements a PVRecord must implement an ioc command.</p>
<p>Look at any of the examples to see how to implement shell commands.</p>
<p>In addition any code that implements a PVRecord must implement an ioc command.
Look at any of the examples to see how to implement shell commands.</p>
<h3>Commands implemented by pvaSrv</h3>
<p><b>pvaSrv</b> provides a pvAccess server that provides access to iocCore records.</p>
<p>pvaSrv does not provide any shell commands but it can be part of an IOC.
Just make sure your application configures pvaSrv and then include the following file:
</p>
<pre>
include "dbPv.dbd"
</pre>
</p>
<h2>database</h2>
<h3>src/database</h3>
@ -501,7 +507,7 @@ It describes the following classes:</p>
<dd>These wrap PVField and PVStructure so that pvCopy and monitor
can be implemented.</dd>
<dt>PVRecordClient</dt>
<dd>This is called by anything that acceses PVRecord.</dd>
<dd>This is called by anything that accesses PVRecord.</dd>
<dt>PVListener</dt>
<dd>This is implemented by anything that wants to trap calls to PVRecord::message.</dd>
<dt>PVDatabase</dt>
@ -530,15 +536,12 @@ typedef std::tr1::shared_ptr&lt;PVRecordClient&gt; PVRecordClientPtr;
class PVListener;
typedef std::tr1::shared_ptr&lt;PVListener&gt; PVListenerPtr;
class RecordPutRequester;
typedef std::tr1::shared_ptr&lt;RecordPutRequester&gt; RecordPutRequesterPtr;
class PVDatabase;
typedef std::tr1::shared_ptr&lt;PVDatabase&gt; PVDatabasePtr;
</pre>
<h3>class PVRecord</h3>
<p>NOTES:
<p>NOTES:</p>
<ul>
<li>This section uses the name record instead of "an instance of PVRecord".</li>
<li>Most clients will access a record via the local channel provider,
@ -549,17 +552,17 @@ typedef std::tr1::shared_ptr&lt;PVDatabase&gt; PVDatabasePtr;
Most of the methods are used by the pvAccess code.
Service implementers will mostly be interested in methods init and process.
These are described first.
</li>
</ul>
<hr>PVRecord Methods</h4>
<h4>PVRecord Methods</h4>
<pre>
class PVRecord
public epics::pvData::Requester,
public std::tr1::enable_shared_from_this&lt;PVRecord&gt;
{
public:
POINTER_DEFINITIONS(PVRecord);
virtual bool init() {initPVRecord(); return true;}
virtual bool init() ;
virtual void start() {}
virtual void process() {}
virtual void destroy();
@ -645,7 +648,7 @@ private:
must have the record locked.</dd>
<dt>tryLock</dt>
<dd>If true then just like lock.
If falseclient can not access record.
If false client can not access record.
A client can try to simultaneously hold the lock for more than two records
by calling this method. But must be willing to accept failure.
</dd>
@ -801,6 +804,7 @@ that holds the data. It has the following methods:
<dt>postPut</dt>
<dd>This is called by the code that implements the data interface.
It is called whenever the put method is called.</dd>
</dl>
<h3>class PVRecordClient</h3>
<pre>
class PVRecordClient {
@ -816,7 +820,6 @@ class PVRecordClient {
<dt>detach</dt>
<dd>The record is being removed from the master database,</dd>
</dl>
</dl>
<h3>class PVListener</h3>
<pre>
class PVListener {
@ -866,7 +869,6 @@ public:
bool addRecord(PVRecordPtr const &amp; record);
epics::pvData::PVStringArrayPtr getRecordNames();
bool removeRecord(PVRecordPtr const &amp; record);
virtual std::string getRequesterName();
private:
PVDatabase();
};
@ -890,8 +892,6 @@ private:
<dt>removeRecord</dt>
<dd>Remove a record from the database.
If the record was not in the database false is returned.</dd>
<dt>getRequesterName</dt>
<dd>Virtual method of Requester</dd>
</dl>
<h2>pvAccess</h2>
<p>This is code that provides an implementation of channelProvider as
@ -919,7 +919,7 @@ is implemented.</p>
<p>This is the code that implements monitors on changes to fields of a PVRecord.
Because it is called by pvAccess client (monitor methods) and by
PVRecord (when postPut is called), it must be careful to prevent deadlocks.
The implementation is via class MonitorLocal (implmented in monitorFactory.cpp)
The implementation is via class MonitorLocal (implemented in monitorFactory.cpp)
and PVCopyMonitor.
MonitorLocal is the interface between pvAccess and PVCopyMonitor.
PVCopyMonitor is the interface between MonitorLocal and PVRecord.
@ -930,7 +930,7 @@ While monitoring is active PVCopyMonitor updates the active monitor element when
a postPut is issued to any field being monitored.
</p>
<p>The following two sections provide a few more details about MonitorLocal
and PVCopyMonitor.<p>
and PVCopyMonitor.</p>
<h4>MonitorLocal</h4>
<p>MonitorLocal implements the following abstract base classes:</p>
<dl>
@ -980,7 +980,7 @@ MonitorLocal manages the following:
With a lock held it clears the monitorElement queue
and allocates an active element.
With no lock held calls pvCopyMonitor-&gt;startMonitoring(activeElement)
<dd>
</dd>
<dt>stop</dt>
<dd>
Called by client.
@ -1028,7 +1028,7 @@ active element but never modifies the pvStructure.
<dl>
<dt>startMonitoring</dt>
<dd>With no lock held it sets its monitorElement to the
startElement pased by monitorLocal and calls pvRecord-&gt;addListener(getPtrSelf()).
startElement passed by monitorLocal and calls pvRecord-&gt;addListener(getPtrSelf()).
It locks the pvRecord.
It calls calls addListener for every field in the record that is being
monitored.
@ -1074,7 +1074,7 @@ and one that is used for testing.</p>
<h3>traceRecord</h3>
<p>This implements a PVRecord that allows a client to set
the trace level of a record. It follows the pattern of a channelPutGet
record:
record:</p>
<pre>
traceRecord
structure argument
@ -1096,7 +1096,7 @@ where:
<dd>Lifecycle messages will be generated.
This all channel create and destroy instances will be shown.</dd>
<dt>2</dt>
<dd>In addition to lifecycle messages a message will be generted
<dd>In addition to lifecycle messages a message will be generated
for each get and put request.</dd>
<dt>&gt;2</dt>
<dd>Currently no definition</dd>
@ -1105,7 +1105,7 @@ where:
<dt>result</dt>
<dd>The result of a cannelPutGet request</dd>
</dl>
<p>testExampleServerMain.cpp has an example of how to create a traceRecord:
<p>testExampleServerMain.cpp has an example of how to create a traceRecord:</p>
<pre>
PVDatabasePtr master = PVDatabase::getMaster();
PVRecordPtr pvRecord;
@ -1116,12 +1116,12 @@ pvRecord = TraceRecord::create(recordName);
result = master-&gt;addRecord(pvRecord);
if(!result) cout&lt;&lt; "record " &lt;&lt; recordName &lt;&lt; " not added" &lt;&lt; endl;
</pre>
</p>
<h3>recordList</h3>
<p>This implements a PVRecord that allows a client to
get the names of all the PVRecords in the PVDatabase.
It follows the pattern of a channelPutGet
record:
</p>
<pre>
traceRecord
structure argument
@ -1134,7 +1134,7 @@ traceRecord
where:
<dl>
<dt>database</dt>
<dd>The name of the datbase. The default is "master"</dd>
<dd>The name of the database. The default is "master"</dd>
<dt>regularExpression</dt>
<dd>For now this is ignored and the complete list of names is always
returned.</dd>
@ -1148,17 +1148,18 @@ requires that a record of this type is present and calls it.
Thus user code does not have to use a channelGetPut to get the list
of record names.</p>
<p>testExampleServerMain.cpp has an example of how to create a traceRecord:
</p>
<pre>
recordName = "recordListPGRPC";
pvRecord = RecordListRecord::create(recordName);
result = master-&gt;addRecord(pvRecord);
if(!result) cout&lt;&lt; "record " &lt;&lt; recordName &lt;&lt; " not added" &lt;&lt; endl;
</pre>
</p>
<h2>exampleServer</h2>
<h3>Overview</h3>
<p>The example implements a simple service that has a top level pvStructure:
</p>
<pre>
structure
structure argument
@ -1234,9 +1235,10 @@ where
<dt>exampleServerRegister.cpp</dt>
<dd>This has the code to start the service via the following iocsh
command.
</dd>
<dt>exampleServerRegister.dbd</dt>
<dd>This is the file that is used to create the shell command
exampleServerCreateRecord.</dd>
exampleServerCreateRecord.
<pre>
exampleServerCreateRecord exampleServer
</pre>
@ -1271,7 +1273,7 @@ separate from where the iocs are build.</p>
<p>The example resides in src
The implementation is in exampleServer.cpp.
</p>
</p>The description consists of</p>
<p>The description consists of</p>
<pre>
class ExampleServer;
typedef std::tr1::shared_ptr&lt;ExampleServer&gt; ExampleServerPtr;
@ -1299,30 +1301,31 @@ private:
</pre>
<p>where</p>
<dl>
<dt>create<dt>
<dt>create</dt>
<dd>This is example specific but each support could provide
a similar static method.
</dd>
<dt>~ExampleServer<dt>
<dt>~ExampleServer</dt>
<dd>The destructor must be declared virtual.</dd>
<dt>destroy</dt>
<dd>Called when the record is being destroyed.
This must call the base class destroy method.
<dt>init<dt>
</dd>
<dt>init</dt>
<dd>A method to initialize the support. It returns true
if initialization is successful and false if not.
NOTE that this is a virtual method of PVRecord itself.</dd>
<dt>process<dt>
<dt>process</dt>
<dd>
This again is a virtual method of PVRecord.
</dd>
<dt>ExampleServer<dt>
<dt>ExampleServer</dt>
<dd>For the example this is private.</dd>
<dt>pvValue</dt>
<dd>This is the field of the top level structure that process
accesses.
</dd>
<dl>
</dl>
<p>The implementation of create method is:</p>
<pre>
ExampleServerPtr ExampleServer::create(
@ -1423,16 +1426,16 @@ int main(int argc,char *argv[])
if(!result) cout&lt;&lt; "record " &lt;&lt; recordName &lt;&lt; " not added" &lt;&lt; endl;
recordName = "traceRecordPGRPC";
pvRecord = TraceRecord::create(recordName);
result = master-&gtr;addRecord(pvRecord);
result = master-&gt;addRecord(pvRecord);
if(!result) cout&lt;&lt; "record " &lt;&lt; recordName &lt;&lt; " not added" &lt;&lt; endl;
recordName = "recordListPGRPC";
pvRecord = RecordListRecord::create(recordName);
result = master-&gtr;addRecord(pvRecord);
result = master-&gt;addRecord(pvRecord);
if(!result) cout&lt;&lt; "record " &lt;&lt; recordName &lt;&lt; " not added" &lt;&lt; endl;
ServerContext::shared_pointer pvaServer =
startPVAServer(PVACCESS_ALL_PROVIDERS,0,true,true);
PVStringArrayPtr pvNames = master-&gtr;getRecordNames();
shared_vector&lt;const string&gtr; names = pvNames-&gtr;view();
PVStringArrayPtr pvNames = master-&gt;getRecordNames();
shared_vector&lt;const string&gt; names = pvNames-&gt;view();
for(size_t i=0; i&lt;names.size(); ++i) cout &lt;&lt; names[i] &lt;&lt; endl;
string str;
while(true) {
@ -1452,13 +1455,13 @@ This:
<li>Runs forever until the user types exit on standard in.</li>
</ul>
<h3>V3IOC exampleServer</h3>
<p>To start exampleServer as part of a V3IOC:
<p>To start exampleServer as part of a V3IOC:</p>
<pre>
mrk&gt; pwd
/home/hg/pvDatabaseCPP/exampleServer/iocBoot/exampleServer
mrk&gt; ../../../bin/linux-x86_64/exampleServer st.cmd
</pre></p>
<p>You can then issue the commands dbl and pvdbl:
</pre>
<p>You can then issue the commands dbl and pvdbl:</p>
<pre>
epics&gt; dbl
pvdouble
@ -1472,7 +1475,6 @@ epics&gt;
</pre>
dbl shows the V3 records.
pvdbl shows the pvRecords.
</p>
<p>
It starts pvaSrv so that the V3 records can be accessed via Channel Access
or via PVAccess.</p>
@ -1516,7 +1518,6 @@ and 2) gives a brief description of an example that gets data for an array of do
If access is via pvAccess then locking is handled by pvAccess.</dd>
</dl>
<p>Access via pvAccess can be done either by local or remote channel provider.</p>
</dl>
<dl>
<dt>Access via channelProviderLocal</dt>
<dd>
@ -1538,7 +1539,7 @@ and 2) gives a brief description of an example that gets data for an array of do
</dl>
<h4>Data synchronization</h4>
<p>If pvAccess is used then it handles data synchronization.
This is done by making a copy of the data that is transfered between the two pvRecords.
This is done by making a copy of the data that is transferred between the two pvRecords.
This is true if either remote or local pvAccess is used.
Each get, put, etc request results in data being copied between the two records.</p>
<p>
@ -1558,7 +1559,8 @@ i. e. a main program, or can be part of a V3IOC.</p>
ClientFactory::start();
ChannelProviderLocalPtr channelProvider = getChannelProviderLocal();
...
ServerContext::shared_pointer serverContext = startPVAServer(PVACCESS_ALL_PROVIDERS,0,true,true);
ServerContext::shared_pointer serverContext =
startPVAServer(PVACCESS_ALL_PROVIDERS,0,true,true);
</pre>
<p>The first call is only necessary if some of the pvRecords
have pvAccess links.
@ -1614,7 +1616,7 @@ exampleLink is a record that, when processed, gets the value from doubleArray an
to the value read.
st.local has both records.
st.remote has only one record named exampleLinkRemote.
<p>
</p>
<p>To start the example:</p>
<pre>
mrk&gt; pwd
@ -1781,7 +1783,7 @@ or some other memory check program.
<dt>arrayPerformanceMain</dt>
<dd>This is server and also a configurable number of longArrayMonitor clients.
The clients can use either the local or
remote providers. The moitor code is the same code that is used by longArrayMonitorMain.
remote providers. The monitor code is the same code that is used by longArrayMonitorMain.
</dd>
<dt>longArrayMonitorMain</dt>
<dd>Remote client that monitors the array served by arrayPerformanceMain.</dd>
@ -1789,7 +1791,7 @@ or some other memory check program.
<dd>Remote client that uses channelGet to access the array served by arrayPerformanceMain.</dd>
<dt>longArrayPutMain</dt>
<dd>Remote client that uses channelPut to access the array served by arrayPerformanceMain.</dd>
<dl>
</dl>
<p>Each has support for <b>-help</b>.</p>
<pre>
mrk&gt; pwd
@ -1797,7 +1799,7 @@ mrk&gt; pwd
mrk&gt; bin/linux-x86_64/arrayPerformanceMain -help
arrayPerformanceMain recordName size delay providerName nMonitor queueSize waitTime
default
arrayPerformance arrayPerformance 10000000 0.0001 local 1 2 0.0
arrayPerformanceMain arrayPerformance 10000000 0.0001 local 1 2 0.0
mrk&gt; bin/linux-x86_64/longArrayMonitorMain -help
longArrayMonitorMain channelName queueSize waitTime
@ -1817,7 +1819,7 @@ longArrayPutMain arrayPerformance 10 0 0 1
mrk&gt;
</pre>
<h3>Example output</h3>
<p><b>Note:</b> These may fail if run on a platform that does not have sufficent memory,</p>
<p><b>Note:</b> These may fail if run on a platform that does not have sufficient memory,</p>
<p>To see an example just execute the following commands in four different terminal windows:</p>
<pre>
bin/linux/&lt;arch&gt;/arrayPerformanceMain
@ -1825,8 +1827,8 @@ bin/linux/&lt;arch&gt;/longArrayMonitorMain
bin/linux/&lt;arch&gt;/longArrayGetMain
bin/linux/&lt;arch&gt;/longArrayPutMain
</pre>
<p>Each program generates a report every second when it has somthing to report.
Examples are:
<p>Each program generates a report every second when it has something to report.
Examples are:</p>
<pre>
mrk&gt; bin/linux-x86_64/arrayPerformanceMain
arrayPerformance arrayPerformance 10000000 0.0001 local 1 2 0
@ -1889,13 +1891,14 @@ get kiloElements/sec 8726.34
</dl>
<p>
arrayPerformance creates a PVRecord that has the structure:.
</p>
<pre>
recordName
long[] value
timeStamp timeStamp
alarm alarm
</pre>
Thus it holds an array of 64 bit integers.</p>
Thus it holds an array of 64 bit integers.
<p>The record has support that consists of a separate thread that runs
until the record is destroyed executing the following algorithm:</p>
<dl>
@ -1906,7 +1909,7 @@ until the record is destroyed executing the following algorithm:</p>
</dd>
<dt>create array</dt>
<dd>A new shared_vector is created and each element is set equal
to the interation count.</dd>
to the iteration count.</dd>
<dt>lock</dt>
<dd>The arrayPerformance record is locked.</dd>
<dt>Begin group put</dt>
@ -1927,7 +1930,7 @@ until the record is destroyed executing the following algorithm:</p>
<h3>longArrayMonitor</h3>
<p>This is a pvAccess client that monitors an arrayPerformance record.
It generates a report every second showing how many elements has received.
For every monitor it also checks that the number of alements is &gt;0 and the
For every monitor it also checks that the number of elements is &gt;0 and the
the first element equals the last element. It reports an error if either
of these conditions is not true.</p>
<p>The arguments for longArrayMonitorMain are:</p>
@ -1958,7 +1961,7 @@ Every second it produces a report.</p>
A value of 0 means never destroy and recreate.
</dd>
<dt>delayTime</dt>
<dd>The time to dalay between gets.</dd>
<dd>The time to delay between gets.</dd>
</dl>
<h3>longArrayPut</h3>
<p>This is a pvAccess client that uses channelPut to access an arrayPerformance record.
@ -1979,14 +1982,14 @@ Every second it produces a report.</p>
A value of 0 means never destroy and recreate.
</dd>
<dt>delayTime</dt>
<dd>The time to dalay between gets.</dd>
<dd>The time to delay between gets.</dd>
</dl>
<h3>Some results</h3>
<h4>array performance</h4>
<p>The results were from my laptop.
It has a 2.2Ghz intel core i7 with 4Gbytes of memory.
The operating system is linux fedora 16.</p>
<p>The results were from my laptop in 2013
It had a 2.2Ghz intel core i7 with 4Gbytes of memory.
The operating system was linux fedora 16.</p>
<p>When test are performed with large arrays it is a good idea to also
run a system monitor facility and check memory and swap history.
If a test configuration causes physical memory to be exhausted
@ -2008,13 +2011,13 @@ connection.</p>
and is putting about 500million elements per second.
Since each element is an int64 this means about 4gigaBytes per second.
</p>
<p>When no monitors are requested and a remote longArrayMonitorMain is run:<p>
<p>When no monitors are requested and a remote longArrayMonitorMain is run:</p>
<pre>
mr&gt; pwd
/home/hg/pvDatabaseCPP-md
mrk&gt; bin/linux-x86_64/longArrayMonitorMain
</pre>
<p>The performance drops to about 25 interations per second and 250 million elements per second.
<p>The performance drops to about 25 iterations per second and 250 million elements per second.
The next section has an example that demonstrates what happens.
Note that if the array size is small enough to fit in the local cache then running longArrayMonitor
has almost no effect of arrayPerforance.
@ -2075,7 +2078,7 @@ thread1 value 10 time 1.04836 iterations/sec 4.76936 elements/sec 238.468million
thread0 value 11 time 1.01575 iterations/sec 4.92249 elements/sec 246.124million
</pre>
<p>As more threads are running the slower each thread runs.</p>
<p>But now consider a size that fits in a local cache.<p>
<p>But now consider a size that fits in a local cache.</p>
<pre>
bin/linux-x86_64/vectorPerformanceMain 5000 0.00n/linux-x86_64/vectorPerformanceMain 5000 0.00 1
...

View File

@ -63,11 +63,11 @@ href="http://epics-pvdata.sourceforge.net/LICENSE.html">EPICS open source licens
<h2 class="nocount">Abstract</h2>
<p>This document describes pvDatabaseCPP,
which is a framework for implementing a network accessable database of smart memory resident
which is a framework for implementing a network accessible database of smart memory resident
records. Network access is via pvAccess. The data in each record is a top level PVStructure as defined by
pvData. The framework includes a complete implementation of ChannelProvider as defined by pvAccess.
The framework can be extended in order to create record instances that implements services.
The minimum that an extenson must provide is a top level PVStructure and a process method.
The minimum that an extension must provide is a top level PVStructure and a process method.
</p>
<p>EPICS version 4 is a set of related products in the EPICS
@ -251,7 +251,7 @@ arrays. It is also described in a later section.</p>
to learn how to implement a service.</p>
<h3>Relationship with pvIOCJava.</h3>
<p>This document descibes a C++ implementation of some of the components in pvIOCJava,
<p>This document describes a C++ implementation of some of the components in pvIOCJava,
which also implements a pvDatabase.
PVDatabaseCPP implements the core components required to create a network accessible database of smart
memory resident records.
@ -266,7 +266,7 @@ Until a need is demonstrated this will remain true.
The main user of a pvDatabase is pvAccess, and in particular, remote pvAccess.
The server side of remote pvAccess creates two threads for each client and always accesses
a record via these threads.
It is expected that these threads will be sufficient to efficently handle all channel methods except
It is expected that these threads will be sufficient to efficiently handle all channel methods except
channelRPC. For channelRPC pvAccess provides (or will provide) a thread pool for channelRPC requests.
If, in the future, a scanning facility is provided by pvDatabaseCPP or some other facility,
then the scanning facility will have to provide some way of handling process requests that block.</p>
@ -316,11 +316,11 @@ The rest of this document discusses only the first phase.</p>
The localChannelProvider accesses data from PVRecords.
It implements all channel methods except channelRPC, which is implemented by pvAccessCPP.</dd>
</dl>
<h3>Minumum Features Required for pvRecord</h3>
<h3>Minimum Features Required for pvRecord</h3>
<p>The first phase will only implement record processing, i. e.
the process method has to do everything itself without any generic field support.
This will be sufficient for implementing many services.
The following are the minimium features required</p>
The following are the minimum features required</p>
<dl>
<dt>PVDatabase</dt>
<dd>This holds a set of PVRecords. It has methods to find, add, and remove records.</dd>
@ -501,7 +501,7 @@ It describes the following classes:</p>
<dd>These wrap PVField and PVStructure so that pvCopy and monitor
can be implemented.</dd>
<dt>PVRecordClient</dt>
<dd>This is called by anything that acceses PVRecord.</dd>
<dd>This is called by anything that accesses PVRecord.</dd>
<dt>PVListener</dt>
<dd>This is implemented by anything that wants to trap calls to PVRecord::message.</dd>
<dt>PVDatabase</dt>
@ -645,7 +645,7 @@ private:
must have the record locked.</dd>
<dt>tryLock</dt>
<dd>If true then just like lock.
If falseclient can not access record.
If false client can not access record.
A client can try to simultaneously hold the lock for more than two records
by calling this method. But must be willing to accept failure.
</dd>
@ -919,7 +919,7 @@ is implemented.</p>
<p>This is the code that implements monitors on changes to fields of a PVRecord.
Because it is called by pvAccess client (monitor methods) and by
PVRecord (when postPut is called), it must be careful to prevent deadlocks.
The implementation is via class MonitorLocal (implmented in monitorFactory.cpp)
The implementation is via class MonitorLocal (implemented in monitorFactory.cpp)
and PVCopyMonitor.
MonitorLocal is the interface between pvAccess and PVCopyMonitor.
PVCopyMonitor is the interface between MonitorLocal and PVRecord.
@ -1028,7 +1028,7 @@ active element but never modifies the pvStructure.
<dl>
<dt>startMonitoring</dt>
<dd>With no lock held it sets its monitorElement to the
startElement pased by monitorLocal and calls pvRecord-&gt;addListener(getPtrSelf()).
startElement passed by monitorLocal and calls pvRecord-&gt;addListener(getPtrSelf()).
It locks the pvRecord.
It calls calls addListener for every field in the record that is being
monitored.
@ -1096,7 +1096,7 @@ where:
<dd>Lifecycle messages will be generated.
This all channel create and destroy instances will be shown.</dd>
<dt>2</dt>
<dd>In addition to lifecycle messages a message will be generted
<dd>In addition to lifecycle messages a message will be generated
for each get and put request.</dd>
<dt>&gt;2</dt>
<dd>Currently no definition</dd>
@ -1134,7 +1134,7 @@ traceRecord
where:
<dl>
<dt>database</dt>
<dd>The name of the datbase. The default is "master"</dd>
<dd>The name of the database. The default is "master"</dd>
<dt>regularExpression</dt>
<dd>For now this is ignored and the complete list of names is always
returned.</dd>
@ -1538,7 +1538,7 @@ and 2) gives a brief description of an example that gets data for an array of do
</dl>
<h4>Data synchronization</h4>
<p>If pvAccess is used then it handles data synchronization.
This is done by making a copy of the data that is transfered between the two pvRecords.
This is done by making a copy of the data that is transferred between the two pvRecords.
This is true if either remote or local pvAccess is used.
Each get, put, etc request results in data being copied between the two records.</p>
<p>
@ -1781,7 +1781,7 @@ or some other memory check program.
<dt>arrayPerformanceMain</dt>
<dd>This is server and also a configurable number of longArrayMonitor clients.
The clients can use either the local or
remote providers. The moitor code is the same code that is used by longArrayMonitorMain.
remote providers. The monitor code is the same code that is used by longArrayMonitorMain.
</dd>
<dt>longArrayMonitorMain</dt>
<dd>Remote client that monitors the array served by arrayPerformanceMain.</dd>
@ -1817,7 +1817,7 @@ longArrayPutMain arrayPerformance 10 0 0 1
mrk&gt;
</pre>
<h3>Example output</h3>
<p><b>Note:</b> These may fail if run on a platform that does not have sufficent memory,</p>
<p><b>Note:</b> These may fail if run on a platform that does not have sufficient memory,</p>
<p>To see an example just execute the following commands in four different terminal windows:</p>
<pre>
bin/linux/&lt;arch&gt;/arrayPerformanceMain
@ -1825,7 +1825,7 @@ bin/linux/&lt;arch&gt;/longArrayMonitorMain
bin/linux/&lt;arch&gt;/longArrayGetMain
bin/linux/&lt;arch&gt;/longArrayPutMain
</pre>
<p>Each program generates a report every second when it has somthing to report.
<p>Each program generates a report every second when it has something to report.
Examples are:
<pre>
mrk&gt; bin/linux-x86_64/arrayPerformanceMain
@ -1906,7 +1906,7 @@ until the record is destroyed executing the following algorithm:</p>
</dd>
<dt>create array</dt>
<dd>A new shared_vector is created and each element is set equal
to the interation count.</dd>
to the iteration count.</dd>
<dt>lock</dt>
<dd>The arrayPerformance record is locked.</dd>
<dt>Begin group put</dt>
@ -1927,7 +1927,7 @@ until the record is destroyed executing the following algorithm:</p>
<h3>longArrayMonitor</h3>
<p>This is a pvAccess client that monitors an arrayPerformance record.
It generates a report every second showing how many elements has received.
For every monitor it also checks that the number of alements is &gt;0 and the
For every monitor it also checks that the number of elements is &gt;0 and the
the first element equals the last element. It reports an error if either
of these conditions is not true.</p>
<p>The arguments for longArrayMonitorMain are:</p>
@ -1958,7 +1958,7 @@ Every second it produces a report.</p>
A value of 0 means never destroy and recreate.
</dd>
<dt>delayTime</dt>
<dd>The time to dalay between gets.</dd>
<dd>The time to delay between gets.</dd>
</dl>
<h3>longArrayPut</h3>
<p>This is a pvAccess client that uses channelPut to access an arrayPerformance record.
@ -1979,7 +1979,7 @@ Every second it produces a report.</p>
A value of 0 means never destroy and recreate.
</dd>
<dt>delayTime</dt>
<dd>The time to dalay between gets.</dd>
<dd>The time to delay between gets.</dd>
</dl>
<h3>Some results</h3>
@ -2014,7 +2014,7 @@ mr&gt; pwd
/home/hg/pvDatabaseCPP-md
mrk&gt; bin/linux-x86_64/longArrayMonitorMain
</pre>
<p>The performance drops to about 25 interations per second and 250 million elements per second.
<p>The performance drops to about 25 iterations per second and 250 million elements per second.
The next section has an example that demonstrates what happens.
Note that if the array size is small enough to fit in the local cache then running longArrayMonitor
has almost no effect of arrayPerforance.

View File

@ -23,5 +23,5 @@ CHECK_RELEASE = WARN
INSTALL_INCLUDE = $(INSTALL_LOCATION)/include/pv
USR_INCLUDES += -I $(INSTALL_LOCATION)/include
-include $(TOP)/../../CONFIG_SITE.local
-include $(TOP)/../configure/CONFIG_SITE.local
-include $(TOP)/../../CONFIG.local

View File

@ -35,5 +35,5 @@
INSTALL_INCLUDE = $(INSTALL_LOCATION)/include/pv
USR_INCLUDES += -I $(INSTALL_LOCATION)/include
-include $(TOP)/../../CONFIG_SITE.local
-include $(TOP)/../configure/CONFIG_SITE.local
-include $(TOP)/../../CONFIG.local

View File

@ -35,5 +35,5 @@
INSTALL_INCLUDE = $(INSTALL_LOCATION)/include/pv
USR_INCLUDES += -I $(INSTALL_LOCATION)/include
-include $(TOP)/../../CONFIG_SITE.local
-include $(TOP)/../configure/CONFIG_SITE.local
-include $(TOP)/../../CONFIG.local

View File

@ -35,5 +35,5 @@
INSTALL_INCLUDE = $(INSTALL_LOCATION)/include/pv
USR_INCLUDES += -I $(INSTALL_LOCATION)/include
-include $(TOP)/../../CONFIG_SITE.local
-include $(TOP)/../configure/CONFIG_SITE.local
-include $(TOP)/../../CONFIG.local

View File

@ -35,6 +35,5 @@
INSTALL_INCLUDE = $(INSTALL_LOCATION)/include/pv
USR_INCLUDES += -I $(INSTALL_LOCATION)/include
-include $(TOP)/../../CONFIG_SITE.local
-include $(TOP)/../configure/CONFIG_SITE.local
-include $(TOP)/../../CONFIG.local