|SAS/SHARE User's Guide|
The following sections discuss considerations, including locking implications, that are specific to SAS programming:
|DATA Step Processing|
The following example shows the effect of implicit locking when two clients, John and Maria, share access to the SAS data set FUEL in their respective sessions at the same time.
While Maria is editing data set DATALIB.FUEL in an FSEDIT window, John can use a DATA step to read DATALIB.FUEL by using a SET, a MERGE, or an UPDATE statement. He cannot create a new version of DATALIB.FUEL, but he can create other data sets or written reports:
data _null_; set datalib.fuel; file report ps=24 n=ps; ... run; data composit; merge datalib.fuel fuel96; run;
If John uses a SET statement to read DATALIB.FUEL, he cannot specify the options KEY= or POINT= unless he overrides the member-level control. By default, member-level control is required for a SET statement that includes one of those options:
data pressure; set fuel (keep=fuel maxpress); set datalib.fuel (cntllev=rec) key=fuel; ... run;
If John uses an UPDATE statement or a SET or a MERGE statement with a BY statement to read DATALIB.FUEL, he may want to specify member-level control to ensure that the data set remains properly ordered while his DATA step runs:
data composit; merge datalib.fuel (cntllev=mem) fuel96; by grade; run;
Although John cannot create a new version of DATALIB.FUEL, he can use a DATA step with a MODIFY statement to update it:
data datalib.fuel; modify datalib.fuel; if (grade='03N') then do; grade='3Np'; revised=today(); replace datalib.fuel; end; run;
When this DATA step tries to update an observation that Maria is editing in her FSEDIT window, the replace operation for that observation fails because Maria has the observation locked. This failure causes the DATA step to terminate immediately. However, any observations that are updated prior to the termination retain their updated values.
For applications that update shared data with the MODIFY statement, it is very important to include error-checking statements to prevent this kind of failure and premature termination. The return codes from the read operation (performed by the MODIFY statement) and the update operations (performed by the REPLACE, the OUTPUT, and the REMOVE statements) are available in the automatic variable _IORC_. For example, the preceding DATA step would be more complete if it looked like this:
data datalib.fuel; modify datalib.fuel; if (grade='03N') then if (_iorc_ = 0) then /* read with lock for update successfully */ do; grade='3Np'; revised=today(); replace datalib.fuel; end; else put 'Observation' _n_ '(fuel' fuel ') was not replaced.'; run;
The DATA step checks the value of _IORC_ to determine if a warning or error condition occurred while reading an observation from DATALIB.FUEL. If the observation was read successfully, it can be replaced. Otherwise, a message is written to the SAS log to record the failure and to identify the observation that was not updated.
To check for specific values of _IORC_, use the SYSRC macro. For example,
data datalib.fuel; modify datalib.fuel; if (grade='03N') then if (_iorc_ = 0) then /* read with lock for update successfully */ do; grade='3Np'; revised=today(); replace datalib.fuel; end; else if (_iorc_ = %sysrc(_SWNOUPD)) then put 'Observation' _n_ '(fuel' fuel ') was not replaced.'; else put 'Observation' _n_ '(fuel' fuel ') read with rc' _iorc_; run;
For complete information about the MODIFY statement, see SAS Language Reference: Dictionary. For information about the SYSRC macro and _IORC_ return code checking, see SAS Macro Language: Reference.
|Using Ordered Data in a Shared Environment|
Many applications that use SAS data sets require the data to be stored in sorted order according to the value (or values) of one or more variables. In Version 6 of SAS software, indexes can be defined on one or more variables in a SAS data file to help SAS applications maintain the order of the observations in SAS data sets. This prevents the application from having to sort the entire data set with each use. Because SAS determines if indexes are used in its processing, indexes must be defined carefully to avoid inadvertently causing less efficient SAS performance. For more information about defining indexes, see the chapter about SAS files in SAS Language Reference: Concepts.
Shared SAS data sets are frequently ordered according to one or more variables. Programmers who develop SAS applications that use shared, ordered data need to be aware of the two ways in which shared data can be used:
Concurrent-update applications generally involve several users who repeat the following type of cycle: position to an observation, update data, position to another observation, update that data, and so on. If these users specify a WHERE clause to position to the next observation and the variable (or variables) in the WHERE clause are indexed, indexing can improve the server's performance by minimizing the server's effort to search for each observation. Because the concurrent-update users' access pattern tends to be random rather than sequential, processing with an index generally does not increase the amount of physical I/O that is performed by the server for each user.
On the other hand, reporting applications frequently read the data of one or more shared data sets - capturing the data as they are at that moment - and develop a report from that data. If the application uses a BY statement so that the data is returned in sorted order, the server's performance can vary greatly while the data is being read. The server's performance can vary due to a number of factors, such as whether the BY variable is indexed and whether options are added to the BY statement that cause the index not to be used.
Because of this performance concern, it is recommended that the server read the data in its physical, unsorted order, and then sort the data in the SAS process that was used to produce the report. One way to do this is by using the SORT procedure to read the data in physical order through the server and to produce a sorted data file in your library WORK.
proc sort data=datalib.fuel out=fuel; by area; run;
Another way is to use the SQL procedure to create a temporary SAS data file and to sort it using an ORDER BY clause.
proc sql; create table fuel as select * from datalib.fuel order by area;
Defining more indexes than are necessary on shared SAS data sets can increase the amount of memory that a server needs. Avoid defining indexes that will not be used by your applications when they access shared data sets through a server.
|Using Non-Interactive SAS Applications in a Shared Environment|
Shared data is sometimes maintained by SAS applications that use the batch or non-interactive methods of processing. As in interactive applications, these non-interactive applications update SAS files through a server. Such applications may be written as one or more SCL programs or as a combination of DATA steps and procedures.
Generally, it is important that no other users access any of the shared SAS files while this type of application runs. To ensure uninterrupted access, use either the LOCK statement or the SCL LOCK function (for SCL programs) at the beginning of your program to gain exclusive access to the SAS files that your application uses. After your program has completed, be sure to release your exclusive access to these SAS files so that other users can access them.
The example that follows uses a two-step SAS program that gains exclusive access to a specific SAS file by using the LOCK statement. First, the program opens a shared SAS data set and copies to another data set data that has not been updated for one month. Then, the program deletes the data from the original data set. After the program has completed processing, it clears the exclusive lock.
%libdef(datalib); /* Try to get exclusive access to the SAS data set. */ lock datalib.fuel; /* Did we succeed? If not, go no further. */ data _null_; x=symget('SYSLCKRC'); put x=hex16.; if (x^='0') then endsas; run; /* Copy any observations that have not been updated in */ /* 30 days to a different, locally-accessed library. */ data permlib.a; drop now; retain now; if (_N_=1) then now=today(); set datalib.fuel; if (accdate<(now- 30)) then output permlib.a; run; /* Now delete those observations from the master file. */ proc sql; delete from datalib.fuel where (accdate<(today()- 30)); quit; /* All done! Release the lock on the master file. */ lock datalib.fuel clear;
Top of Page
Copyright 1999 by SAS Institute Inc., Cary, NC, USA. All rights reserved.