channelArray, trace implemented. Known memory leaks and exceptions fixed.
This commit is contained in:
@@ -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<<.
|
||||
</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> pwd
|
||||
/home/hg/pvDatabaseCPP
|
||||
mrk> 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->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<PVRecordClient> PVRecordClientPtr;
|
||||
class PVListener;
|
||||
typedef std::tr1::shared_ptr<PVListener> PVListenerPtr;
|
||||
|
||||
class RecordProcessRequester;
|
||||
typedef std::tr1::shared_ptr<RecordProcessRequester> RecordProcessRequesterPtr;
|
||||
|
||||
class RecordPutRequester;
|
||||
typedef std::tr1::shared_ptr<RecordPutRequester> 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 & recordName,
|
||||
epics::pvData::PVStructurePtr const & 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 & 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 & subField);
|
||||
virtual void postSubField();
|
||||
private:
|
||||
...
|
||||
};
|
||||
@@ -812,6 +899,7 @@ public:
|
||||
requested,PVRecordFieldPtr const & pvRecordField) = 0;
|
||||
virtual void beginGroupPut(PVRecordPtr const & pvRecord) = 0;
|
||||
virtual void endGroupPut(PVRecordPtr const & pvRecord) = 0;
|
||||
virtual void unlisten(PVRecordPtr const & 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& recordName);
|
||||
bool addRecord(PVRecordPtr const & record);
|
||||
epics::pvData::PVStringArrayPtr getRecordNames();
|
||||
bool removeRecord(PVRecordPtr const & 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><=0</dt>
|
||||
<dd>No debug messages </dd>
|
||||
<dt>>0</dt>
|
||||
<dd>Generate a message when anything is created or destroyed</dd>
|
||||
<dt>>1</dt>
|
||||
<dd>Also generate processing messages.</dd>
|
||||
</dl>
|
||||
<p>ChannelProviderLocal has a method:</p>
|
||||
<pre>
|
||||
void createChannelLocalDebugRecord(
|
||||
String const & 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 & 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>>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->addRecord(pvRecord);
|
||||
if(!result) cout<< "record " << recordName << " not added" << 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->addRecord(pvRecord);
|
||||
if(!result) cout<< "record " << recordName << " not added" << endl;
|
||||
</pre>
|
||||
<h3>powerSupplyRecordTest</h3>
|
||||
<p>This simulates a simple power supply record.
|
||||
It is used for testing.</p>
|
||||
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
Reference in New Issue
Block a user