channelArray, trace implemented. Known memory leaks and exceptions fixed.

This commit is contained in:
Marty Kraimer
2013-06-27 10:38:05 -04:00
parent db4e10e393
commit 255f58aeb8
22 changed files with 1979 additions and 692 deletions
+222 -68
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, 23-May-2013</h2>
<h2 class="nocount">EPICS v4 Working Group, Working Draft, 27-Jun-2013</h2>
<dl>
<dt>Latest version:</dt>
<dd><a
@@ -46,11 +46,11 @@
</dd>
<dt>This version:</dt>
<dd><a
href="http://epics-pvdata.hg.sourceforge.net/hgweb/epics-pvdata/pvDatabaseCPP/raw-file/tip/documentation/pvDatabaseCPP_20130523.html">pvDatabaseCPP20130523.html</a>
href="http://epics-pvdata.hg.sourceforge.net/hgweb/epics-pvdata/pvDatabaseCPP/raw-file/tip/documentation/pvDatabaseCPP_20130627.html">pvDatabaseCPP20130627.html</a>
</dd>
<dt>Previous version:</dt>
<dd><a
href="http://epics-pvdata.hg.sourceforge.net/hgweb/epics-pvdata/pvDatabaseCPP/raw-file/tip/documentation/pvDatabaseCPP_20130516.html">pvDatabaseCPP20130516.html</a>
href="http://epics-pvdata.hg.sourceforge.net/hgweb/epics-pvdata/pvDatabaseCPP/raw-file/tip/documentation/pvDatabaseCPP_20130523.html">pvDatabaseCPP20130523.html</a>
</dd>
<dt>Editors:</dt>
<dd>Marty Kraimer, BNL</dd>
@@ -74,33 +74,31 @@ The minimum that an extenson must provide is a top level PVStructure and a proce
<h2 class="nocount">Status of this Document</h2>
<p>This is the 23-May-2013 version of the definition of pvDatabaseCPP.
<p>This is the 27-Jun-2013 version of the definition of pvDatabaseCPP.
</p>
<p>The following Channel methods are implemented and working: getField,
channelProcess, channelGet, channelPut, channelPutGet, and Monitor.
But lots of work remains:</p>
channelProcess, channelGet, channelPut, channelPutGet,channelArray and Monitor.
But work remains:</p>
<dl>
<dt>Other Channel Methods</dt>
<dd>Only ChannelArray remains.
Note that pvIOCJava does not implement the pvRequest for channelArray
correctly. It uses a private convention rather than using the output
of CreateRequest. This will be fixed before pvDatabaseCPP implements ChannelArray.
<dd>channlRPC will not be implemented because pvAccess itself
provides what is required to easily implement channelRPC requests.
</dd>
<dt>Monitor Algorithms</dt>
<dd>Monitor algorithms have not been implemented.
Thus all monitors are onPut.</dd>
<dt>Lifecycle problems</dt>
<dd>Problems when channel clients disconnect.
I am asking for help from Matej</dd>
<dt>Memory leak at exit</dt>
<dd>I am asking for help from Matej</dd>
<dt>Memory leaks</dt>
<dd>I think all memory leaks have been fixed.</dd>
<dt>Scalar Arrays</dt>
<dd>Share has not been implemented.
This will wait until Michael has new implementation of ScalarArray.</dd>
This will wait for a new implementation of ScalarArray.</dd>
<dt>Structure Arrays</dt>
<dd>Has not been implemented</dd>
<dt>toString</dt>
<dd>The toString methods should be replaced by stream operator&lt;&lt;.
</dd>
<dt>Testing</dt>
<dd>Needs lots more testing</dd>
<dd>Needs more testing</dd>
</dl>
<div id="toc">
@@ -142,7 +140,7 @@ A record is smart because code can be attached to a record, which is accessed vi
</dl>
<p>database provides base classes that make it easy to create record instances.
The code attached to each record must create the top
level PVStructure and the following two methods:</p>
level PVStructure and the following three methods:</p>
<dl>
<dt>init</dt>
<dd>This is a method for initializing the support.
@@ -151,7 +149,67 @@ level PVStructure and the following two methods:</p>
<dt>process</dt>
<dd>This is what makes a record smart.
</dd>
<dt>destroy</dt>
<dd>This releases and resorurces used by the impplementation.</dd>
</dl>
<h3>Getting started</h3>
<p>Included with this project are two main programs that are useful for
seeing how pvDatabase can be used by clients.
The programs are:
<dl>
<dt>exampleCounterMain</dt>
<dd>This has a database consisting of two records:
The exampleCounter discussed in a following section and a record
that allows a pvAccess client to set the trace level of the
exampleCounter. This is also discussed below.
</dd>
<dt>testExamplServerMain</dt>
<dd>This has a database with several records.</dd>
</dt>
</p>
<p>To start one of the programs on linux, do the following:
<pre>
mrk&gt; pwd
/home/hg/pvDatabaseCPP
mrk&gt; bin/linux-x86_64/testExampleServer
</pre></p>
<p>The Java programs
<a
href="http://epics-pvdata.hg.sourceforge.net/hgweb/epics-pvdata/swtshellJava/raw-file/tip/documentation/swtshellJava.html">
swtshellJava.html</a>
can be used to access the database.</p>
<p>In particular read the sections "Getting Started" and "Simple Example".
They will work on the testExampleServer with the following differences:
<dl>
<dt>startExample.zip</dt>
<dd>Do NOT use this. Instead run testExampleServer</dd>
<dt>channelList result</dt>
<dd>The result of channelList will show the list of records that
testExampleServer has rather than the records from startExample.zip</dd>
</dl>
</p>
<p>The database has the following records:
<dl>
<dt>exampleCounter</dt>
<dd>A record that is an instance of exampleCounter described below.
The most useful channel methods are channelGet, channelProcess,
and monitor.</dd>
<dt>exampleDouble</dt>
<dd>A record that is an instance of a record with a process method
that does nothing. To test it start a channelPut and a channelGet and/or monitor.</dd>
<dt>exampleDoubleArray</dt>
<dd>An array record that is an instance of a record with a process method
that does nothing. It can be tested like exampleDouble. In addition channelArray can
also be used.</dd>
<dt>examplePowerSupply</dt>
<dd>Can be used by channelGet, channelPut, channelPutGet, and monitor.</dd>
<dt>laptoprecordListPGRPC</dt>
<dd>Implements the record expected by swtshell channelList.
It can also be used via channelPutGet but unnecessary.</dd>
<dt>traceRecordPGRPC</dt>
<dd>This can be used via channelPutGet to set the trace level of another record.</dd>
</dl>
<h3>Relationship with pvIOCJava.</h3>
<p>This document descibes a C++ implementation of some of the components in pvIOCJava,
which also implements a pvDatabase.
@@ -227,7 +285,7 @@ private:
</dd>
<dt>~ExampleCounter<dt>
<dd>The destructor must be declared virtual.</dd>
<dt><destroy</dt>
<dt>destroy</dt>
<dd>Called when the record is being destroyed.
This must call the base class destroy method.
<dt>init<dt>
@@ -276,12 +334,11 @@ ExampleCounter::ExampleCounter(
pvTimeStamp.attach(pvStructure->getSubField("timeStamp"));
}
</pre>
The example is very simple. It just calls the base class constructor.
The example is very simple. Note that it calls the base class constructor.
<p>The destructor and destroy methods are:</p>
<pre>
ExampleCounter::~ExampleCounter()
{
destroy();
}
void ExampleCounter::destroy()
@@ -289,7 +346,7 @@ void ExampleCounter::destroy()
PVRecord::destroy();
}
</pre>
The destructor just calls destroy.
The destructor has nothing to do.
The destroy method, which is virtual, just calls the destroy method of the base class.
A more complicated example can clean up any resources it used but must call the base
class destroy method.
@@ -326,8 +383,13 @@ void ExampleCounter::process()
It adds 1.0 to the current value.
It then sets the timeStamp to the current time.
<h4>exampleCounterMain.cpp</h4>
<p>This is in test/server.
The main program is:</p>
<p>This is in test/server.</p>
<p><b>NOTE:</b>
This is a shorter version of the actual code.
It shows the essential code.
The actual example shows how the create additional records.
</p>
<p>The main program is:</p>
<pre>
int main(int argc,char *argv[])
{
@@ -439,14 +501,11 @@ The following are the minimium features required</p>
</dd>
<dt>pvRecord.cpp</dt>
<dd>
The implementation of the base class for PVREcord.
The implementation of the base class for PVRecord.
It can also implement record instances with a process
method does nothing.
This can be used to create a "dumb" record where all changes are
done by clients.
The complete implementation is provided in the header file.
Thus code will be generated only if other code includes the
header file and creates a record instance.
</dd>
<dt>exampleCounter.h</dt>
<dd>
@@ -472,6 +531,9 @@ pvRecord = RecordListRecord::create(recordName);
result = master-&gt;addRecord(pvRecord);
</pre>
</dd>
<dt>traceRecord.h</dt>
<dd>This implements a PVRecord that can set the trace level for
another record. See below for a discussion of trace level.</dd>
</dl>
<p>The classes in pvDatabase.h describe a database of memory resident
@@ -514,9 +576,6 @@ typedef std::tr1::shared_ptr&lt;PVRecordClient&gt; PVRecordClientPtr;
class PVListener;
typedef std::tr1::shared_ptr&lt;PVListener&gt; PVListenerPtr;
class RecordProcessRequester;
typedef std::tr1::shared_ptr&lt;RecordProcessRequester&gt; RecordProcessRequesterPtr;
class RecordPutRequester;
typedef std::tr1::shared_ptr&lt;RecordPutRequester&gt; RecordPutRequesterPtr;
@@ -548,12 +607,12 @@ public:
virtual bool init() {initPVRecord(); return true;}
virtual void process() {}
virtual void destroy();
static PVRecordPtr create(
epics::pvData::String const &amp; recordName,
epics::pvData::PVStructurePtr const &amp; pvStructure);
virtual ~PVRecord();
virtual void destroy();
epics::pvData::String getRecordName();
PVRecordStructurePtr getPVRecordStructure();
PVRecordFieldPtr findPVRecordField(
@@ -582,6 +641,8 @@ public:
epics::pvData::MessageType messageType);
void toString(epics::pvData::StringBuilder buf);
void toString(epics::pvData::StringBuilder buf,int indentLevel);
int getTraceLevel();
void setTraceLevel(int level);
protected:
PVRecord(
epics::pvData::String const &amp; recordName,
@@ -596,27 +657,30 @@ private:
...
}
</pre>
<p>The methods are:</h3>
<p>The methods are:</p>
<dl>
<dt>init</dt>
<dd>Virtual method.
<p>Derived classes must implement this method.
This method Must call initPVRecord.</p>
Derived classes must implement this method.
This method Must call initPVRecord.
</dd>
<dt>process</dt>
<dd>Virtual method.
<p>Derived classes must implement this method.
The base implementation does nothing.</p>
Derived classes must implement this method.
The base implementation does nothing.
</dd>
<dt>destroy</dt>
<dd>This is a virtual method.
A derived class must call the base class destroy method after it
has released any resources it uses.</dd>
<dt>create</dt>
<dd>Static method to create dumb records, i.e. records with a process method
that does nothing.</dd>
<dd>Static method to create dumb records,
i.e. records with a process method that does nothing.
A derived class should have it';s own static create method.
</dd>
<dt>~PVRecord</dt>
<dd>The destructor which must be virtual. A derived class must also have
a virtual destructor.</dd>
<dt>destroy</dt>
<dd>This is a virtual method.
</dd>
<dt>getRecordName</dt>
<dd>Return the recordName.</dd>
<dt>getPVRecordStructure</dt>
@@ -670,6 +734,27 @@ private:
The message will be sent to every requester.</dd>
<dt>toString</dt>
<dd>Just calls the top level PVStructure toString method.</dd>
<dt>getTraceLevel</dt>
<dd>This can be used for debugging. There are currently three
levels that are used by existing code.
<dl>
<dt>0</dt>
<dd>Produce no trace messages.</dd>
<dt>1</dt>
<dd>Issue a message to std::cout whenever anything is created
or destroyed.</dd>
<dt>2</dt>
<dd>In addition to lifetime messages also issue a message
whenever the record is accessed by pvAccess client.</dd>
</dl>
</dd>
<dt>setTraceLevel</dt>
<dd>Set the trace level. Note that special, described below.
provides a record support that allows a pvAccess client
to set the trace level of a record.</dd>
</dl>
<p>The protected methods are:</p>
<dl>
<dt>PVRecord</dt>
<dd>The constructor. It requires a recordName and a top level PVStructure.</dd>
<dt>initPVRecord</dt>
@@ -707,6 +792,8 @@ protected:
return shared_from_this();
}
virtual void init();
virtual void postParent(PVRecordFieldPtr const &amp; subField);
virtual void postSubField();
private:
...
};
@@ -812,6 +899,7 @@ public:
requested,PVRecordFieldPtr const &amp; pvRecordField) = 0;
virtual void beginGroupPut(PVRecordPtr const &amp; pvRecord) = 0;
virtual void endGroupPut(PVRecordPtr const &amp; pvRecord) = 0;
virtual void unlisten(PVRecordPtr const &amp; pvRecord);
};
</pre>
<p>where</p>
@@ -831,6 +919,9 @@ public:
<dd>A related set of changes is being started.</dd>
<dt>endGroupPut</dt>
<dd>A related set of changes is done.</dd>
<dt>unlisten</dt>
<dd>The record is being destroyed. The listener must release all
access to the record.</dd>
</dl>
<h3>class PVDatabase</h3>
<pre>
@@ -842,6 +933,7 @@ public:
virtual void destroy();
PVRecordPtr findRecord(epics::pvData::String const&amp; recordName);
bool addRecord(PVRecordPtr const &amp; record);
epics::pvData::PVStringArrayPtr getRecordNames();
bool removeRecord(PVRecordPtr const &amp; record);
virtual epics::pvData::String getRequesterName();
virtual void message(
@@ -865,6 +957,8 @@ private:
<dt>addRecord</dt>
<dd>Add a record to the database.
If the record already exists it is not modified and false is returned.</dd>
<dt>getRecordNames</dt>
<dd>Returns an array of all the record names.</dd>
<dt>removeRecord</dt>
<dd>Remove a record from the database.
If the record was not in the database false is returned.</dd>
@@ -882,24 +976,6 @@ It provides access to PVRecords and is access by the server side of remote pvAcc
except for channelRPC, provides a complete implementation of Channel
as defined by pvAccess.
For monitors it calls the code described in the following sections.</p>
<h3>ChannelLocalDebug</h3>
<p>The channelProvider implementation provides the ability to generate
debug messages based a debug level with the following meaning:</p>
<dl>
<dt>&lt;=0</dt>
<dd>No debug messages </dd>
<dt>&gt;0</dt>
<dd>Generate a message when anything is created or destroyed</dd>
<dt>&gt;1</dt>
<dd>Also generate processing messages.</dd>
</dl>
<p>ChannelProviderLocal has a method:</p>
<pre>
void createChannelLocalDebugRecord(
String const &amp; recordName);
</pre>
<p>This method creates a PVRecord that allows a pvAccess client to set the
debug level.</p>
<h3>pvCopy</h3>
<p>This provides code that creates a top level PVStructure that is an arbitrary
subset of the fields in the PVStructure from a PVRecord.
@@ -980,17 +1056,95 @@ like pvIOCJava there are plans to support for the following monitor algorithms:<
<dt>registerMonitorAlgorithmCreater</dt>
<dd>Called by code that implements a monitor algorithm.</dd>
</dl>
<h3>channelLocalDebugRecord</h3>
<h2>special</h2>
<p>This section provides two useful record support modules
and one that is used for testing.</p>
<h3>traceRecord</h3>
<p>This implements a PVRecord that allows a client to set
a debug level for the local channel provider implementation.
The top level structure has a single integer field named value.
See ChannelProviderLocal for the meaning associated with value.</p>
<p>ChannelProviderLocal has a method:</p>
the trace level of a record. It follows the pattern of a channelPutGet
record:
<pre>
void createChannelLocalDebugRecord(String const &amp; recordName);
traceRecord
structure arguments
string recordName
int level 0
structure result
string status
</pre>
<p>This creates an instance of a ChannelLocalDebugRecord and installs it
into the PVDatabase.</p>
where:
<dl>
<dt>recordName</dt>
<dd>The name of the record to set the trace level.</dd>
<dt>level</dt>
<dd>The level to set. The meaning is:
<dl>
<dt>0</dt>
<dd>No trace messages generated</dd>
<dt>1</dt>
<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
for each get and put request.</dd>
<dt>&gt;2</dt>
<dd>Currently no definition</dd>
</dl>
</dd>
<dt>result</dt>
<dd>The result of a cannelPutGet request</dd>
</dl>
<p>testExampleServerMain.cpp has an example of how to create a traceRecord:
<pre>
PVDatabasePtr master = PVDatabase::getMaster();
PVRecordPtr pvRecord;
String recordName;
bool result(false);
recordName = "traceRecordPGRPC";
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 set
the trace level of a record. It follows the pattern of a channelPutGet
record:
<pre>
traceRecord
structure arguments
string database master
string regularExpression .*
structure result
string status
string[] names
</pre>
where:
<dl>
<dt>database</dt>
<dd>The name of the datbase. The default is "master"</dd>
<dt>regularExpression</dt>
<dd>For now this is ignored and the complete list of names is always
returned.</dd>
<dt>status</dt>
<dd>The status of a putGet request.</dd>
<dt>names</dt>
<dd>The list of record names.</dd>
</dl>
<p>Note that swtshell has a command <b>channelList</b> that
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:
<pre>
recordName = "laptoprecordListPGRPC";
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>
<h3>powerSupplyRecordTest</h3>
<p>This simulates a simple power supply record.
It is used for testing.</p>
</div>
</body>
</html>