Difference between revisions of "V4 Design: Record Processing"

From EPICSWIKI
Line 1: Line 1:
= EPICS V4: Record Processing =
= EPICS V4: Record Processing =
August 23 2005  
August 24 2005  


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


The main motive for the V4 semantics related to record and link processing is
The main motive for the V4 semantics related to record and link processing is
Line 38: Line 40:


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


Line 47: Line 49:
V4 record processing is designed to make data acquisition easier.
V4 record processing is designed to make data acquisition easier.
Both input and output links can wait for record processing.
Both input and output links can wait for record processing.
This must be done, however, without record support blocking.
This is done, however, without record support blocking.
If blocking makes it easier to implement record support,
If blocking makes it easier to implement record support,
then the support can spawn a separate thread that does block.
then the support can spawn a separate thread that does block.
Line 61: Line 63:
V4 record processing has the following features not available in V3:
V4 record processing has the following features not available in V3:


*All links to other records:
* All links to other records:
** Can request that the linked record be processed.
** Can request that the linked record be processed
** Can wait until the linked record completes processing
** Can wait until the linked record completes processing
* While record support is active a record can still be processed and post monitors.
* Database links are not processed via recursive calls to dbProcess
* Database links are not processed via recursive calls to dbProcess
* Lock sets do not exist. Instead each record instance has a lock.
* Lock sets do not exist. Instead each record instance has a lock.
* Monitors are implemented by database access without requiring calls to post monitors.
* Monitors are implemented by database access without help from record support
* Channel Access and Database Access can access arrays and structures
* Channel Access and Database Access can access arrays and structures


=== V4 Link Semantics ===
=== Link Semantics ===


NOTES:
The link semanics are similar for 1) database links, 2) channel access links,
*Instead of "forward link" the name "process link" is used.
and 2) a channel access process variable link.
*Unless stated otherwise, the features described in this section apply to both database and channel access links.
All provide the ability to request processing and to wait until processing completes.
 
Links are processed as follows:
 
* Input Link from another record
** Optionally request that record be processed.
** Optionally wait for record to complete processing.
** Get value.
** When a record has multiple input links the links can be processed in parallel or sequentially
* Output Link to another record
** Put value
** Optionally request that the record be processed.
*** For database links, if the record is already active or already queued for processing the link request fails.
*** What about channel access links? Perhaps they should also fail.
** Optionally wait until record completes processing.
** When a record has multiple output links the links can be processed in parallel or sequentially
* Process Link
** request processing
** Optionally wait until record completes processing.
** When a record has multiple output links the links can be processed in parallel or sequentially


The following rules are for links which request processing.
=== Processing Database Links ===
 
* If record is already being processed the request is ignored.
** Should the record containing the link have a warning message?
* Can a record declare that links to particular fields not cause processing?
** If yes than this should be declared by a record instance
** If yes than record containing link should have warning message
* Can a record declare that it can not be processed via process links?
** If yes than this should be declared by a record instance
** If yes than record containing link should have warning message
 
NOTE: wait does NOT mean to block. It means to save state, return,
and resume at the saved state when called again.
 
=== Processing V4 Database Links ===


In V3 record linked via database links are processed via recursive calls to
In V3 record linked via database links are processed via recursive calls to
Line 114: Line 84:
when a link requests processing:
when a link requests processing:


# If the record is active or already queued the request is ignored. Should the requester receive an error?
# 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 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.
# If neither 1) or 2) are true than the record is queued for processing.


Question. Should these same rules apply to Channel Access Links?


=== Record Locking ===
=== Record Locking ===
Line 136: Line 105:
All changes to database fields are done via an interface implemented by database
All changes to database fields are done via an interface implemented by database
access. This makes it possible for database access to handle monitors.
access. This makes it possible for database access to handle monitors.
Monitors are posted by dbProcess when
* record support is called with and returns processActive.
* during the last part of record processing.


=== Database Field Types ===
=== Database Field Types ===
Line 151: Line 125:


Later releases will provide access to more complicated fields.
Later releases will provide access to more complicated fields.
<center>
== Link Semantics ==
</center>
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:
* Input Link: Perform the following actions
** Optionally request that record be processed.
** Optionally wait for record to complete processing.
** 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:
* If record is already being processed the request fails.
* A record can specify that links to particular fields not cause processing.
** This can be specified in the Database Definition or the record instance.
* 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




----
----
<center>
<center>
== V4 Record Processing ==
== Record Processing ==
  </center>
  </center>


Line 183: Line 200:
* Record support can implement substates. For example the sequence record keeps state about which link set it is processing.
* 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.
* Individual record types might use only a subset of the above states.
* V3 link instances had attributes like CA, CP, CPP. For V4 these should be something like:
* 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.
** 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
** wait - a request to wait until it has processed all it's input links
Line 202: Line 219:
** prepare the record for processing
** prepare the record for processing
** set state = processStart and goto processInputActive
** set state = processStart and goto processInputActive
* processInputActive call iocRecord
* processInputActive
** If iocRecord returns processInputActive return
** call iocRecord
** If iocRecord returns processActive set processState = processStart and goto processActive
*** If iocRecord returns processInputActive return
** If iocRecord returns processDone goto processDone
*** If iocRecord returns processActive set processState = processStart and goto processActive
* processActive - Call record support
*** If iocRecord returns processDone goto processDone
** If record support returns processActive return
* processActive
** If record support returns processDone goto processOutputActive
** Call record support
* processOutputActive - Call iocRecord
*** If record support returns processActive post monitors and return
** If iocRecord returns processOutputActive return
*** If record support returns processDone goto processOutputActive
** If iocRecord returns processDone goto state processDone
* processOutputActive
** Call iocRecord
*** If iocRecord returns processOutputActive return
*** If iocRecord returns processDone goto processDone
* processDone
* processDone
** Perform final processing - See below for details.
** Perform final processing - See below for details.
Line 231: Line 251:


=== processState processIdle ===
=== processState processIdle ===
When dbProcess is called with processIdle then it:
When dbProcess is called with processIdle it:
* prepares record for processing
* prepares record for processing
* calls iocRecord with processState processStart
* calls iocRecord with processStart


=== processState processStart ===
=== processState processStart ===


When iocRecord is called with processState processStart it:
When iocRecord is called with processStart it:
* initializes severity. See Alarm Processing for details.
* prepares for alarmStatus and alarmSeverity. See Alarm Processing for details.
* initializes status. See Alarm Processing for details.
* starts processing it's input links. Details are given below.
* starts processing it's input links. Details are given below.
* returns with processState one of the following:
* returns with processState one of the following:
** processInputActive - dbProcess will again call iocRecord.
** processInputActive - dbProcess returns and when called again calls iocRecord.
** processActive - dbProcess will set processState to processStart and call record support.
** processActive - dbProcess calls record support with processStart.
** processDone - dbProcess will complete processing. record support will NOT be called and iocRecord will not be called to handle output links
** processDone - dbProcess completes processing. record support will NOT be called and iocRecord will not be called to handle output links


When record support is called with processState processStart it:
When record support is called with processStart it:
* starts processing
* starts processing
* returns with processState one of the following:
* returns with processState one of the following:
** processActive - dbProcess will again call record support
** processActive - dbProcess returns and when called again calls record support.
** processDone - dbProcess will call iocRecord to process it's output links
** processDone - dbProcess calls iocRecord with processDone.


=== processState processInputActive ===  
=== processState processInputActive ===  
Only iocRecord is called with or returns this state.


This state means that one or more input links handled by iocRecord have not
This state means that one or more input links handled by iocRecord have not
Line 259: Line 280:
When iocRecord detects that all it's input
When iocRecord detects that all it's input
links have completed, it sets processState = processActive and returns.
links have completed, it sets processState = processActive and returns.
dbProcess will then call record support to start processing.
dbProcess calls record support to start processing.


iocRecord can also return processDone, In this case dbProcess will just
iocRecord can also return processDone, In this case dbProcess will just
Line 266: Line 287:


=== processState processActive ===  
=== processState processActive ===  
Only record support is called with this state.
iocRecord and record support can return this state.


This state means that record support and associated device support
This state means that record support and associated device support
Line 277: Line 301:


When record support is called it returns one of:
When record support is called it returns one of:
* processActive - dbProcess will post monitors and call record support again when it is called.
* processActive - dbProcess post monitors and returns. When it is called again it calls record support.
* processDone - dbProcess will call iocRecord to process it's output links
* processDone - dbProcess calls iocRecord with processDone.


=== processState processOutputActive ===  
=== processState processOutputActive ===  
Only iocRecord is called with or returns this state.


This state means that one or more output links handled by iocRecord have not
This state means that one or more output links handled by iocRecord have not
Line 287: Line 313:


=== processState processDone ===
=== processState processDone ===
When iocRecord is called with processDone it starts processing its output links.
It returns either
* processOutputActive - record support returns and when called again calls iocRecord with processOutputActive.
* processDone - dbProcess does final processing as described next.


When both record support and iocRecord have reported that they are done,
When both record support and iocRecord have reported that they are done,
Line 295: Line 326:
* If the request to process the record included a callback, the callback is called.
* If the request to process the record included a callback, the callback is called.
* If other record completion callback requests are present, call them.
* If other record completion callback requests are present, call them.
* Monitors???
* post monitors
* ???
* ???
* The record is set idle.
* The record is set idle.
Line 305: Line 336:
support handles record specific input links. The support is responsible for
support handles record specific input links. The support is responsible for
implementing sequential or parallel link processing.
implementing sequential or parallel link processing.
Link support doeso the actual I/O. The Link support methods
Link support performs the actual I/O. The Link support 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
Line 367: Line 398:
* If the ordinal number of X is less than that of Y
* If the ordinal number of X is less than that of Y
** Just call dbLock for record Y
** Just call dbLock for record Y
* If the ordinal numnber of X is less than that of Y
* If the ordinal numnber of X is greater than that of Y
** call dbUnlock for X
** call dbUnlock for X
** call dbLock for Y
** call dbLock for Y
Line 386: Line 417:
Monitors are handled as follows:
Monitors are handled as follows:


Each field of a record instance has an associated "modified" bit.


Monitors will be handled via the calls to dbLock/dbUnlock.
Monitors are implemented in two ways:
* When dbLock is called all modify bits are false.
* Changes made while record is being processed. These are handled by dbProcess.
* Changes by other code. These are handled by dbLock/dbUnlock.
 
Each field of a record instance has two associated "modified" bits.
One is for changes handled by dbProcess. The other is for changes made
by dbLock/dbUnlock.
 
 
The first way is changes made while a record is being processed.
dbProcess 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.
* Each field modification causes the associated modify bit to be set true.
* When dbUnlock is called it
* When dbUnlock is called it
** posts all fields that have changed
** posts all fields that have changed
** sets the associated modify bit false
** sets the associated modify bit false
Note that when dbLockLink is called it may call dbUnlock, which will
post any changes. Record suppot needs to be aware that this can happen.
If it want fields to update only at the end of record processing,
it can keep private variables and then modify fields at the end of record
processing.


The following is the initial attempt to describe how monitors are implemented.
The following is the initial attempt to describe how monitors are implemented.
Line 426: Line 465:
** Large arrays should not be posted until monitor system is ready to accept the data.
** 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.
*** 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.


----
----
Line 434: Line 476:
The V4 semantics for status and severity have the following goals:
The V4 semantics for status and severity have the following goals:
* alarmSeverity has the same values as for V3
* alarmSeverity has the same values as for V3
* status is independent of alarmSeverity, i.e. it just reports a status.
* alarmStatus is a string
* a record starts processing with alarmSeverity = "NO_ALARM" and status empty.
* 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.
* 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
* alarmSeverity will ONLY be posted if it has changed since the last time it was posted


The semantics that implement these goals are:
The semantics, which are implemented by iocRecord, are:


* When a record starts processing the following is done
* When iocRecord is called with processStart
** The status is saved in previousStatus
** A private variable newSeverity is set to NO_ALARM
** status is set to an empty string
** A private variable prevSeverity is set to alarmSeverity
** The alarmSeverity is saved in previousAlarmSeverity
* When iocRecord completes its part of record processing
** alarmSeverity is set to NO_ALARM
** If newSeverity is NO_ALARM and prevSeverity is not NO_ALARM
* When the status is modified
*** alarmSeverity is set to NO_ALARM
** If the new status is different than previousStatus
*** alarmStatus is set to empty
*** previousStatus is set to the new status
*** the status modified bit is set
* When the alarmSeverity is modified
** If the new alarmSeverity is different than previousAlarmSeverity
*** previousAlarmSeverity is set to the new alarmSeverity
*** the alarmSeverity modified bit is set
* When monitors are posted
** If status != previousStatus the status modified bit is set
** If alarmSeverity != previousAlarmSeverity the alarmSeverity modified bit is set
**  If the status modified bit is set the status is posted and previousStatus set equal to status
**  If the alarmSeverity modified bit is set the alarmSeverity is posted and previousAlarmSeverity set equal to alarmSeverity


Question: What is done by iocRecord and what by database access?
* When the iocRecord.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.
----
----
<center>
<center>
Line 548: Line 586:
=== timeStamp ===
=== timeStamp ===


This is just transfered a struct with two fields:
This is just transfered like a struct with two fields:
* int64 secondsSinceEpoch
* int64 secondsSinceEpoch
* int32 nanoSeconds
* int32 nanoSeconds


=== struct ===
=== struct ===
Line 570: Line 609:
is contains fields of the above types.
is contains fields of the above types.


The following two forms of access available.
Access will only be available to clients that have knowledge of
 
fields within the structure. For channel access clients this means that
* Access by clients that have knowledge of the structure -
they provide a propertyCatalog that has some subset of the fields in the structure.
** In this case the data is transfered as a sequence of field values.
** Do this via dataAccess property catalog.
* Access by clients that do not know about the structure -
**The structure value is presented as a string that has the structAssignmentList syntax defined in "V4 DB Record Instance Syntax"
** Is this needed? Can we just require that client know property catalog?




Line 589: Line 623:


Arrays still need lots more discussion!!!
Arrays still need lots more discussion!!!
Database Access is 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.
The database definition syntax allow an array to be any of the basic types, i.e. DbfBool,...,DbfFloat64, DbfString, DbfArray, DbfStruct.
The database definition syntax allow an array to be any of the basic types, i.e. DbfBool,...,DbfFloat64, DbfString, DbfArray, DbfStruct.


Database access only allows access to arrays of the following types.
For the initial V4 version, database access only allows access to arrays of the following types.
* primitive - DbfBool,...,DbfFloat64
* primitive - DbfBool,...,DbfFloat64
* DbfString
* DbfString
Line 603: Line 632:
directly if it satisfies the criteria for accessing a DbfStruct.
directly if it satisfies the criteria for accessing a DbfStruct.


How to prevent two clients from trying to access the same array simultaneously?
Question: Should database Access be implemented so that record/link/device support can transfer an array in segments. Examples:
* Does it matter?
* If the array is a circular buffer, it is presented in two segements
* If application wants to allow only single access let the apllication solve the problem
* 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.
** runControl records are one solution
 
** Other solutions can be envisioned
If an array is available only in segments then can we
* Conclusion is that this is not a database responsibility
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




Line 620: Line 653:
and data.
and data.


These will be handled automatically as described in "Posting Modifications"
These is handled automatically as described in "Posting Modifications"

Revision as of 19:52, 24 August 2005

EPICS V4: Record Processing

August 24 2005


Overview

This document described the semantics for V4 record processing. 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 provided led to many of the ideas described below. This wiki is a companion to the wiki "V4 Design: dbdInterfaces".

The main motive for the V4 semantics related to record and link processing is that the 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:

  • All links to other records:
    • Can request that the linked record be processed
    • Can wait until the linked record completes processing
  • While record support is active a record can still be processed and post monitors.
  • Database links are not processed via recursive calls to dbProcess
  • Lock sets do not exist. Instead each record instance has a lock.
  • Monitors are implemented by database access without help from record support
  • Channel Access and Database Access can access arrays and structures

Link Semantics

The link semanics are similar for 1) database links, 2) channel access links, and 2) a channel access process variable link. All provide the ability to request processing and to wait until processing completes.

Processing Database Links

In V3 record 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 when a link requests processing:

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


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.

All changes to database fields are done via an interface implemented by database access. This makes it possible for database access to handle monitors.

Monitors are posted by dbProcess when

  • record support is called with and returns processActive.
  • during the last part of record processing.


Database Field Types

The early releases of V4 will support Channel Access and Database Access to the following types of fields:

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

Later releases will provide access to more complicated fields.

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:

  • Input Link: Perform the following actions
    • Optionally request that record be processed.
    • Optionally wait for record to complete processing.
    • 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:

  • If record is already being processed the request fails.
  • A record can specify that links to particular fields not cause processing.
    • This can be specified in the Database Definition or the record instance.
  • 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

This section describes the semantics implemented by dbProcess.

dbProcess maintains a variable processState which is passed to iocRecord and to record support and can also be returned by them.

V4 Processing States

processState is passed to process (iocRecord or record support) and is also returned by process. processState defines the states:

processIdle
record is not being processed
processStart
processing is starting
processInputActive
iocRecord is waiting for input links to complete
processActive
record support is waiting for completion of record specific activity
processOutputActive
iocRecord 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


dbProcess

The functionality described in this section will be divided between iocCore and iocRecord. iocRecord is the V4 successor to the V3 dbCommon. For V4 it is a separate software component.

NOTE: FLNK (forward link) is replaced by an array of process links.


When dbProcess is called the action it takes depends on processState.

  • processIdle
    • prepare the record for processing
    • set state = processStart and goto processInputActive
  • processInputActive
    • call iocRecord
      • If iocRecord returns processInputActive return
      • If iocRecord returns processActive set processState = processStart and goto processActive
      • If iocRecord 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 iocRecord
      • If iocRecord returns processOutputActive return
      • If iocRecord 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
    • iocRecord processes all its input links and then
    • Record support stays active as long as desired and then
    • iocRecord 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 iocRecord, some by record support, and some by link support.

processState processIdle

When dbProcess is called with processIdle it:

  • prepares record for processing
  • calls iocRecord with processStart

processState processStart

When iocRecord 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 iocRecord.
    • processActive - dbProcess calls record support with processStart.
    • processDone - dbProcess completes processing. record support will NOT be called and iocRecord 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 iocRecord with processDone.

processState processInputActive

Only iocRecord is called with or returns this state.

This state means that one or more input links handled by iocRecord have not completed.

When iocRecord detects that all it's input links have completed, it sets processState = processActive and returns. dbProcess calls record support to start processing.

iocRecord 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 iocRecord finds the record disabled.

processState processActive

Only record support is called with this state. iocRecord 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 iocRecord with processDone.

processState processOutputActive

Only iocRecord is called with or returns this state.

This state means that one or more output links handled by iocRecord have not completed.


processState processDone

When iocRecord is called with processDone it starts processing its output links. It returns either

  • processOutputActive - record support returns and when called again calls iocRecord with processOutputActive.
  • processDone - dbProcess does final processing as described next.

When both record support and iocRecord 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 can be processed in parallel, sequentially, or a combination of these. iocRecord handles the links in iocRecord and record support handles record specific input links. The support is responsible for implementing sequential or parallel link processing. Link support performs the actual I/O. The Link support 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 iocRecord or record support to again call dbProcess when all input links complete.

If is OK for dbProcess to be called multiple times while links are being processed.


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 dbProcess
    • 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 dbProcess 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.

Note that if all linked records are passive and the same priority then all processing can occur without any context switches. The following occurs:

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

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

Each record instance has an associated lock maintained by dbAccess. When dbProcess is called it takes the lock. Before it returns it unlocks. Thus iocRecord 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

dbUnlockLink just calls dbUnlock for the linked record.


Posting Modifications

The document "V4 Design: dbdIterfaces" provides a design that allows dbAccess to detect all changes to fields of an IOC record.

dbAccess handles all posting on monitors without requiring any help from the code that modifies database fields.

Monitors are handled as follows:


Monitors are implemented in two ways:

  • Changes made while record is being processed. These are handled by dbProcess.
  • Changes by other code. These are handled by dbLock/dbUnlock.

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


The first way is changes made while a record is being processed. dbProcess 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 bit 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.


The problem is how to implement posting. 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 iocRecord, are:

  • When iocRecord is called with processStart
    • A private variable newSeverity is set to NO_ALARM
    • A private variable prevSeverity is set to alarmSeverity
  • When iocRecord completes its part of record processing
    • If newSeverity is NO_ALARM and prevSeverity is not NO_ALARM
      • alarmSeverity is set to NO_ALARM
      • alarmStatus is set to empty
  • When the iocRecord.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

NOTE: This topic still needs lots of discussion.

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. (Later releases of V4 will support more complicated types.)

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


Other fields will only be available as one of the above types. For example a DbfLink field will appear as a string.

Since the field view provides access to subfields of a field and to elements of an array, information from every DbfType is available.

As an example if a Database Definition is

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

Then if a client attaches to process variable:

    record.field(calcInpLink[1].link)

The data will be presented as a string describing the link. An example of a string value is:

    acro9440(0,5)


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 the 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

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

Note that if a struct contains a field that is a DbfStruct, the struct field itself will not be available but it is possible to access the DbfStruct field itself if it is contains fields of the above types.

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

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

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 is handled automatically as described in "Posting Modifications"