Difference between revisions of "V4 Design: Record Processing"

From EPICSWIKI
Line 1: Line 1:
EPICS V4: Record Processing September 27 2005  
EPICS V4: Record Processing October 21 2005  


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


<b>UNRESOLVED ISSUES</b>
<b>UNRESOLVED ISSUES</b>
* This document will undergo LOTS of evolution1
* This document is still evolving
* Monitors
* Monitors
** How will monitor data be managed?
** How will monitor data be managed?
** Big problem is how will array data be managed?
** Big problem is how will array data be managed?
* Alarms
** How will V4 handle alarms?
* Events
** What is the V4 event model?
** What is required from the IOC database?


This document described semantics for V4 record processing that are
This document described semantics for V4 record processing that are
different than for V3.
different than for V3.
This includes the following:
This includes the following:
* Semantics for record processing
* Semantics for Database and Channel Access Links.
* Semantics for Database and Channel Access Links.
* Semantics for record processing
* Record Locking
* Record Locking
* Posting database monitors
* Posting database monitors
Line 61: Line 66:


<center>
<center>
= Goals for V4 Record Processing =
= Overview of V4 Record Processing =
  </center>
  </center>


V4 record processing has the following features.
V4 will provide something analogous to V3 dbProcess.
Some of these features were partially available in V3 but not in a
The name may be different but for now it will still be called dbProcess.
consistant way.


* All links to other records:
In V4 database access and channel access appear the same to record and
** Can request that the linked record be processed.
link support.
** Can wait until the linked record completes asynchronous processing.
Only the implementation knows the difference.
* While record support is active a record can still be processed and post monitors.
In this document the term channelAccess will mean access to a record.
* Database links are processed via queue requests rather than recursive calls to dbProcess
Thus it can mean a workstation client or a field of
* Instead of lock sets, each record instance has a lock.
a record that is a link to a record.
* Monitors are implemented by database access without help from record support


== Link Semantics ==


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


== Processing Local Links ==
* database fields
** "owned" by database not record support
** fields can only be accessed via interfaces
** support can optionally provide storage for data associated with a field
** for channelAccess all fields appear as type primitive, string, struct, array or combination thereof
* dbProcess
** is responsible for common fields
** processes synchronous linked records by queuing requests rather than recursive calls to dbProcess
** can be called an arbitrary number of times while record is active
* link
** always has associated support
** can be record link or can be something else, e.g. a link to hardware
* record link
** can request process and/or wait for asynchronous completion
** local synchronous requests queued by dbProcess
** record is active and can be processed while asynchronous links active
* struct fields
** Can have associated support which can be synchronous or asynchronous
* block
** asynchronous support can proceed in parallel
** record instance can request that all active asynchronous support complete before calling link/struct support.
* lock
** record instances are locked
** dbProcess locks before calling support
** other code can also lock
** Two records can be locked without deadlock
* monitors
** dbProcess handles monitors
** support triggers monitors by writing to fields


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.
<center>
* If the linked record does not allow link requests to cause processing the request fails.
= Database Fields =
* If a queue request is allowed then the request is handled as follows:
</center>
** The requests are queued if FIFO order
== Field Access by Support Code ==
** The queue is emptied immediately after the record containing the link returns to DbProcess
Support code can access database fields only via interfaces implemented by
** If all linked records complete synchronously the record containing the link is reprocessed before the thread processes any other records.
the IOC database.
 
Thus record fields are owned by the IOC database not by record support.
 
 
== 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 DbProcess when
Support code can register to provide storage for particular fields.
* record support returns processActive.
For example support code could implement a circular buffer for field <tt>value</tt>.
* at the end of record processing.
When some other code
request the array associated with <tt>value</tt>, the IOC database
calls the support. The support returns the first portion of the circular
buffer and the caller must make an additional call to retrieve the rest of
the circular buffer.


== Field Access by Channel Access ==


== Database Field Types ==
For V4 database access and channel access appear the same to record
instances.
It is only the code that implements link support that knows the difference.
If a linked record is local, database access is used, and, if the record
is remote, channel access.


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


* primitive types
* primitive types
Line 133: Line 148:
** array of primitive or string or struct
** array of primitive or string or struct


For other database field types, i.e. links, the database will make the field
appear as one of the above types. For example a link field will appear
as a string with syntax that matches the information associated with the link.
For example a process link will have a string something like
    processLink(pvname = 'pvname', wait = true)


<center>
<center>
= Link Semantics =
= dbProcess - Record Processing Semantics =
  </center>
  </center>


NOTES:
This section describes the semantics implemented by dbProcess.
* Link just means access to a record or field. The requester can be:
 
** A database link in a record
The following are involved in record processing
** A channel access link in a record
* dbProcess
** A channel access client PV.
** is responsible for the fields in recordCommon
* Instead of "forward link" the name "process link" is used.
** implements a queue for local records that are processed because of record links
* wait does NOT mean to wait synchronously. It means to save state, return, and resume at the saved state when called again.
** posts monitors caused by field changes during record processing
* block means to pause additional record processing until link completion. It doesd NOT mean to block synchronously. This determines if multiple links can be procesed in parallel.
* record support
** is responsible for record instance fields
** calls link/struct support via interfaces implemented by the support
* link support
** can be links to other records, to driver support, etc
** implements interfaces called by record and/or other support
* struct support
** is responsible for all fields in the struct
** implements interfaces called by record and/or other support
 
== Processing Life Cycle ==
Assume a record instance is idle, i.e. is ready to start processing.
The following sequence of events occur:
* dbProcess processes the fields in recordCommon that must be processed before record support is called
** fields that have associated support may be asynchronous
** record support will not be called until all asynchronous support in recordCommon completes
* dbProcess calls record support after recordCommon support completes and as long as record support is active
** record support handles the record specific fields
** struct and link fields can have associated support
** associated support may be asynchronous
*** record support returns to dbProcess indicating that it is active
*** record support is required to detect when asynchronous support completes
*** when processing is complete record support returns to dbProcess indicating that it is done.
* whenever record support returns to dbProcess while still active, dbProcess posts any fields that were modified.
* when record support completes
** dbProcess processes the fields in recordCommon that must be processed after record support completes.
** dbProcess posts monitors for all fields that were modified since before the last time record support was called.
* record processing is complete. The record is again idle.
 
An additional complication is that it is possible to cancel processing while
a record is active.




Links are processed as follows:
== record common ==


* Process Link: Perform the following actions
A record type can have fields that are processed by dbCommon rather than
** Request processing
record support. These fields are optional but it is expected that most record
** Optionally wait until linked record completes
types will include a standard set of fields.
** Optionally block until linked record completes
* Output Link:
** Put value
** Optionally request processing. <b>If record can not be processed should the value be changed?</b>
** Optionally wait until completion
** Optionally block until completion
* 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 request that record be processed.
*** Optionally wait for linked record to complete processing.
*** Optionally block until completion
*** Get value.


The following rules apply when a process request is made:
dbCommon will process the following fields:
* 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.


----
* before record support is called
<center>
** disable - if true NO processing will be done.
= Record Processing Semantics =
** scanDisable
</center>
*** has associated support
*** if record is scan disabled record processing completes immediately
** alarm fields
*** alarm handling is described below
* after record support completes
** processLink array
*** has associated support


This section describes the semantics implemented by DbProcess.
== record support ==


Each record type has two sets of record support.
Record support is responsible for all the fields not in dbCommon.
One is implemented by RecordCommonSupport, which provides support for the
For link and struct fields there may be associated support which
fields in RecordCommon.
may be synchronous or asynchronous. Record support communicates with
The other is the record support for the fields in the record type,
the link/struct support via interfaces that are implemented by the support.
which will be called RecordSupport in this section.
When "record support" is mentioned it can apply to either RecordCommonSupport or
RecordSupport.
Each support implements method process.


One of the arguments to process is processState which has the values:
Record support may be called multiple times by dbProcess while a record instance
is active.
One of the arguments to process is ProcessState which has the values:
* processCancel - Cancel any outstanding activity
* processCancel - Cancel any outstanding activity
* processStart - Start processing
* processStart - Start processing
Line 202: Line 236:
* processActive - Not done
* processActive - Not done


If record support returns processActive it must keep internal state so
that it knows how to handle processCancel and processContinue.


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 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
For record support the above rules allow:
it is being called for initial or final processing.
* process can be called repeatedly. This will continue as long as it returns processActive
* Everytime process returns processActive DbProcess posts monitors.
 
== Record Locking ==


During each stage DbProcess can call process multiple times:
V3 implemented lock sets in order to prevent different threads
* At the beginning of each stage process is called with state processStart. process returns one of:
from simultaneously accessing linked records.
** processDone - DbProcess proceeds to the next stage of record processing:
*** RecordCommonSupport initial - DbProcess calls RecordSupport
*** RecordSupport - Calls RecordCommonSupport
*** RecordCommonSupport final - DbProcess performs final processing and sets record idle.
** processActive
*** RecordCommonSupport must call the callback passed to process to continue processing
*** RecordSupport can call the callback passed to process when it is done.  A call to DbProcess will also call process.
** processQuit
*** If RecordSupport returned this DbProcess 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.
Instead of lock sets V4:
The standard RecordCommonSupport does the following:
* implements a per record instance lock.
* initial processing means to handle the disable fields
* defines a rule that allows two records to be locked without deadlocks
** 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 DbProcessContinue 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 DbProcessContinue to be called when the link completes.


For RecordSupport the above rules allow:
== Posting Monitors ==
* process can be called repeatedly. This will continue as long as it returns processActive
 
* Everytime process returns processActive DbProcess posts 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 record can be periodically scanned.
the posting of monitors.
 
Monitors are posted by DbProcess when
* record support returns processActive.
* at the end of record processing.
 
<center>
= link/struct Semantics =
</center>
 
Both link and struct fields can have associated support.
The support can be synchronous or asynchronous.
 
Support code implements interfaces.
Code that is responsible for a field communicates with the support via
the interface. Lets call this code the client.
 
Each link and struct field has a well defined client.
* dbProcess is the client for fields in dbCommon
* record support is the client for the other top level fields in a record
* the struct support is the client for any link or struct fields in the struct
 
Every link/struct has an associated block. The client is responsible for
implementing block. If block is true then the support will not be called
until all outstanding record activity completes.
 
<center>
= channelAccess links =
</center>
 
channelAccess link 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 workstation channel access client
 
A channelAccess link is one of the following types:
* Monitor Link
** Implemented via a monitor request on linked field
** Optionally process record containing the link when monitor value is returned.
* Input Link
** Optionally request that record be processed.
** Optionally wait for linked record to complete processing.
** Get value.
* Output Link:
** Put value
** Optionally request processing. <b>If record can not be processed should the value be changed?</b>
** Optionally wait until completion
* Process Link: Perform the following actions
** Request processing
** Optionally wait until linked record completes
 
NOTES:
* processLink is the replacement for the V3 forwardLink
* wait does NOT mean to wait synchronously. It means to save state, return, and resume at the saved state when called again.
 
 
Links are processed as follows:




== Links to Other Records ==
The following rules apply when a process request is made:
* If record is already being processed the request is just ignored
* record support can specify that links to particular fields not cause processing.
** Where should this be specified?  In the Database Definition, the record instance, or both.
** If a process request is allowed, should it be done regardless of the scan mechanism, i.e. the record does not have to be passive?


Links can be processed in parallel, sequentially, or a
combination of these.
RecordCommonSupport handles the links in RecordCommon and RecordSupport
handles record specific links. Record 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 DbProcessContinue
when all links complete.


----
----
Line 269: Line 338:




V4 does not call DbProcess recursively. Instead a process request is queued.
V4 does not call dbProcess 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
dbProcess itself manages the queue , which is FIFO.
does not necessarily cause unnecessary context switches.
When record support returns the first entry in the queue is processed.
In addition if link or struct support completes before the queue
is empty, a request to process the record containing the link/struct will
be added to the same queue.
Thus if a set of synchronous records are processed they will complete processing
without any context switch.


<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
all processing can occur without any context switches.
* 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, with a request to 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.
<b>Question</b> What about periodically scanned records? Needs thought.
<b>Question</b> What about periodically scanned records? Needs thought.


Line 302: Line 358:
1) a global lock, and 2) A per record instance lock.
1) a global lock, and 2) A per record instance lock.


The global lock, which is implemented by DbAccess,  must be taken
The global lock must be taken
whenever the structure of the database is modified. Examples are
whenever the structure of the database is modified. Examples are
1) adding new record types, 2) adding new record instances, and 3) modifying
1) adding new record types, 2) adding new record instances, and 3) modifying
database links. Global locks are not discussed further in this document.
database links. Global locks are not discussed further in this document.


Each record instance has an associated lock maintained by dbAccess.
Each record instance has an associated lock.
When DbProcess is called it takes the lock.
When dbProcess 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 record support does not need to lock or unlock.


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


This leaves the problem of how to access fields from two different record
This leaves the problem of how to access fields from two different record
Line 340: Line 396:
interface implemented by database access.
interface implemented by database access.


 
dbProcess posts monitors when:
Fields are modified in one of two ways:
* Changes made while record is being processed. For these posting is handled by DbProcess.
* 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 DbProcess. The other is for changes made
by dbLock/dbUnlock.
 
DbProcess posts monitors when:
* When record support returns processActive.
* When record support returns processActive.
* When it finishes record processing.
* When it finishes record processing.


 
How to implement monitors must be decided.
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.


----
----
Line 392: Line 406:
= Alarm Processing =
= Alarm Processing =
  </center>
  </center>
<b>Question</b> Will V4 alarm handling be different than V3? If so this section
may be meaningless.


The V4 semantics for status and severity have the following goals:
The V4 semantics for status and severity have the following goals:
Line 449: Line 466:
For external access only basic types can be accessed.
For external access only basic types can be accessed.
This means that structures and arrays that do not consist of basic types
This means that structures and arrays that do not consist of basic types
are not accessable outside the record. For example a DbfLink is
are not accessablevia clannelAccess. For example a DbfLink is
not accessable via channel access as a DbfLink.
not accessable via channel access as a DbfLink.


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

Revision as of 14:25, 21 October 2005

EPICS V4: Record Processing October 21 2005


Overview

UNRESOLVED ISSUES

  • This document is still evolving
  • Monitors
    • How will monitor data be managed?
    • Big problem is how will array data be managed?
  • Alarms
    • How will V4 handle alarms?
  • Events
    • What is the V4 event model?
    • What is required from the IOC database?

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

  • Semantics for record processing
  • Semantics for Database and Channel Access Links.
  • 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.


Overview of V4 Record Processing

V4 will provide something analogous to V3 dbProcess. The name may be different but for now it will still be called dbProcess.

In V4 database access and channel access appear the same to record and link support. Only the implementation knows the difference. In this document the term channelAccess will mean access to a record. Thus it can mean a workstation client or a field of a record that is a link to a record.


V4 record processing has the following features.

  • database fields
    • "owned" by database not record support
    • fields can only be accessed via interfaces
    • support can optionally provide storage for data associated with a field
    • for channelAccess all fields appear as type primitive, string, struct, array or combination thereof
  • dbProcess
    • is responsible for common fields
    • processes synchronous linked records by queuing requests rather than recursive calls to dbProcess
    • can be called an arbitrary number of times while record is active
  • link
    • always has associated support
    • can be record link or can be something else, e.g. a link to hardware
  • record link
    • can request process and/or wait for asynchronous completion
    • local synchronous requests queued by dbProcess
    • record is active and can be processed while asynchronous links active
  • struct fields
    • Can have associated support which can be synchronous or asynchronous
  • block
    • asynchronous support can proceed in parallel
    • record instance can request that all active asynchronous support complete before calling link/struct support.
  • lock
    • record instances are locked
    • dbProcess locks before calling support
    • other code can also lock
    • Two records can be locked without deadlock
  • monitors
    • dbProcess handles monitors
    • support triggers monitors by writing to fields


Database Fields

Field Access by Support Code

Support code can access database fields only via interfaces implemented by the IOC database. Thus record fields are owned by the IOC database not by record support.

Support code can register to provide storage for particular fields. For example support code could implement a circular buffer for field value. When some other code request the array associated with value, the IOC database calls the support. The support returns the first portion of the circular buffer and the caller must make an additional call to retrieve the rest of the circular buffer.

Field Access by Channel Access

For V4 database access and channel access appear the same to record instances. It is only the code that implements link support that knows the difference. If a linked record is local, database access is used, and, if the record is remote, channel access.

V4 allows channel 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

For other database field types, i.e. links, the database will make the field appear as one of the above types. For example a link field will appear as a string with syntax that matches the information associated with the link. For example a process link will have a string something like

   processLink(pvname = 'pvname', wait = true)

dbProcess - Record Processing Semantics

This section describes the semantics implemented by dbProcess.

The following are involved in record processing

  • dbProcess
    • is responsible for the fields in recordCommon
    • implements a queue for local records that are processed because of record links
    • posts monitors caused by field changes during record processing
  • record support
    • is responsible for record instance fields
    • calls link/struct support via interfaces implemented by the support
  • link support
    • can be links to other records, to driver support, etc
    • implements interfaces called by record and/or other support
  • struct support
    • is responsible for all fields in the struct
    • implements interfaces called by record and/or other support

Processing Life Cycle

Assume a record instance is idle, i.e. is ready to start processing. The following sequence of events occur:

  • dbProcess processes the fields in recordCommon that must be processed before record support is called
    • fields that have associated support may be asynchronous
    • record support will not be called until all asynchronous support in recordCommon completes
  • dbProcess calls record support after recordCommon support completes and as long as record support is active
    • record support handles the record specific fields
    • struct and link fields can have associated support
    • associated support may be asynchronous
      • record support returns to dbProcess indicating that it is active
      • record support is required to detect when asynchronous support completes
      • when processing is complete record support returns to dbProcess indicating that it is done.
  • whenever record support returns to dbProcess while still active, dbProcess posts any fields that were modified.
  • when record support completes
    • dbProcess processes the fields in recordCommon that must be processed after record support completes.
    • dbProcess posts monitors for all fields that were modified since before the last time record support was called.
  • record processing is complete. The record is again idle.

An additional complication is that it is possible to cancel processing while a record is active.


record common

A record type can have fields that are processed by dbCommon rather than record support. These fields are optional but it is expected that most record types will include a standard set of fields.

dbCommon will process the following fields:

  • before record support is called
    • disable - if true NO processing will be done.
    • scanDisable
      • has associated support
      • if record is scan disabled record processing completes immediately
    • alarm fields
      • alarm handling is described below
  • after record support completes
    • processLink array
      • has associated support

record support

Record support is responsible for all the fields not in dbCommon. For link and struct fields there may be associated support which may be synchronous or asynchronous. Record support communicates with the link/struct support via interfaces that are implemented by the support.

Record support may be called multiple times by dbProcess while a record instance is active. 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

If record support returns processActive it must keep internal state so that it knows how to handle processCancel and processContinue.


For record support the above rules allow:

  • process can be called repeatedly. This will continue as long as it returns processActive
  • Everytime process returns processActive DbProcess posts monitors.

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 DbProcess when

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

link/struct Semantics

Both link and struct fields can have associated support. The support can be synchronous or asynchronous.

Support code implements interfaces. Code that is responsible for a field communicates with the support via the interface. Lets call this code the client.

Each link and struct field has a well defined client.

  • dbProcess is the client for fields in dbCommon
  • record support is the client for the other top level fields in a record
  • the struct support is the client for any link or struct fields in the struct

Every link/struct has an associated block. The client is responsible for implementing block. If block is true then the support will not be called until all outstanding record activity completes.

channelAccess links

channelAccess link 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 workstation channel access client

A channelAccess link is one of the following types:

  • Monitor Link
    • Implemented via a monitor request on linked field
    • Optionally process record containing the link when monitor value is returned.
  • Input Link
    • Optionally request that record be processed.
    • Optionally wait for linked record to complete processing.
    • Get value.
  • Output Link:
    • Put value
    • Optionally request processing. If record can not be processed should the value be changed?
    • Optionally wait until completion
  • Process Link: Perform the following actions
    • Request processing
    • Optionally wait until linked record completes

NOTES:

  • processLink is the replacement for the V3 forwardLink
  • wait does NOT mean to wait synchronously. It means to save state, return, and resume at the saved state when called again.


Links are processed as follows:


The following rules apply when a process request is made:

  • If record is already being processed the request is just ignored
  • record support can specify that links to particular fields not cause processing.
    • Where should this be specified? In the Database Definition, the record instance, or both.
    • If a process request is allowed, should it be done regardless of the scan mechanism, i.e. the record does not have to be passive?



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.

dbProcess itself manages the queue , which is FIFO. When record support returns the first entry in the queue is processed. In addition if link or struct support completes before the queue is empty, a request to process the record containing the link/struct will be added to the same queue. Thus if a set of synchronous records are processed they will complete processing without any context switch.

Question What about periodically scanned records? Needs thought.

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

For V4 there will be two locks associated with the IOC database: 1) a global lock, and 2) A per record instance lock.

The global lock must be taken whenever the structure of the database is modified. Examples are 1) adding new record types, 2) adding new record instances, and 3) modifying database links. Global locks are not discussed further in this document.

Each record instance has an associated lock. When dbProcess is called it takes the lock. Before it returns it unlocks. Thus record support does not need to lock or unlock.

Other code that needs access to fields of a record instance must lock before accessing any fields and unlock 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.

dbProcess posts monitors when:

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

How to implement monitors must be decided.


Alarm Processing

Question Will V4 alarm handling be different than V3? If so this section may be meaningless.

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 accessablevia clannelAccess. 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

Both of these have the following:

  • choiceName A string that selects the link support.
  • dataStructName 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 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.