Experimental Physics and
| |||||||||||||||
|
The RHIC control system supports aliases in the client-side directory services. We find this useful for two general categories of situations; transition between names, and multiplexing records. The former uses aliases only during the transition period. The latter makes permanent use of aliases. There are a couple situations that create the need for transitioning between names: 1) The naming standard changes, or was not correctly understood when the PVs were first named and deployed. Perhaps there are EDM screens or other applications deployed as well as the IOC. In order to change the PV names to the "correct" values, the IOC must be rebooted at the same time the new EDM screens are released (and old EDM screens reloaded). The coordination needed for this type of release often leads to "old" names living longer than desired. Using aliases, both "old" and "new" names can co-exist for a transition period while old EDM screens continue to be supported, and new screen are rolled out. 2) The mission of the PV changes over time. E.g. today the digitizer/scope/timing trigger is connected to one beam diagnostic system, but next month it is connected to a different system. Another variation on this theme is the idea of deploying/testing IOCs before the final "mission" of the H/W is specified. For RHIC we took advantage of that by deploying digitizers and function generators with "generic names" (funcGen1, funcGen2, adc1, adc2) for testing purposes, well ahead of when the PS group was ready to provide detailed wiring diagrams. As the "mission" was being finalized, we used aliases to assign mission- specific names to signals while retaining the "generic name" in case the PS group changed their minds as they wired up the signals. The idea of multiplexing records has cropped up at SNS, which is my real impetus behind thinking about aliases..... There is a "virtual scope" application in use at SNS. It is a very sophisticated application, designed for high performance, and flexible configuration. One feature of this application is that it can display signals with different time bases (sample frequency, trigger times). It does this by associating time-PVs with the signal-PV. This association is done via the PV name. I.e. if the signal-PV has a name like "LINAC_BPM_004", the trigger time PV must have a name like "LINAC_BPM_004_trigger". The trouble with this scheme is that there can be dozens of signals that all share the same time base. To support the virtual scope, there needs to be one set of time-PVs for every signal-PV, even though they all contain identical values. Of course, this could be corrected in the virtual scope by configuring it to use specific time-PVs, rather than making constructions based on the name of the PV, but then the application loses its generality. Having a set of aliases which support the virtual scope, but all of which refer to the same underlying record removes duplication and preserves generality. OK, assuming that aliases are therefore "a good thing", what are the potential pitfalls, and how could one implement them in a server-side context, rather than in a directory service? Our RHIC experience indicates that there still should be one and only one "canonical" name for a record. I.e. as silly as it sounds when you ask "record, what is your name?" you should get the same answer whether you are using an alias or not. Otherwise one cannot do meaningful save/compare/restore operations before/during/after a transition period. Existing diagnostic tools should act in a natural way. I.e. a tool which should print out all the records in an IOC should not print out duplicates just because aliases are in effect for that record. However, tools which search for records by name should work with either the canonical name or the alias. Alias should be easy to configure and manage. There must be diagnostic tools which allow one to print out the set of aliases in effect. OK, with all that in mind, is it still possible/reasonable to implement aliases on the server-side (putting aside for the moment the question of whether it is a good idea to do so)? I believe the answer is "Yes, it is trivially easy to do so." For those who care about details, I'll support this claim with detailed explanation of how I think it can be done, and even some source code with a "reference implementation" at the end of this message. For now, I'll show some examples of how it might work. Suppose there is a function called "addPvAlias" which takes two arguments. The first is the name of an existing record. The second is an alias name. Suppose there is also a diagnostic function "dbla" which prints out all the aliases on an IOC. Here's how it might work: VXWORKS>dbl BNL_test:iocsns170:Time value = 0 = 0x0 VXWORKS>dbla value = = 0x0 HOST>caget "larryTest1.NAME" larryTest2.NAME --- Invalid channel name VXWORKS> addPvAlias "BNL_test:iocsns170:Time", "larryTest1" value = 33542248 = 0x1ffd068 = dbla + 0xa8 VXWORKS>dbl BNL_test:iocsns170:Time value = 0 = 0x0 VXWORKS>dbla alias: larryTest1, name: BNL_test:iocsns170:Time value = 1 = 0x1 VXWORKS> dbpr "larryTest1" ASG: DESC: The current time DISA: 0 DISP: 0 DISV: 1 NAME: BNL_test:iocsns170:Time RVAL: 0 SEVR: NO_ALARM STAT: NO_ALARM TPRO: 0 VAL: OCT 24 10:18:52 value = 0 = 0x0 HOST>caget "larryTest1.NAME" larryTest1.NAME BNL_test:iocsns170:Time
Here is the (hacked up) source code. This module can be compiled and loaded to a running EPICS system. To properly implement aliases, similar code would be implemented with the PV directory module in IOC core. Thoughts? -- Larry #include <errno.h> #include <stdio.h> #include <stdlib.h> #include <string.h> static char *strdup(const char *s){ char *dup = (char *) malloc(strlen(s)+1); if(dup) strcpy(dup, s); return dup; } /* #include <libCom/ellLib.h> */ struct ELLNODE { struct ELLNODE *next; struct ELLNODE *previous; }; typedef struct ELLNODE ELLNODE; struct ELLLIST { ELLNODE node; int count; }; typedef struct ELLLIST ELLLIST; extern ELLNODE *ellNext (ELLNODE *pNode); /* #include <dbStatis/dbStaticPvt.h> */ struct dbRecordType; typedef struct dbRecordType dbRecordType; struct dbBase; typedef struct dbBase dbBase; extern dbBase *pdbbase; /* #include <dbStatis/dbBase.h> */ typedef struct dbRecordNode { ELLNODE node; void *precord; char *recordname; int visible; /* 0 */ }dbRecordNode; typedef struct{ ELLNODE node; dbRecordType *precordType; dbRecordNode *precnode; }PVDENTRY; static ELLLIST aliasList; /* automatically initialized to 0 */ typedef struct { ELLNODE node; const char *name; const char *alias; } aliasNode; extern PVDENTRY *dbPvdFind(dbBase *pdbbase,char *name,int lenName); extern PVDENTRY *dbPvdAdd(dbBase *pdbbase,dbRecordType *precordType,dbRecordNode *precnode); PVDENTRY *addPvAlias(char *name, const char *alias){ if(!name || !alias) { errno = -1; return NULL; } { PVDENTRY *enode = dbPvdFind(pdbbase, name, strlen(name)); if(!enode) { errno = -1; return NULL; } { dbRecordNode *recnode = (dbRecordNode *) calloc(sizeof(dbRecordNode), 1); if(!recnode) { errno = -2; return NULL; } recnode->precord = enode->precnode->precord; recnode->recordname = strdup(alias); { PVDENTRY *retval = dbPvdAdd(pdbbase, enode->precordType, recnode); if(!retval) { errno = -3; return NULL; } { aliasNode *anode = calloc(sizeof(aliasNode),1); if(!anode) { errno = -4; return NULL; } anode->name = enode->precnode->recordname; anode->alias = recnode->recordname; ellAdd(&aliasList, anode); } } } } } unsigned long dbla(void){ aliasNode *enode = (aliasNode *) aliasList.node.next; while(enode){ printf("alias: %s, name: %s\n", enode->alias, enode->name); enode = (aliasNode *) enode->node.next; } return aliasList.count; }
| ||||||||||||||
ANJ, 10 Aug 2010 |
·
Home
·
News
·
About
·
Base
·
Modules
·
Extensions
·
Distributions
·
Download
·
· Search · EPICS V4 · IRMIS · Talk · Bugs · Documents · Links · Licensing · |