diff --git a/documentation/pvDatabaseCPP_20121211.html b/documentation/pvDatabaseCPP_20121211.html new file mode 100644 index 0000000..a61cfe3 --- /dev/null +++ b/documentation/pvDatabaseCPP_20121211.html @@ -0,0 +1,892 @@ + + + +
+ +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 must be extended in order to create record instances. +The minimum that an extenson must provide is a top level PVStructure and a process method +but the framework provides for complex extensions.
+ +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 11-Dec-2012 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.
+ + +This document descibes a C++ implementation of some of the components in pvIOCJava. +It extracts the core components required to create a network accessible database of smart +memory resident records. +pvDatabaseCPP does not and will not implement any of the specialized support that pvIOCJava +provides. Instead other projects will implement the specialized support. +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. +
+ +A brief description of a pvDatase is that it is a network accessible set of 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. +This local provider is accessed by the remote pvAccess server. +A record is smart because code can be attached to a record.
+This document describes components that provides the following features: +
database does not itself implement pvRecord instances. +Instead it provides a base classes that make it easy to create record instances. +What does have to be implemented is a top +level PVStructure and the following two methods:
+Directory example/record has an example PVRecord implementation. +It implements a counter. +The top level structure is:
++structure + long value ++
NOTE: The example compiles but does not build because nothing +is implemented.
+ +This is the class description. +The example extends PVRecord.
+
+class ExampleRecord :
+ public virtual PVRecord
+{
+public:
+ POINTER_DEFINITIONS(ExampleRecord);
+ static PVRecordPtr create(epics::pvData::String const & recordName);
+ virtual ~ExampleRecord();
+ virtual bool isSynchronous();
+ virtual void process(
+ epics::pvDatabase::RecordProcessRequesterPtr const &processRequester);
+private:
+ ExampleRecord(epics::pvData::String const & recordName,
+ epics::pvData::PVStructurePtr const & pvStructure,
+ epics::pvData::PVLongPtr const &pvValue);
+ epics::pvData::PVLongPtr pvValue;
+};
+
+where
+This is the class implementation.
+
+ExampleRecord::~ExampleRecord(){}
+
+PVRecordPtr ExampleRecord::create(String const & recordName)
+{
+ String properties;
+ PVStructurePtr pvStructure = getStandardPVField()->scalar(pvLong,properties);
+ PVLongPtr pvValue = pvStructure->getLongField("value");
+ PVRecordPtr pvRecord(new ExampleRecord(recordName,pvStructure,pvValue));
+ return pvRecord;
+}
+
+ExampleRecord::ExampleRecord(
+ String const & recordName,
+ PVStructurePtr const & pvStructure,
+ PVLongPtr const &pvValue)
+: PVRecord(recordName,pvStructure),
+ pvValue(pvValue)
+{}
+
+bool ExampleRecord::isSynchronous() {return true;}
+
+void ExampleRecord::process(
+ RecordProcessRequesterPtr const &processRequester,bool alreadyLocked)
+{
+ if(!alreadyLocked) lock();
+ pvValue->put(pvValue->get() + 1);
+ processRequester->recordProcessResult(Status::Ok);
+ unlock();
+ processRequester->recordProcessComplete();
+ dequeueProcessRequest(processRequester);
+}
+
+where
+This is a main for creating and running the example.
+
+int main(int argc,char *argv[])
+{
+ String recordName("exampleRecord");
+ PVRecordPtr pvRecord = ExampleRecord::create(recordName);
+ PVDatabasePtr pvDatabase = PVDatabase::getMaster();
+ pvDatabase->addRecord(pvRecord);
+ cout << recordName << "\n";
+ string str;
+ while(true) {
+ cout << "Type exit to stop: \n";
+ getline(cin,str);
+ if(str.compare("exit")==0) break;
+
+ }
+ return 0;
+}
+
+The main program creates an example record and adds it to the database. +It then runs until the process is stopped by typing exit. +
Until the process is stopped, +pvAccess clients can put and get the value field. +For example
++pvget exampleRecord +pvput exampleRecord 5 ++
Will both work.
+This documentation describes the first phase of a phased implementation of pvDatabaseCPP: +
Future phases of pvDatabaseCPP should 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 provide a first attempt to describe the classes required for the first +phase.
+The last section gives a brief overview of the features provided by pvIOCJava.
+ +The classes in pvDatabase.h implement 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;
+
+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);
+ PVRecord(
+ epics::pvData::String const & recordName,
+ epics::pvData::PVStructurePtr const & pvStructure);
+ virtual ~PVRecord();
+ virtual void process(
+ RecordProcessRequesterPtr const &recordProcessRequester,
+ bool alreadyLocked) = 0;
+ virtual bool isSynchronous() = 0;
+ virtual bool requestImmediatePut(epics::pvData::PVFieldPtr const &pvField);
+ virtual void immediatePutDone();
+ 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);
+ void lock();
+ void unlock();
+ bool tryLock();
+ void lockOtherRecord(PVRecordPtr const & otherRecord);
+ void addPVRecordClient(PVRecordClientPtr const & pvRecordClient);
+ void removePVRecordClient(PVRecordClientPtr const & pvRecordClient);
+ void detachClients();
+ void beginGroupPut();
+ void endGroupPut();
+ void queueProcessRequest(
+ RecordProcessRequesterPtr const &recordProcessRequester);
+ void dequeueProcessRequest(
+ RecordProcessRequesterPtr const &recordProcessRequester);
+ void queuePutRequest(
+ RecordPutRequesterPtr const &recordPutRequester);
+ void putDone(
+ RecordPutRequesterPtr const &recordPutRequester);
+ virtual epics::pvData::String getRequesterName();
+ 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);
+ //init MUST be called after derived class is constructed
+ void init();
+
+};
+
+The methods are: +
Derived classes must implement this method.
+A client must only call this method when + RecordProcessRequester::becomeProcessor is called as a result + of a queueProcessRequest. + A client can either call lock before calling processs + or let process lock the record. + If a client wants to put data into the record it should lock, put, and then call + process.
+If the record is synchronous, process will return only when all processing + is complete. If the record is asynchronous then process arranges for some + other thread to do the processing and returns.
+When processing is done the record calls two client callbacks:
+The purpose is to allow the implementation to provide fields + that allow a client to abort process. + For example a motor record might provide a field stop
+The default always returns false.
+A record implementation can override the default and return true. + In it does requestImmediatePut it returns with the record locked.
+The client can change the value of the associated field and then call + immediatePutDone
+The default does nothing.
+Must be called by client as a result of a call to requestImmediatePut + that returns true.
+The default does nothing.
+This is for code that wants to change data in a record without processing. + If RecordPutRequester::requestResult is called with result true + then the record is locked and the client can make changes. + When done the client must call putDone
+
+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();
+ 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);
+};
+
+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();
+ PVRecordFieldPtrArrayPtr getPVRecordFields();
+ epics::pvData::PVStructurePtr getPVStructure();
+ virtual void removeListener(PVListenerPtr const & pvListener);
+ virtual void postPut();
+};
+
+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 RecordProcessRequester :
+ virtual public PVRecordClient,
+ virtual public epics::pvData::Requester
+{
+public:
+ POINTER_DEFINITIONS(RecordProcessRequester);
+ virtual ~RecordProcessRequester();
+ virtual void recordDestroyed() = 0;
+ virtual void becomeProcessor() = 0;
+ virtual void recordProcessResult(epics::pvData::Status status) = 0;
+ virtual void recordProcessComplete() = 0;
+};
+
+where
+
+class RecordPutRequester :
+ virtual public PVRecordClient
+{
+public:
+ POINTER_DEFINITIONS(RecordPutRequester);
+ virtual ~RecordPutRequester();
+ virtual void requestResult(bool result) = 0;
+};
+
+where
+
+class PVDatabase : virtual public epics::pvData::Requester {
+public:
+ POINTER_DEFINITIONS(PVDatabase);
+ static PVDatabasePtr getMaster();
+ virtual ~PVDatabase();
+ PVRecordPtr findRecord(epics::pvData::String const& recordName);
+ bool addRecord(PVRecordPtr const & record);
+ bool removeRecord(PVRecordPtr const & record);
+private:
+ PVDatabase();
+};
+
+where
+Not yet described.
+A brief description is that it must implement the following components of pvIOCJava:
+The following are the direct sub packages of pvIOCJava/src/org/epics/pvioc:
+In addition there is one class file JavaIOC.java. +This is starting a IOC instance. +This is not required for pvIOCCPP which is either a main or runs as part of a V3 IOC.
+ +