diff --git a/documentation/pvDatabaseCPP.html b/documentation/pvDatabaseCPP.html index 5ee9213..097c145 100644 --- a/documentation/pvDatabaseCPP.html +++ b/documentation/pvDatabaseCPP.html @@ -38,7 +38,7 @@
EPICS version 4 is a set of related products in the EPICS -V4 control system programming environment:
-Each of these products has a Java and a C++ implementation.
This is the 09-Apr-2013 version of the definition of pvDatabaseCPP. +
This is the 17-Apr-2013 version of the definition of pvDatabaseCPP.
-This is the beginning of the implementation of pvDataBaseCPP. -It describes the features that will be provided. -The class definitions for PVRecord are implemented. -The class definition for PVDatabase are defined but not implemented.
- +The following Channel methods are implemented and working: getField,i +channelProcess, channelGet, channelPut, and channelPutGet. +But lots of work remains:
+This document describes components that provides the following features:
database -provides base classes that make it easy to create record instances. +
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:
This document descibes a C++ implementation of some of the components in pvIOCJava, which also implements a pvDatabase. -It extracts the core components required to create a network accessible database of smart +PVDatabaseCPP extracts the core components required to create a network accessible database of smart memory resident records. pvDatabaseCPP does not implement any of the specialized support that pvIOCJava provides. @@ -190,10 +177,10 @@ mrk> bin/linux-x86_64/exampleCounter
The example resides in src/database. +
The example resides in src/database. The complete implementation is in the header file. A serious implementation would probably break the code into two files: 1) a header, and 2) the implementation. The description consists of
@@ -208,26 +195,32 @@ public: POINTER_DEFINITIONS(ExampleCounter); static ExampleCounterPtr create( epics::pvData::String const & recordName); - virtual ~ExampleCounter() {} + virtual ~ExampleCounter(); + virtual void destroy(); virtual bool init(); virtual void process(); private: ExampleCounter(epics::pvData::String const & recordName, epics::pvData::PVStructurePtr const & pvStructure); epics::pvData::PVLongPtr pvValue; + epics::pvData::PVTimeStamp pvTimeStamp; + epics::pvData::TimeStamp timeStamp; };where
The implementation of create is:
+The implementation of create method is:
ExampleCounterPtr ExampleCounter::create( epics::pvData::String const & recordName) { epics::pvData::PVStructurePtr pvStructure = - epics::pvData::getStandardPVField()->scalar(epics::pvData::pvDouble,""); + epics::pvData::getStandardPVField()->scalar( + epics::pvData::pvDouble,"timeStamp,alarm""); ExampleCounterPtr pvRecord( new ExampleCounter(recordName,pvStructure)); if(!pvRecord->init()) pvRecord.reset(); @@ -256,20 +250,38 @@ ExampleCounterPtr ExampleCounter::create( This:
The private constructor is just:
+The private constructor method is:
ExampleCounter::ExampleCounter( epics::pvData::String const & recordName, epics::pvData::PVStructurePtr const & pvStructure) : PVRecord(recordName,pvStructure) -{ } +{ + pvTimeStamp.attach(pvStructure->getSubField("timeStamp")); +}The example is very simple. It just calls the base class constructor. -
The implementation of init is:
+The destructor and destroy methods are:
++ExampleCounter::~ExampleCounter() +{ + destroy(); +} + +void ExampleCounter::destroy() +{ + PVRecord::destroy(); +} ++The destructor just calls destroy. +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. +
The implementation of init is:
bool ExampleCounter::init() { @@ -283,23 +295,26 @@ bool ExampleCounter::init()This:
The implementation of process is:
+The implementation of process is:
void ExampleCounter::process() { pvValue->put(pvValue->get() + 1.0); + timeStamp.getCurrent(); + pvTimeStamp.set(timeStamp); }-It just adds 1.0 to the current value. +It adds 1.0 to the current value. +It then sets the timeStamp to the current time.
This is in test/server. +
This is in test/server. The main program is:
int main(int argc,char *argv[]) @@ -326,10 +341,10 @@ This:
This documentation describes the first phase of a phased implementation of pvDatabaseCPP: @@ -412,8 +427,8 @@ The following are the minimium features required
The classes in pvDatabase.h describe a database of memory resident +
The classes in pvDatabase.h describe a database of memory resident smart records. It describes the following classes:
NOTES: +
NOTES:
Derived classes must implement this method. - This method Must call initPVRecord.
+ This method Must call initPVRecord.Not yet described. It is only of interest to someone who wants to understand how it works.
-A brief description is that it must implement the following components of pvIOCJava:
+A brief description is that it implements the following components of pvIOCJava:
This product is made available subject to acceptance of the EPICS open source license.
+This document describes pvDatabaseCPP, +which is a framework for implementing a network accessable 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. +
+ + +This is the 17-Apr-2013 version of the definition of pvDatabaseCPP. +
+The following Channel methods are implemented and working: getField,i +channelProcess, channelGet, channelPut, and channelPutGet. +But lots of work remains:
+A brief description of a pvDatabase is that it is a set of network accessible, smart, +memory resident records. +Each record has data composed of a top level PVStructure. +Each record has a name which is the channelName for pvAccess. +A local Channel Provider implements the complete ChannelProvider and +Channel interfaces as defined by pvAccess. +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.
+ +This document describes components that provides the following features: +
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:
+This document descibes a C++ implementation of some of the components in pvIOCJava, +which also implements a pvDatabase. +PVDatabaseCPP extracts the core components required to create a network accessible database of smart +memory resident records. +pvDatabaseCPP does not implement any of the specialized support that pvIOCJava +provides. +It is expected that many services will be created that do not require the full features provided +by pvIOCJava. In the future pvIOCJava should be split into multiple projects with one of +them named pvDatabaseJava.
+Similar to epics base, pvIOCJava implements the concept of synchronous and asynchronous record processing. +For pvDatabaseCPP the process method is allowed to block. +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 +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.
+ +The example implements a simple counter. +The example can be run on linux as follows:
++mrk> pwd +/home/hg/pvDatabaseCPP +mrk> bin/linux-x86_64/exampleCounter + ++
The example consists of two components:
+The example resides in src/database. +The complete implementation is in the header file. +A serious implementation would probably break the code into two files: +1) a header, and 2) the implementation. The description consists of
++class ExampleCounter; +typedef std::tr1::shared_ptr<ExampleCounter> ExampleCounterPtr; + +class ExampleCounter : + public PVRecord +{ +public: + POINTER_DEFINITIONS(ExampleCounter); + static ExampleCounterPtr create( + epics::pvData::String const & recordName); + virtual ~ExampleCounter(); + virtual void destroy(); + virtual bool init(); + virtual void process(); +private: + ExampleCounter(epics::pvData::String const & recordName, + epics::pvData::PVStructurePtr const & pvStructure); + epics::pvData::PVLongPtr pvValue; + epics::pvData::PVTimeStamp pvTimeStamp; + epics::pvData::TimeStamp timeStamp; +}; ++
where
+The implementation of create method is:
++ExampleCounterPtr ExampleCounter::create( + epics::pvData::String const & recordName) +{ + epics::pvData::PVStructurePtr pvStructure = + epics::pvData::getStandardPVField()->scalar( + epics::pvData::pvDouble,"timeStamp,alarm""); + ExampleCounterPtr pvRecord( + new ExampleCounter(recordName,pvStructure)); + if(!pvRecord->init()) pvRecord.reset(); + return pvRecord; +} ++This: +
The private constructor method is:
++ExampleCounter::ExampleCounter( + epics::pvData::String const & recordName, + epics::pvData::PVStructurePtr const & pvStructure) +: PVRecord(recordName,pvStructure) +{ + pvTimeStamp.attach(pvStructure->getSubField("timeStamp")); +} ++The example is very simple. It just calls the base class constructor. +
The destructor and destroy methods are:
++ExampleCounter::~ExampleCounter() +{ + destroy(); +} + +void ExampleCounter::destroy() +{ + PVRecord::destroy(); +} ++The destructor just calls destroy. +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. +
The implementation of init is:
++bool ExampleCounter::init() +{ + + initPVRecord(); + epics::pvData::PVFieldPtr pvField; + pvValue = getPVStructure()->getLongField("value"); + if(pvValue.get()==NULL) return false; + return true; +} ++This: +
The implementation of process is:
++void ExampleCounter::process() +{ + pvValue->put(pvValue->get() + 1.0); + timeStamp.getCurrent(); + pvTimeStamp.set(timeStamp); +} ++It adds 1.0 to the current value. +It then sets the timeStamp to the current time. +
This is in test/server. +The main program is:
++int main(int argc,char *argv[]) +{ + PVDatabasePtr master = PVDatabase::getMaster(); + ChannelProviderLocalPtr channelProvider = ChannelProviderLocal::create(); + String recordName("exampleCounter"); + PVRecordPtr pvRecord = ExampleCounter::create(recordName); + bool result = master->addRecord(pvRecord); + cout << "result of addRecord " << recordName << " " << result << endl; + pvRecord.reset(); + cout << "exampleServer\n"; + string str; + while(true) { + cout << "Type exit to stop: \n"; + getline(cin,str); + if(str.compare("exit")==0) break; + + } + return 0; +} ++This: +
This documentation describes the first phase of a phased implementation of pvDatabaseCPP: +
Future phases of pvDatabaseCPP might include:
+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.
+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 starting to implement services. +The following are the minimium features required
+The following sections describes the classes required for the first phase.
+ +This directory has the following files:
+The classes in pvDatabase.h describe a database of memory resident +smart records. +It describes the following classes:
+Each class is described in a separate subsection.
++namespace epics { namespace pvDatabase { + +class PVRecord; +typedef std::tr1::shared_ptr<PVRecord> PVRecordPtr; +typedef std::map<epics::pvData::String,PVRecordPtr> PVRecordMap; + +class PVRecordField; +typedef std::tr1::shared_ptr<PVRecordField> PVRecordFieldPtr; +typedef std::vector<PVRecordFieldPtr> PVRecordFieldPtrArray; +typedef std::tr1::shared_ptr<PVRecordFieldPtrArray> PVRecordFieldPtrArrayPtr; + +class PVRecordStructure; +typedef std::tr1::shared_ptr<PVRecordStructure> PVRecordStructurePtr; + +class PVRecordClient; +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; + +class PVDatabase; +typedef std::tr1::shared_ptr<PVDatabase> PVDatabasePtr; ++ +
NOTES: +
+class PVRecord + public epics::pvData::Requester, + public std::tr1::enable_shared_from_this<PVRecord> +{ +public: + POINTER_DEFINITIONS(PVRecord); + + virtual bool init() {initPVRecord(); return true;} + virtual void process() {} + + 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( + epics::pvData::PVFieldPtr const & pvField); + bool addRequester(epics::pvData::RequesterPtr const & requester); + bool removeRequester(epics::pvData::RequesterPtr const & requester); + inline void lock_guard() { epics::pvData::Lock theLock(mutex); } + void lock(); + void unlock(); + bool tryLock(); + void lockOtherRecord(PVRecordPtr const & otherRecord); + bool addPVRecordClient(PVRecordClientPtr const & pvRecordClient); + bool removePVRecordClient(PVRecordClientPtr const & pvRecordClient); + void detachClients(); + bool addListener(PVListenerPtr const & pvListener); + bool removeListener(PVListenerPtr const & pvListener); + void beginGroupPut(); + void endGroupPut(); + epics::pvData::String getRequesterName() {return getRecordName();} + virtual void message( + epics::pvData::String const & message, + epics::pvData::MessageType messageType); + void message( + PVRecordFieldPtr const & pvRecordField, + epics::pvData::String const & message, + epics::pvData::MessageType messageType); + void toString(epics::pvData::StringBuilder buf); + void toString(epics::pvData::StringBuilder buf,int indentLevel); +protected: + PVRecord( + epics::pvData::String const & recordName, + epics::pvData::PVStructurePtr const & pvStructure); + void initPVRecord(); + epics::pvData::PVStructurePtr getPVStructure(); + PVRecordPtr getPtrSelf() + { + return shared_from_this(); + } +private: +... +} ++
The methods are: +
Derived classes must implement this method. + This method Must call initPVRecord.
+Derived classes must implement this method. + The base implementation does nothing.
++class PVRecordField { + public virtual epics::pvData::PostHandler, + public std::tr1::enable_shared_from_this<PVRecordField> +public: + POINTER_DEFINITIONS(PVRecordField); + PVRecordField( + epics::pvData::PVFieldPtr const & pvField, + PVRecordStructurePtr const &parent, + PVRecordPtr const & pvRecord); + virtual ~PVRecordField(); + virtual void destroy(); + PVRecordStructurePtr getParent(); + epics::pvData::PVFieldPtr getPVField(); + epics::pvData::String getFullFieldName(); + epics::pvData::String getFullName(); + PVRecordPtr getPVRecord(); + bool addListener(PVListenerPtr const & pvListener); + virtual void removeListener(PVListenerPtr const & pvListener); + virtual void postPut(); + virtual void message( + epics::pvData::String const & message, + epics::pvData::MessageType messageType); +protected: + PVRecordFieldPtr getPtrSelf() + { + return shared_from_this(); + } + virtual void init(); +private: +... +}; ++
When PVRecord is created it creates a PVRecordField for every field in the PVStructure +that holds the data. It has the following methods: +
+ ++class PVRecordStructure : public PVRecordField { +public: + POINTER_DEFINITIONS(PVRecordStructure); + PVRecordStructure( + epics::pvData::PVStructurePtr const & pvStructure, + PVRecordFieldPtrArrayPtr const & pvRecordField); + virtual ~PVRecordStructure(); + virtual void destroy(); + PVRecordFieldPtrArrayPtr getPVRecordFields(); + epics::pvData::PVStructurePtr getPVStructure(); + virtual void removeListener(PVListenerPtr const & pvListener); + virtual void postPut(); +protected: + virtual void init(); +private: +... +}; ++
When PVRecord is created it creates a PVRecordStructure for every structure field in the PVStructure +that holds the data. It has the following methods: +
++class PVRecordClient { + POINTER_DEFINITIONS(PVRecordClient); + virtual ~PVRecordClient(); + virtual void detach(PVRecordPtr const & pvRecord); +}; ++
where
++class PVListener { + virtual public PVRecordClient +public: + POINTER_DEFINITIONS(PVListener); + virtual ~PVListener(); + virtual void dataPut(PVRecordFieldPtr const & pvRecordField) = 0; + virtual void dataPut( + PVRecordStructurePtr const & + requested,PVRecordFieldPtr const & pvRecordField) = 0; + virtual void beginGroupPut(PVRecordPtr const & pvRecord) = 0; + virtual void endGroupPut(PVRecordPtr const & pvRecord) = 0; +}; ++
where
++class PVDatabase : virtual public epics::pvData::Requester { +public: + POINTER_DEFINITIONS(PVDatabase); + static PVDatabasePtr getMaster(); + virtual ~PVDatabase(); + virtual void destroy(); + PVRecordPtr findRecord(epics::pvData::String const& recordName); + bool addRecord(PVRecordPtr const & record); + bool removeRecord(PVRecordPtr const & record); + virtual epics::pvData::String getRequesterName(); + virtual void message( + epics::pvData::String const &message, + epics::pvData::MessageType messageType); +private: + PVDatabase(); +}; ++
where
+Not yet described. +It is only of interest to someone who wants to understand how it works. +
+A brief description is that it implements the following components of pvIOCJava:
+