Difference between revisions of "V4 Design: Record Processing"

From EPICSWIKI
Line 1: Line 1:
EPICS V4: Record Processing September 16 2005  
EPICS V4: Record Processing September 23 2005  


----
----
Line 6: Line 6:


<b>UNRESOLVED ISSUES</b>
<b>UNRESOLVED ISSUES</b>
* Monitored data: What are the semantics for monitors that involve large amounts of memory?
* This document will undergo LOTS of evolution1
* Monitors
** How will monitor data be managed?
** Big problem is how will array data be managed?


This document described semantics for V4 record processing that are
This document described semantics for V4 record processing that are
Line 64: Line 67:


* Links to other records:
* Links to other records:
** Can request that the linked record be processed. In V3 this was only available for puts and only if recordtype set pp(TRUE).
** Can request that the linked record be processed. In V3 this was only available for database links.
** Can wait until the linked record completes processing. In V3 this was only possible for puts.
** Can wait until the linked record completes asynchronous processing. In V3 this was only possible for database links. For channel access only special support in SynApps provided this capability for channel access links.
* While record support is active a record can still be processed and post monitors.
* While record support is active a record can still be processed and post monitors.
* Database links are processed via queue requests rather than recursive calls to dbProcess.
* Database links are processed via queue requests rather than recursive calls to dbProcess
* Instead of lock sets, each record instance has a lock.
* Instead of lock sets, each record instance has a lock.
* Monitors are implemented by database access without help from record support
* Monitors are implemented by database access without help from record support
* Channel Access and Database Access can access structures


== Link Semantics ==
== Link Semantics ==
Line 78: Line 80:
All provide the ability to request processing and to wait until processing completes.
All provide the ability to request processing and to wait until processing completes.


== Processing Database Links ==
== Processing Local Links ==


A local link just means a link to a record in the same IOC.
In V3 records linked via database links are processed via recursive calls to
In V3 records linked via database links are processed via recursive calls to
dbProcess. In V4 this will no longer be done. For V4 the following is done
dbProcess. In V4 this will no longer be done.
when a link requests processing:
Each thread that scans records,
e.g. the 1 second scan thread does the following
when a record requests processing of a local link:
 
* If the linked record is active or already queued the request fails.
* If the linked record does not allow link requests to cause processing the request fails.
* If a queue request is allowed then the request is handled as follows:
** The requests are queued if FIFO order
** The queue is emptied immediately after the record containing the link returns to DbAccess.process
** If all linked records complete synchronously the record containing the link is reprocessed before the thread processes any other records.


# If the record is active or already queued the request fails.
# If the record does not allow link requests to cause processing the request fails.
# If neither 1) or 2) are true than the record is queued for processing.




Line 103: Line 112:
the posting of monitors.
the posting of monitors.


Monitors are posted by dbProcess when
Monitors are posted by DbAccess.process when
* record support returns processActive.
* record support returns processActive.
* at the end of record processing.
* at the end of record processing.
Line 110: Line 119:
== Database Field Types ==
== Database Field Types ==


V4 allows Channel Access and Database Access to the
V4 allows Channel and Database Access to the
following types of fields:
following types of fields:


Line 135: Line 144:


Links are processed as follows:
Links are processed as follows:
* Process Link: Perform the following actions
** Optionally specify it other processing can be done in parallel
** Request processing
** Optionally wait until record completes processing.
* Output Link: Two varieties are available
**Output Only: Perform the following actions
*** Optionally specify it other processing can be done in parallel
*** Put value
*** Optionally wait until the put completes
** Output and Process: Perform the following actions
*** Optionally specify it other processing can be done in parallel
*** Put value and request that record be processed. <b>If record can not be processed should the value be changed?</b>
*** Optionally wait until the put and process completes


* Input Link: Two flavors are available
* Input Link: Two flavors are available
Line 141: Line 165:
*** Optionally process record containing the link when monitor value is returned.
*** Optionally process record containing the link when monitor value is returned.
** Input Link: Perform the following actions
** Input Link: Perform the following actions
*** Optionally specify it other processing can be done in parallel
*** Optionally request that record be processed.
*** Optionally request that record be processed.
*** Optionally wait for record to complete processing.
*** Optionally wait for record to complete processing.
*** Get value.
*** Get value.
* Output Link: Two varieties are available
**Output Only: Perform the following actions
*** Put value
*** Optionally wait until the put completes
** Output and Process: Perform the following actions
*** Put value and request that record be processed. Note that if record can not be processed the value is not changed.
*** Optionally wait until the put and process completes
* Process Link: Perform the following actions
** request processing
** Optionally wait until record completes processing.


The following rules apply when a process request is made:
The following rules apply when a process request is made:
Line 169: Line 184:
----
----
<center>
<center>
= Record Processing =
= Record Processing Semantics =
  </center>
  </center>


This section describes the semantics implemented by dbProcess.
This section describes the semantics implemented by DbAccess.process.


dbProcess maintains a variable processState which is passed to recordCommon
Each record type has two sets of record support.
and to record support and can also be returned by them.
One is implemented by RecordCommonSupport, which provides support for the
fields in RecordCommon.
The other is the record support for the fields in the record type,
which will be called RecordSupport in this section.
Each support implements method process.


== V4 Processing States ==
One of the arguments to process is processState which has the values:
* processCancel - Cancel any outstanding activity
* processStart - Start processing
* processContinue - Making additional call


processState is passed to process (recordCommon or record support) and is also
process returns ProcessReturn which is one of the following:
returned by process.  processState defines the states:
* processDone - Done and successful
; processCancel
* processQuit - Do not do any more processing
: If record support is called with this state, it must terminate outstanding processing and prepare for being called with processIdle.
* processActive - Not done
; processIdle
: record is not being processed
; processStart
: processing is starting
; processInputActive
: recordCommon is waiting for input links to complete
; processActive
: record support is waiting for completion of record specific activity
; processOutputActive
: recordCommon is waiting for output and process links to complete
; processDone
: process has completed.


NOTES:
* Record support can implement substates. For example the sequence record keeps state about which link set it is processing.
* Individual record types might use only a subset of the above states.
* V3 link instances had attributes like CA, CP, CPP. For V4 these are:
** process - a request to process the record before gets or after puts.
** wait - a request to wait until it has processed all it's input links
** parallel - OK to allow simultaneous gets or puts


There are three stages to processing a record:
* RecordCommonSupport perform initial processing, e.g. all input links are processed.
* RecordSupport performs its processing in collaboration with link and device support
* RecordCommonSupport performs final processing, e.g. ouput links and process links are processed.


== dbProcess ==
It is up to RecordCommonSupport to keep internal state so that it knows if
it is being called for initial or final processing.


The functionality described in this section will be divided between
During each stage DbAccess.process can call process multiple times:
iocCore and recordCommon. recordCommon is the V4 successor to the V3 dbCommon.
* At the beginning of each stage process is called with state processStart. process returns one of:
For V4 it is a separate software component.
** processDone - DbAccess.process proceeds to the next stage of record processing:
*** RecordCommonSupport initial - DbAccess.process calls RecordSupport
*** RecordSupport - Calls RecordCommonSupport
*** RecordCommonSupport final - DbAccess.process does its final processing and sets record idle.
** processActive - DbAccess.process will be called again via a call to DbAccess.processContinue
*** RecordCommonSupport must call DbAccess.processContinue
*** RecordSupport can call DbAccess.processContinue. A call to DbAccess.process will also call DbAccess.process.
** processQuit
*** If RecordSupport returned this DbAccess.process calls RecordCommonSupport with state processCancel
*** Otherwise RecordSupport does its normal end of processing and sets the record idle.


NOTE: FLNK (forward link) is replaced by an array of process links.
For RecordCommonSupport the above rules allow asynchronous links.
The standard RecordCommonSupport does the following:
* initial processing means to handle the disable fields
** A get request is made for the disable link
***  If it is synchronous RecordCommonSupport returns processAbort if the record is disable or processDone  otherwise.
*** If it is asynchronous, processContinue is returned and RecordCommonSupport arranges for DbAccess.processContinue to be called when the link completes.
* final processing means to handle the array of process links
** If all are synchronous RecordCommonSupport returns processDone
** If any are asynchronous, processContinue is returned and RecordCommonSupport arranges for DbAccess.processContinue to be called when the link completes.


For RecordSupport the above rules allow:
* process can be called repeatedly. This will continue as long as it returns processActive
* Everytime process returns processActive DbAccess.process posts monitors.
* The record can be periodically scanned.


When dbProcess is called the action it takes depends on processState.
* processCancel
** If recordCommon is active it is called with state processCancel
** If record support is active it is called with state processCancel
** prepare for state processIdle
* processIdle
** prepare the record for processing
** set state = processStart and goto processInputActive
* processInputActive
** call recordCommon
*** If recordCommon returns processInputActive return
*** If recordCommon returns processActive set processState = processStart and goto processActive
*** If recordCommon returns processDone goto processDone
* processActive
** Call record support
*** If record support returns processActive post monitors and return
*** If record support returns processDone goto processOutputActive
* processOutputActive
** Call recordCommon
*** If recordCommon returns processOutputActive return
*** If recordCommon returns processDone goto processDone
* processDone
** Perform final processing - See below for details.
** set processState = processIdle
** return
NOTES:
* Record support is called with state processStart or processActive. It can return processActive as often as it wants. This supports the semantics of both the motor and sequence records.
* The semantics support the following model
** recordCommon processes all its input links and then
** Record support stays active as long as desired and then
** recordCommon processes all its output links and then
** dbProcess does final processing and sets the record idle.
The remaining subsections provide more details about each processState. Keep in mind
that some actions are performed by dbProcess, some by recordCommon,
some by record support, and some by link support.
== processState processCancel ==
When process (Record Support or recordCommon) is called with this state
it just prepares for being called again with state processIdle.
An example of when process is called with this state is when a Channel Access
request is made to modify a link or device field in a record instance that is not idle. If this happens, record support and/or recordCommon will be called
to cancel any outstanding internal state.
Process does not have to call link or device support because Database Access
will call the cancel method of any link or device support attached to
the record.
== processState processIdle ==
When dbProcess is called with processIdle it:
* prepares record for processing
* calls recordCommon with processStart
== processState processStart ==
When recordCommon is called with processStart it:
* prepares for alarmStatus and alarmSeverity. See Alarm Processing for details.
* starts processing it's input links. Details are given below.
* returns with processState one of the following:
** processInputActive - dbProcess returns and when called again calls recordCommon.
** processActive - dbProcess calls record support with processStart.
** processDone - dbProcess completes processing. record support will NOT be called and recordCommon will not be called to handle output links
When record support is called with processStart it:
* starts processing
* returns with processState one of the following:
** processActive - dbProcess returns and when called again calls record support.
** processDone - dbProcess calls recordCommon with processDone.
== processState processInputActive ==
Only recordCommon is called with or returns this state.
This state means that one or more input links handled by recordCommon have not
completed.
When recordCommon detects that all it's input
links have completed, it sets processState = processActive and returns.
dbProcess calls record support to start processing.
recordCommon can also return processDone, In this case dbProcess will just
do final cleanup and set state back to processIdle. This is done,
for example if recordCommon finds the record disabled.
== processState processActive ==
Only record support is called with this state.
recordCommon and record support can return this state.
This state means that record support and associated device support
are waiting for something to complete. Examples are:
* wait for links to complete
* wait for a motor to reach some position.
The record, however, can be processed so that it can
report intermediate data values, e.g. the current motor position.
For example the record can be periodically scanned.
When record support is called it returns one of:
* processActive - dbProcess post monitors and returns. When it is called again it calls record support.
* processDone - dbProcess calls recordCommon with processDone.
== processState processOutputActive ==
Only recordCommon is called with or returns this state.
This state means that one or more output links handled by recordCommon have not
completed.
recordCommon returns either
* processOutputActive - record support returns and when called again calls recordCommon with processOutputActive.
* processDone - dbProcess does final processing as described next.
== processState processDone ==
Only recordCommon is called with or returns this state.
When recordCommon is called with processDone it starts processing its output links.
It returns either
* processOutputActive - record support returns and when called again calls recordCommon with processOutputActive.
* processDone - dbProcess does final processing as described next.
When both record support and recordCommon have reported that they are done,
dbProcess does some final steps and then sets the processState to processIdle.
The final steps are:
* If the request to process the record included a callback, the callback is called.
* If other record completion callback requests are present, call them.
* post monitors
* The record is set idle.


== Links to Other Records ==
== Links to Other Records ==


Links can be processed in parallel, sequentially, or a
Links can be processed in parallel, sequentially, or a
combination of these. recordCommon handles the links in recordCommon and record
combination of these.
support handles record specific input links. The support is responsible for
RecordCommonSupport handles the links in RecordCommon and RecordSupport
handles record specific links. The support is responsible for
implementing sequential or parallel link processing.
implementing sequential or parallel link processing.
Link support performs the actual I/O. The Link support methods
LinkSupport performs the actual I/O. The LinkSupport methods
provide options specifying if the linked record should be processed and
provide options specifying if the linked record should be processed and
provide a callback to call when link processing completes. It is up to
provide a callback to call when link processing completes. It is up to
recordCommon or record support to again call dbProcess when all input links
RecordCommonSupport or RecordSupport to call DbAccess.processContinue
complete.
when all links complete.
 
If is OK for dbProcess to be called multiple times while links
are being processed.


----
----
Line 372: Line 266:
Lock sets solved two Mutual Exclusion problems:
Lock sets solved two Mutual Exclusion problems:
* V3 allowed dbProcess to be called recursively.
* V3 allowed dbProcess to be called recursively.
** process passive database links and forward links were implemented via recursive calls to dbProcess
** process passive database links and forward links were implemented via recursive calls to DbAccess.process
** Lock sets prevented deadly embrace problems for circular links.
** Lock sets prevented deadly embrace problems for circular links.
* No puts could be done to an record in a lock set while record processing is active.
* No puts could be done to an record in a lock set while record processing is active.
Line 379: Line 273:




V4 does not call dbProcess recursively. Instead a process request is queued.
V4 does not call DbAccess.process recursively. Instead a process request is queued.
The request fails if either of the following is true:
The request fails if either of the following is true:
* The record is active.
* The record is active.
* The record is already queued.
* The record is already queued.


Queuing requests to process rather than recursively calling dbProcess
Queuing requests to process rather than recursively calling DbAccess.process
does not necessarily cause unnecessary context switches.
does not necessarily cause unnecessary context switches.
<b>
Must design a way to queue process requests to the same thread
that issues the requests if the link is to a local record.
First thoughts is that this should be FIFO and queue emptied immediately
after the requesting record returns from process.
</b>
For example if all linked records are passive and the same priority then
For example if all linked records are passive and the same priority then
all processing can occur without any context switches.
all processing can occur without any context switches.
* A request is made to a thread to call dbProcess.
* A request is made to a thread to call DbAccess.process.
** The request is put on a queue associated with the thread.
** The request is put on a queue associated with the thread.
* Sometime later the request is dequeued and dbProcess is called.
* Sometime later the request is dequeued and DbAccess.process is called.
** For each link, with a request to process request, the request is put on the queue for the same thread
** For each link, with a request to process request, the request is put on the queue for the same thread
** After all requests are queued dbProcess returns
** After all requests are queued DbAccess.process returns
* The thread takes each request off the queue and calls dbProcess for the associated linked record
* The thread takes each request off the queue and calls DbAccess.process for the associated linked record
** When all linked records finish processing a request is queued to call dbProcess for the original record
** When all linked records finish processing a request is queued to call DbAccess.process for the original record
* The request for the original record is removed from the queue and it's dbProcess is again called.
* The request for the original record is removed from the queue and it's DbAccess.process is again called.
** The record completes.
** The record completes.
<b>Question</b> What about periodically scanned records? Needs thought.
<b>Question</b> What about periodically scanned records? Needs thought.
Line 402: Line 304:


Each record instance has an associated lock maintained by dbAccess.
Each record instance has an associated lock maintained by dbAccess.
When dbProcess is called it takes the lock.
When DbAccess.process is called it takes the lock.
Before it returns it unlocks.
Before it returns it unlocks.
Thus recordCommon and record support do not need to lock or unlock.
Thus recordCommon and record support do not need to lock or unlock.
Line 436: Line 338:


Fields are modified in one of two ways:
Fields are modified in one of two ways:
* Changes made while record is being processed. For these posting is handled by dbProcess.
* Changes made while record is being processed. For these posting is handled by DbAccess.process.
* Changes by other code. For these posting is handled by dbLock/dbUnlock.
* Changes by other code. For these posting is handled by dbLock/dbUnlock.


Each field of a record instance has two associated "modified" bits.
Each field of a record instance has two associated "modified" bits.
One is for changes handled by dbProcess. The other is for changes made
One is for changes handled by DbAccess.process. The other is for changes made
by dbLock/dbUnlock.
by dbLock/dbUnlock.


dbProcess posts monitors when:
DbAccess.process posts monitors when:
* When record support returns processActive.
* When record support returns processActive.
* When it finishes record processing.
* When it finishes record processing.

Revision as of 16:03, 23 September 2005

EPICS V4: Record Processing September 23 2005


Overview

UNRESOLVED ISSUES

  • This document will undergo LOTS of evolution1
  • Monitors
    • How will monitor data be managed?
    • Big problem is how will array data be managed?

This document described semantics for V4 record processing that are different than for V3. This includes the following:

  • Semantics for Database and Channel Access Links.
  • Semantics for record processing
  • Record Locking
  • Posting database monitors
  • Status and Alarm Severity
  • Access to array and structure fields.

This version is based on feedback from the EPICS core developer's meeting at ANL/APS on July 11th through July 14th. In addition discussions with Andrew Johnson and Eric Norum have led to many of the ideas described below. This wiki is a companion to the wiki "V4 Design: dbdInterfaces".

V3 record processing semantics do not work well for data acquisition applications. An example of data acquisition is:

  • Move sample to new position.
    • Several motors may be involved
    • While moving post monitors to show current position, etc.
  • Sample data
  • Wait until CA client has fetched the data before next move.

SynAPPS provides the Scan, motor, etc records which help with data processing applications. These records process as follows:

  • Record does not complete processing until all inputs, outputs, etc done. Not completing means that they do not call recGblFwdLink until all proccessing is complete. Note that recGblFwdLink is what causes the V3 ioc to complete record processing.
  • While waiting for asynchronous events these records have PACT=0 but keep state that shows it is still active
  • Can be scanned and issue monitors while internal state is active

Leaving PACT 0 but not calling recGblFwdLink was not anticipated when the V3 record processing semantics were created. For V4 a record can be processed while it is waiting for asynchronous processing to complete.

In V3, if an input link is asynchronous, Process Passive does not wait for asynchronous processing to complete before fetching data. This also complicated data acquisition applications.

V4 record processing is designed to make data acquisition easier. Both input and output links can wait for record processing. This is done, however, without record support blocking. If blocking makes it easier to implement record support, then the support can spawn a separate thread that does block. Record support can communicate with the separate thread to decide when to complete record processing.


Goals for V4 Record Processing

V4 record processing has the following features not available in V3:

  • Links to other records:
    • Can request that the linked record be processed. In V3 this was only available for database links.
    • Can wait until the linked record completes asynchronous processing. In V3 this was only possible for database links. For channel access only special support in SynApps provided this capability for channel access links.
  • While record support is active a record can still be processed and post monitors.
  • Database links are processed via queue requests rather than recursive calls to dbProcess
  • Instead of lock sets, each record instance has a lock.
  • Monitors are implemented by database access without help from record support

Link Semantics

The link semanics are similar for database and channel access links ( input, output, and process). All provide the ability to request processing and to wait until processing completes.

Processing Local Links

A local link just means a link to a record in the same IOC. In V3 records linked via database links are processed via recursive calls to dbProcess. In V4 this will no longer be done. Each thread that scans records, e.g. the 1 second scan thread does the following when a record requests processing of a local link:

  • If the linked record is active or already queued the request fails.
  • If the linked record does not allow link requests to cause processing the request fails.
  • If a queue request is allowed then the request is handled as follows:
    • The requests are queued if FIFO order
    • The queue is emptied immediately after the record containing the link returns to DbAccess.process
    • If all linked records complete synchronously the record containing the link is reprocessed before the thread processes any other records.


Record Locking

V3 implemented lock sets in order to prevent different threads from simultaneously accessing linked records.

Instead of lock sets V4:

  • Implements a per record instance lock.
  • Defines a rule that allows two records to be locked without deadlocks

Posting Monitors

In V3 monitors are posted when code (record support, device support, database access, etc) calls db_post_event. In V4 database access will itself handle the posting of monitors.

Monitors are posted by DbAccess.process when

  • record support returns processActive.
  • at the end of record processing.


Database Field Types

V4 allows Channel and Database Access to the following types of fields:

  • primitive types
  • string
  • one dimensional array of primitive or string or struct
  • struct with fields of following types:
    • primitive
    • string
    • struct
    • array of primitive or string or struct


Link Semantics

NOTES:

  • Link just means access to a record or field. The requester can be:
    • A database link in a record
    • A channel access link in a record
    • A channel access client PV.
  • Instead of "forward link" the name "process link" is used.

Links are processed as follows:

  • Process Link: Perform the following actions
    • Optionally specify it other processing can be done in parallel
    • Request processing
    • Optionally wait until record completes processing.
  • Output Link: Two varieties are available
    • Output Only: Perform the following actions
      • Optionally specify it other processing can be done in parallel
      • Put value
      • Optionally wait until the put completes
    • Output and Process: Perform the following actions
      • Optionally specify it other processing can be done in parallel
      • Put value and request that record be processed. If record can not be processed should the value be changed?
      • Optionally wait until the put and process completes
  • Input Link: Two flavors are available
    • Monitor Link
      • Implemented via a monitor request on linked field
      • Optionally process record containing the link when monitor value is returned.
    • Input Link: Perform the following actions
      • Optionally specify it other processing can be done in parallel
      • Optionally request that record be processed.
      • Optionally wait for record to complete processing.
      • Get value.

The following rules apply when a process request is made:

  • If record is already being processed the request fails.
  • Record support can specify that links to particular fields not cause processing.
  • A record can declare that it can not be processed via process links.
    • This can be specified in the Database Definition or the record instance.
  • If a process request is allowed, it will be done regardless of the scan mechanism, i.e. the record does not have to be passive.

NOTES For Record links:

  • wait does NOT mean to block. It means to save state, return, and resume at the saved state when called again.
  • When a record has multiple input links the links can be processed in parallel or sequentially
  • When a record has multiple output links the links can be processed in parallel or sequentially

Record Processing Semantics

This section describes the semantics implemented by DbAccess.process.

Each record type has two sets of record support. One is implemented by RecordCommonSupport, which provides support for the fields in RecordCommon. The other is the record support for the fields in the record type, which will be called RecordSupport in this section. Each support implements method process.

One of the arguments to process is processState which has the values:

  • processCancel - Cancel any outstanding activity
  • processStart - Start processing
  • processContinue - Making additional call

process returns ProcessReturn which is one of the following:

  • processDone - Done and successful
  • processQuit - Do not do any more processing
  • processActive - Not done


There are three stages to processing a record:

  • RecordCommonSupport perform initial processing, e.g. all input links are processed.
  • RecordSupport performs its processing in collaboration with link and device support
  • RecordCommonSupport performs final processing, e.g. ouput links and process links are processed.

It is up to RecordCommonSupport to keep internal state so that it knows if it is being called for initial or final processing.

During each stage DbAccess.process can call process multiple times:

  • At the beginning of each stage process is called with state processStart. process returns one of:
    • processDone - DbAccess.process proceeds to the next stage of record processing:
      • RecordCommonSupport initial - DbAccess.process calls RecordSupport
      • RecordSupport - Calls RecordCommonSupport
      • RecordCommonSupport final - DbAccess.process does its final processing and sets record idle.
    • processActive - DbAccess.process will be called again via a call to DbAccess.processContinue
      • RecordCommonSupport must call DbAccess.processContinue
      • RecordSupport can call DbAccess.processContinue. A call to DbAccess.process will also call DbAccess.process.
    • processQuit
      • If RecordSupport returned this DbAccess.process calls RecordCommonSupport with state processCancel
      • Otherwise RecordSupport does its normal end of processing and sets the record idle.

For RecordCommonSupport the above rules allow asynchronous links. The standard RecordCommonSupport does the following:

  • initial processing means to handle the disable fields
    • A get request is made for the disable link
      • If it is synchronous RecordCommonSupport returns processAbort if the record is disable or processDone otherwise.
      • If it is asynchronous, processContinue is returned and RecordCommonSupport arranges for DbAccess.processContinue to be called when the link completes.
  • final processing means to handle the array of process links
    • If all are synchronous RecordCommonSupport returns processDone
    • If any are asynchronous, processContinue is returned and RecordCommonSupport arranges for DbAccess.processContinue to be called when the link completes.

For RecordSupport the above rules allow:

  • process can be called repeatedly. This will continue as long as it returns processActive
  • Everytime process returns processActive DbAccess.process posts monitors.
  • The record can be periodically scanned.


Links to Other Records

Links can be processed in parallel, sequentially, or a combination of these. RecordCommonSupport handles the links in RecordCommon and RecordSupport handles record specific links. The support is responsible for implementing sequential or parallel link processing. LinkSupport performs the actual I/O. The LinkSupport methods provide options specifying if the linked record should be processed and provide a callback to call when link processing completes. It is up to RecordCommonSupport or RecordSupport to call DbAccess.processContinue when all links complete.


Mutual Exclusion

V3 implemented lock sets, i.e. when a record was being processed it and all records linked via database links were locked.

Lock sets solved two Mutual Exclusion problems:

  • V3 allowed dbProcess to be called recursively.
    • process passive database links and forward links were implemented via recursive calls to DbAccess.process
    • Lock sets prevented deadly embrace problems for circular links.
  • No puts could be done to an record in a lock set while record processing is active.
    • For synchronous records this guarantees that no fields are modified except by record processing itself.
    • For asynchronous records this guarantee is not valid.


V4 does not call DbAccess.process recursively. Instead a process request is queued. The request fails if either of the following is true:

  • The record is active.
  • The record is already queued.

Queuing requests to process rather than recursively calling DbAccess.process does not necessarily cause unnecessary context switches.

Must design a way to queue process requests to the same thread that issues the requests if the link is to a local record. First thoughts is that this should be FIFO and queue emptied immediately after the requesting record returns from process.

For example if all linked records are passive and the same priority then all processing can occur without any context switches.

  • A request is made to a thread to call DbAccess.process.
    • The request is put on a queue associated with the thread.
  • Sometime later the request is dequeued and DbAccess.process is called.
    • For each link, with a request to process request, the request is put on the queue for the same thread
    • After all requests are queued DbAccess.process returns
  • The thread takes each request off the queue and calls DbAccess.process for the associated linked record
    • When all linked records finish processing a request is queued to call DbAccess.process for the original record
  • The request for the original record is removed from the queue and it's DbAccess.process is again called.
    • The record completes.

Question What about periodically scanned records? Needs thought.

This leaves the question of what should be done about mutual exclusion.

Each record instance has an associated lock maintained by dbAccess. When DbAccess.process is called it takes the lock. Before it returns it unlocks. Thus recordCommon and record support do not need to lock or unlock.

Other code that needs access to fields of a record instance must call dbLock before accessing any fields and dbUnlock after all accesses are complete.

This leaves the problem of how to access fields from two different record instances simultaneously. For example code that implements database access needs such access. Code that needs such access must call dbLockLink before accessing the linked record and dbUnlockLink after access.

dbLockLink is implemented as follows:

  • Each Record instances has a unique ordinal number
  • Assume Record X has a link to record Y
  • If the ordinal number of X is less than that of Y
    • Just call dbLock for record Y
  • If the ordinal numnber of X is greater than that of Y
    • call dbUnlock for X
    • call dbLock for Y
    • call dbLock for X

Posting Modifications

The document "V4 Design: dbdIterfaces" provides a design that allows database access to handle all posting on monitors without requiring any help from the code that modifies database fields. It can do this because fields can be modified only via an interface implemented by database access.


Fields are modified in one of two ways:

  • Changes made while record is being processed. For these posting is handled by DbAccess.process.
  • Changes by other code. For these posting is handled by dbLock/dbUnlock.

Each field of a record instance has two associated "modified" bits. One is for changes handled by DbAccess.process. The other is for changes made by dbLock/dbUnlock.

DbAccess.process posts monitors when:

  • When record support returns processActive.
  • When it finishes record processing.


Other code can only change fields between calls to dbLock/dbUnlock

  • When dbLock is called all its modify bits are false.
  • Each field modification causes the associated modify bit to be set true.
  • When dbUnlock is called it
    • posts all fields that have changed
    • sets the associated modify bits false

The following is the initial attempt to describe how monitors are implemented.

The following definitions are used:

  • monitor - A client has asked to be notified when a field value changes.
  • post - Create storage, copy the current value of the field into the storage, and pass the storage to the monitor subsystem.

Separate discussions is required for the following: 1) primitive fields, 2) string fields, 3) structured fields, and 4) array fields.

The following are just some thoughts.

  • primitive fields - No problems.
  • string fields - Memory is an issue.
    • Should there be a way to postpone posting until the monitor is ready to retrieve the value?
    • If so who decides?
  • struct fields - Memory is again an issue.
    • Structure with only primitive field or string should be posted immediately but what about array fields?
    • Who decides?
    • How?
  • array fields - memory is an issue
    • It should be possible to post small arrays of primitive type.
    • Large arrays should not be posted until monitor system is ready to accept the data.
      • It should also be possible to just notify the client that the array changed but the client must issue a read request to retrieve the data.

In any case the way monitors are posted must take into consideration the views defined in the database definition for each record.


Alarm Processing

The V4 semantics for status and severity have the following goals:

  • alarmSeverity has the same values as for V3
  • alarmStatus is a string
  • a record starts processing with alarmSeverity = "NO_ALARM" and status empty.
  • status will ONLY be posted if it has changed since the last time it was posted.
  • alarmSeverity will ONLY be posted if it has changed since the last time it was posted

The semantics, which are implemented by recordCommon, are:

  • When recordCommon is called with processStart
    • A private variable newSeverity is set to NO_ALARM
    • A private variable prevSeverity is set to alarmSeverity
  • When recordCommon completes its part of record processing
    • If newSeverity is NO_ALARM and prevSeverity has a different value
      • alarmSeverity is set to NO_ALARM
      • alarmStatus is set to empty
  • When the recordCommon.setSeverity(sevr,status) is called
    • If sevr is less than or equal to newSeverity nothing is done
    • else
      • alarmSeverity is set to sevr
      • alarmStatus is set to status
      • newSeverity is set to sevr

NOTE: alarmStatus and alarmSeverity are written by the normal method. This means that their values will be posted.


Channel Access/ Database Access field types


Overview

This section discusses how IOC database fields are accessed by channel access or via database links.

For the initial V4 implementation only the following types of data will be accessable.

  • primitive types
  • string
  • enum
  • one dimensional array of primitive or string or struct
  • struct with fields of following types:
    • primitive
    • string
    • enum
    • struct (use recursion for allowed types)
    • one dimensional array of primitive or string or struct

The dbdInterfaces document defines database field types. It also defines a subset called basic types, which consists of primitive types, string, array, and structure. For external access only basic types can be accessed. This means that structures and arrays that do not consist of basic types are not accessable outside the record. For example a DbfLink is not accessable via channel access as a DbfLink.

Non basic fields will only be available via some combination of basic types.

For example a DbfLink field will appear as a string. If a Database Definition is

    struct(calcInpLink) {
        field(link,link(in))
        field(value,float64)
    };
    
    record(xxx) {
        field(link,link(in))
        field(value,float64)
    ...
        field(inp,array(struct(calcInpLink)[]))
    ...
    }

If a client attaches to

    record.field(link)

The data will be appear in the form:

    choiceName(pvname,...)

where choiceName is the name of the link support and the arguments are the values of the dataStruct associated with the support.

Then if a client specifies the process variable:

    record.field(inp[1].link)

Then it connects to the link field of the second calcInpLink of field inp.


primitive types

This includes DbfBool, DbfOctet, DbfInt16, ... , DbfFloat64. These do not present any problems. The scalar value is transfered.

string

A string is just a UTF_8 encoded character string

DbfMenu and DbfEnum

Handled as an enum


DbfLink and DbfDevice

Both of these have the following:

  • choiceName A string that selects the link or device support.
  • dataStruct Each support has an associated struct for configuration.

How should these be made available? Perhaps:

The field appears as a string with the following syntax:

choiceName(structAssignmentList)

where structAssignmentList has the same syntax as defined in "V4 DB Record Instance Syntax"

timeStamp

This is just transfered like a struct with two fields:

  • int64 secondsSinceEpoch
  • int32 nanoSeconds


struct

The database definition syntax allows a struct to be composed of fields of any DbfType. Database access, however, will only allow access to structs with fields of the following types:

  • primitive - DbfBool,...,DbfFloat64
  • DbfString
  • DbfArray of primitive type or string
  • DbfStruct - As long as its fields are valid types

The individual fields can be accessed directly so this discussion only involves access to the entire structure.

Access will only be available to clients that have knowledge of fields within the structure. For channel access clients this means that they provide a propertyCatalog that has some subset of the fields in the structure.


array

Arrays of the following types are accessable:

  • primitive - DbfBool,...,DbfFloat64
  • DbfString
  • DbfStruct - As long as its fields are valid types

Note that arrays of structs are not accessable in the early V4 releases.

Arrays still need lots more discussion!!! The database definition syntax allow an array to be any of the basic types, i.e. DbfBool,...,DbfFloat64, DbfString, DbfArray, DbfStruct.

For the initial V4 version, database access only allows access to arrays of the following types.

  • primitive - DbfBool,...,DbfFloat64
  • DbfString
  • ???? What else

An individual element of an array of type DbfStruct can be accessed directly if it satisfies the criteria for accessing a DbfStruct.

Question: Should database Access be implemented so that record/link/device support can transfer an array in segments. Examples:

  • If the array is a circular buffer, it is presented in two segements
  • If the array is stored in hardware, e.g. a transient recorder, the array can be read from the hardware and passed to the client in segments.

If an array is available only in segments then can we prevent two clients from trying to access the same array simultaneously?

Perhaps this is a problem that must be solved by an application:

  • runControl records are one solution
  • Other solutions can be envisioned


MDArray

Not implemented if the early V4 releases.

Associated Data

The typical example is a client that asks for timeStamp, severity, status, and data. These are handled automatically as described in "Posting Modifications"