[comp.os.vms] more re: sharing files

MANION@CURIE.RM.FCCC.EDU (Frank Manion) (08/05/88)

   Mike Temkin writes:
>Does anyone out there know how to make a file multi-accessible (readwise)
>in VMS?  There must be a way since I would think that the help file is
>that way.  Any help is appreciated.

Yes, there is a way:
Most high level languages allow an option on the OPEN statements of
the language of the form READONLY and/or SHARING, SHARED, etc.
In Fortran:

(1)	OPEN(1,file='file.dat',status='old',readonly)

will open a file for reading allowing sharing with other readers;

(2)	OPEN(1,file='file.dat',status='old',readonly,shared)

will open a file for reading allowing sharing with other readers and
potentially other shared writers.

(3)	OPEN(1,file='file.dat',status='old',shared)

will open a file for reading and writing allowing sharing with other
readers/writers which have fab$m_shrput set;

(4)      OPEN(1,file='file.dat',status='old')

will open a file and disallow any sharing...

A later writer replies...
>   Any program that opens a file to write to it will almost certainly open
>it for exclusive access.  Programs written in high level languages 
>sometimes default to exclusive access.  From VAX Fortran, for example, the
>OPEN statement must include the keyword SHARED, else the file is opened for
>exclusive access, (FAB$B_SHR=FAB$V_NIL).

Sorry my friend, but you are wrong. VAX Fortran simply leaves the FAB$B_SHR
field initialized to zero in this case, which forces the RMS default to
be set. The defaults, taken from page 5-26 of the V4 RMS ref. manual are as
follows:
  "* If the FAB$B_FAC field is set or defaulted to FAB$V_GET, the
     SHR filed defaults to SHRGET". 
  "* If the FAB$B_FAC field is set or defaulted to either PUT, DEL, UPD,
     or TRN, the FAB$B_SHR field defaults to FAB$V_NIL."
Thus if the user opens a file without the SHARED keyword, but with the
READONLY keyword, GET sharing will be allowed. Files opened for create
or write access will default to NIL sharing, as stated above.

But don't take my word for it; for that matter, don't take DEC's either.
At the end of this message is a Fortran program which peeks into the
FAB fields an prints out what they are for each type of open. It also
can be used to see how different types of OPENs interact.

Now for a very important point: on normal sequential files (i.e. most text
files) RMS only takes out record locks on files openned with SHRPUT, SHRDEL
or SHRUPD sharing. This means that record locking overhead is ***AVOIDED*** on
opens which only declare SHRGET. OPEN statement (1) above, only opens the
file for SHRGET. OPEN statements (2) and (3) declare SHRPUT, SHRDEL, and
SHRUPD, as well as SHRGET. Thus, openning a file from fortran with
READONLY,SHARED will result in substantially slower access then a READONLY
open. On a 11/785 the READONLY,SHARED form is about 500 percent slower
than a READONLY open. If all you want to do is allow multiple readers
to access a file, the READONLY open (i.e. SHRGET) is the way to go.

Opening a file unnecessarily with READONLY,SHARED has another problem:
It will 1) allow a shared writter access to the file, which 2) may
cause the original program to encounter RECORD-LOCK ERRORS! This may
break programs written before V4.3 when full sharing of sequential files
was implemented. Prior to V4.3, READONLY,SHARED had to be specified to
allow file sharing of sequential files.

The moral of the above story is (on V4.3 and above) to only declare that
type of sharing which you need. Failing to heed this warning may result
in 1) slower execution, and additional burden on programming to correctly
handle possible record locking.

c***********************************************************************
c program TESTLOCK.FOR to test accessability of files with different
c fortran sharing options.

c Note that this program appears to bear out the RMS reference manual
c with record to unspecified (i.e. 0 or defaulted) values for the fab$b_fac
c and fab$b_shr fields of the FAB.

c At prompt, type:
c type RS to open readonly, shared file
c type R  to open readonly  file
c type S  to open file shared
c type anything else to open file without readonly and shared keywords.

c the program attempts to open TESTLOCK.FOR multiple times with the
c different sharing options requested.

      implicit      none

      integer*4      AccessTest
      external       AccessTest
      integer*4      status
      integer*4      a(1000)
      integer*4      i,n, lun
      character*3    opt
      logical*4      is_there

      lun = 7
      do while(.true.)
        lun = lun + 1
        write(5,'(a)')'$Options: '
        read(5,'(a)',end=500)opt
        call str$upcase(opt,opt)
        if( is_there(opt,'RS') ) then
          write(6,'(a)')' Readonly, shared'
          open(lun,file='testlock.for',status='old',shared,
     1        readonly,useropen=AccessTest)
          read(lun,900)(a(i),i=1,n)
        else if( is_there(opt,'S') ) then
          write(6,'(a)')' shared'
          open(lun,file='testlock.for',status='old',shared,
     1     useropen=AccessTest)
          read(lun,900)(a(i),i=1,n)
        else if(is_there(opt,'R')) then
          write(6,'(a)')' Readonly'
          open(lun,file='testlock.for',status='old',readonly,
     1     useropen=AccessTest)
          read(lun,900)(a(i),i=1,n)
        else
          write(6,'(a)')' not readonly and not shared'
          open(lun,file='testlock.for',status='old',
     1     useropen=AccessTest)
          read(lun,900)(a(i),i=1,n)
          end if
        end do

500   stop

900   format(q,a)

      end

      logical*4 function is_there(a,b)
      character*(*) a,b

      is_there = .true.
      i = 1
      do while(is_there.and.i.le.len(b))
        is_there = is_there .and. (index(a,b(i:i)).ne.0)
        i = i + 1
        end do
      return
      end

      integer*4 function AccessTest( fab, rab, lun )

      implicit      none

c fetch needed definitions of system data structures.

      include            '($fabdef)'      ! FAB definitions
      include            '($rabdef)'      ! RAB definitions

c formal parameter declarations

      record            /fabdef/      fab      ! Declare fab as a FAB
      record            /rabdef/      rab      ! Declare rab as a RAB
      integer*4      lun

c declare local constants and data types

      integer*4       sys$open, sys$connect
      byte             shr, fac

c open file and connect the stream.

      fac = fab.fab$b_fac
      shr = fab.fab$b_shr
      AccessTest = sys$open(fab)
      if(AccessTest) then
        AccessTest = sys$connect(rab)
        end if

c print the options. The defaults if fac is 0 are found on page
c 5-10 under subheading fab$v_get of the "VAX Record Management
c Services reference manual" (version 4.0 edition)
c " Get is the default access if fab$b_fac field is not specified
c   or the del,upd,or trn sharing options are set in fab$b_shr."
c Note that fab$b_fac = 0 does not imply NIL sharing!

c Note: this routine assumes the file is being OPENED, not CREATED.
c       the defaults are slightly different in this case.

      write(6,'(a,z2.2,a,$)')' Accessability(',fac,'):'
      if ( ( fac .and. fab$m_put ) .ne. 0 ) write(6,'(a,$)')'+ put'
      if ( ( fac .and. fab$m_get ) .ne. 0 ) write(6,'(a,$)')'+ get'
      if ( ( fac .and. fab$m_del ) .ne. 0 ) write(6,'(a,$)')'+ del'
      if ( ( fac .and. fab$m_upd ) .ne. 0 ) write(6,'(a,$)')'+ upd'
      if ( ( fac .and. fab$m_trn ) .ne. 0 ) write(6,'(a,$)')'+ trn'
      if ( ( fac .and. fab$m_bio ) .ne. 0 ) write(6,'(a,$)')'+ bio'
      if ( ( fac .and. fab$m_bro ) .ne. 0 ) write(6,'(a,$)')'+ bro'
      if ( ( fac .and. fab$m_exe ) .ne. 0 ) write(6,'(a,$)')'+ exe'
      if ( fac .eq. 0 .or. (shr .and. (fab$m_shrdel.or.
     1       fab$m_shrupd.or.fab$m_trn) .ne. 0) ) then
         if ( ( fac .and. fab$m_get ) .eq. 0) then
           write(6,'(a,$)')'+ defaults to get'
           end if
        end if

c the defaults if shr is 0 are fond on page 5-26 of the
c above referenced manual at the end of the section on Fab$b_shr
c "if the fab$b_fac field is set or defaulted to GET, the SHR field
c  defaults to SHRGET. If the fab$b_fac field is set or defaulted
c  to either PUT, DEL, UPD, or TRN, the SHR field defaults to
c  NIL."

      write(6,'(a,z2.2,a,$)')'       Sharing(',shr,'):'
      if ( ( shr .and. fab$m_nil ) .ne. 0 ) write(6,'(a,$)')'+ nil'
      if ( ( shr .and. fab$m_shrput ) .ne. 0 ) write(6,'(a,$)')'+ put'
      if ( ( shr .and. fab$m_shrget ) .ne. 0 ) write(6,'(a,$)')'+ get'
      if ( ( shr .and. fab$m_shrdel ) .ne. 0 ) write(6,'(a,$)')'+ del'
      if ( ( shr .and. fab$m_shrupd ) .ne. 0 ) write(6,'(a,$)')'+ upd'
      if ( ( shr .and. fab$m_upi ) .ne. 0 ) write(6,'(a,$)')'+ upi'
      if ( ( shr .and. fab$m_mse ) .ne. 0 ) write(6,'(a,$)')'+ mse'
      if ( shr .eq. 0 ) then
        if ( (fac.and.(fab$m_put.or.fab$m_del.or.fab$m_upd
     1      .or.fab$m_trn)) .ne. 0) then
            write(6,'(a,$)')'+ defaults to nil'
c      nil sharing takes precedence over all other forms, thus
c      it would be confusing to say defaults to get and defaults to nil
        else if ( fac .eq. 0 .or. (fac.and.fab$m_get).ne.0 ) then
          write(6,'(a,$)')'+ defaults to get'
          end if
        end if

      return
      end