home *** CD-ROM | disk | FTP | other *** search
/ PC Press 1997 July / Sezamfile97_1.iso / msdos / clipper / nettos11.a01 / SYNCHRO / LOGREC.PRG < prev    next >
Text File  |  1993-02-23  |  14KB  |  488 lines

  1. /*
  2.  * File......: LOGREC.PRG
  3.  * Author....: Glenn Scott
  4.  * CIS ID....: 71620,1521
  5.  * Date......: $Date$
  6.  * Revision..: $Revision$
  7.  * Log file..: $Logfile$
  8.  * 
  9.  * This is an original work by Glenn Scott and is placed in the
  10.  * public domain.
  11.  *
  12.  * Modification history:
  13.  * ---------------------
  14.  *
  15.  * $Log$
  16.  *
  17.  */
  18.  
  19. #include "netto.ch"
  20. #include "ftint86.ch"
  21.  
  22. #define OP_LOG      208
  23. #define OP_LOCK     209
  24. #define OP_REL      210
  25. #define OP_RELSET   211
  26. #define OP_CLR      212
  27. #define OP_CLRSET   213
  28.  
  29. /*  $DOC$
  30.  *  $FUNCNAME$
  31.  *     FN_LOGLR()
  32.  *  $CATEGORY$
  33.  *     Synchronization
  34.  *  $ONELINER$
  35.  *     Log logical record 
  36.  *  $SYNTAX$
  37.  *
  38.  *     fn_logLR( <cRecord>, <nLockDir>, <nTimeOut> ) -> lSuccess
  39.  *
  40.  *  $ARGUMENTS$
  41.  *
  42.  *     <cRecord>   - a character string containing the name of the 
  43.  *                   "record" to be logged in the log table for
  44.  *                   possible later locking.
  45.  *
  46.  *     <nLockDir>  - Locking directive.  Only used if you're in 
  47.  *                   "extended lock mode", otherwise ignored.
  48.  *                   The following locking directives are valid:
  49.  *
  50.  *          0 = Log Record (the default).  This only logs the record in 
  51.  *              the table; it does not lock the record.
  52.  *          1 = Log and lock record with an exclusive lock.
  53.  *              This will log the record and lock it for exclusive use
  54.  *              by one user. He is the only one who can read and write
  55.  *              this record.
  56.  *          3 = Log and lock record with a shareable, read-only lock.
  57.  *              This will log a record and lock it with a read-only lock.
  58.  *              While this record is locked anyone can read it, no one can
  59.  *              update it. If you wish to update this record with a write,
  60.  *              the read-only lock must be changed to an exclusive lock.
  61.  *
  62.  *     <nTimeOut>  - Amount of time to wait for a lock in 1/18th 
  63.  *                   of a second ticks.  0 = Don't wait (the 
  64.  *                   default).  This parameter is only valid if 
  65.  *                   you're in extended lock mode (lock mode 1), 
  66.  *                   otherwise, it will be ignored.
  67.  *
  68.  *  $RETURNS$
  69.  *
  70.  *     <lSuccess>, .t. if the call succeeds, .f. if it doesn't.
  71.  *     Check FN_ERROR() for specific error codes.  The valid codes
  72.  *     are:
  73.  *
  74.  *                  0  = Success
  75.  *                254  = Timeout failure
  76.  *                255  = Failure
  77.  *
  78.  *  $DESCRIPTION$
  79.  *
  80.  *     This call places a logical record in the log table and 
  81.  *     optionally locks it.  
  82.  *
  83.  *     Logical Records are simply "names" that are locked by 
  84.  *     workstations.  The server maintains the tables for each 
  85.  *     workstation.  They don't represent actual files or 
  86.  *     physical byte ranges, but they could.  You can use these
  87.  *     logical records to lock anything of significance.
  88.  *
  89.  *     The server maintains a "log table" for each workstation.
  90.  *     To lock something, it must first be "logged".  After
  91.  *     everything is logged, then a "lock" is issued.  
  92.  *
  93.  *     You can unlock the entire set of logged records at once,
  94.  *     or just one at a time.  You can remove the logged records
  95.  *     from the table all at once, or one at a time.
  96.  *
  97.  *     This is most useful in a Clipper application if you want
  98.  *     to lock a "bunch of things", but treat the package as 
  99.  *     one lock.  For example, say an employee record consists of
  100.  *     one record in EMPLOYEE.DBF and a few records in "TIMECARD.DBF"
  101.  *     and still more records in "HISTORY.DBF."  Perhaps you want
  102.  *     to show a bunch of this data on the screen and you don't 
  103.  *     want anyone to change anything about this employee while 
  104.  *     you're working.
  105.  *
  106.  *     The "employee" is thus a "conceptual" thing.  You can't 
  107.  *     rlock() the employee, what does that mean?  Which record 
  108.  *     from which file?
  109.  *
  110.  *     Instead, you can issue a logical lock on "SCOTT, GLENN" or
  111.  *     better yet, on the employee's ID number.  
  112.  *
  113.  *     Now, if every application _cooperates_ and checks the 
  114.  *     status of the logical lock on "SCOTT, GLENN" before 
  115.  *     updating, then you in effect have created a lock on multiple
  116.  *     records in multiple databases. 
  117.  *
  118.  *     The sequence would look something like this:
  119.  *
  120.  *            fn_logLr( "SCOTT, GLENN" )
  121.  *            if fn_lkLRSet()
  122.  *               qout( "Got the lock" )
  123.  *               // Do processing here on this employee 
  124.  *            else
  125.  *               qout( "Lock failed, try later" )
  126.  *            endif
  127.  *            fn_clLRSet()      // unlock everything and clear log table
  128.  *
  129.  *
  130.  *     IMPORTANT!  There's no _real_ (i.e., physical) locking going
  131.  *     on here.  If some application does not obey the logicial 
  132.  *     locking protocol you define (i.e., lock the employee id),
  133.  *     then this won't work.  
  134.  *
  135.  *     You could implement this sort of scheme by using a .DBF and
  136.  *     thus it would not be NetWare-specific, but one advantage to
  137.  *     this technique is that if the workstation reboots, the locks
  138.  *     will eventually get cleared when the first of two things happens:
  139.  *
  140.  *         - the workstation loads the shell and attaches to 
  141.  *           the server again
  142.  *
  143.  *         - the watchdog process in the server detects the station
  144.  *           is gone and clears the connection.
  145.  *
  146.  *  $EXAMPLES$
  147.  *
  148.  *  $SEEALSO$
  149.  *     FN_RELLR() FN_CLRLR() FN_LKLRSET() FN_RELLRSE() FN_CLLRSET() FN_GETLMOD()
  150.  *  $INCLUDE$
  151.  *
  152.  *  $END$
  153.  */
  154.  
  155.  
  156. function fn_logLR( cRec, nLockDir, nTimeOut  )
  157.   local aRegs[ INT86_MAX_REGS ], lRes, nCurMode := fn_getLMod()
  158.  
  159.   default nLockDir to 0,;
  160.           nTimeOut to 0
  161.  
  162.   cRec        := iif( len( cRec ) > 99, substr( cRec, 1, 99 ), cRec )
  163.   aRegs[ AX ] := makehi( OP_LOG )
  164.   aRegs[ DS ] := I2BYTE( len( cRec ) ) + cRec
  165.   aRegs[ DX ] := REG_DS
  166.  
  167.   if nCurMode == 1
  168.      aRegs[ AX ] += nLockDir
  169.      aRegs[ BP ] := nTimeOut
  170.   endif
  171.  
  172.   lRes := ft_int86( INT21, aRegs )
  173.   if lRes
  174.      if UNSIGNED( LOWBYTE( aRegs[ AX ] ) ) # ESUCCESS
  175.         _fnSetErr( UNSIGNED( LOWBYTE( aRegs[ AX ] ) ) )
  176.         lRes := .f.
  177.      else
  178.         lRes := .t.
  179.         _fnSetErr( ESUCCESS )
  180.      endif
  181.   else
  182.      _fnSetErr( EINT86 )
  183.   endif
  184.  
  185.   return lRes
  186.  
  187.  
  188. /*  $DOC$
  189.  *  $FUNCNAME$
  190.  *     FN_RELLR()
  191.  *  $CATEGORY$
  192.  *     Synchronization
  193.  *  $ONELINER$
  194.  *     Release logical record
  195.  *  $SYNTAX$
  196.  *
  197.  *     fn_relLR( <cRecord> ) -> lSuccess
  198.  *
  199.  *  $ARGUMENTS$
  200.  *
  201.  *     <cRecord>  - the name of the "record" to unlock
  202.  *
  203.  *  $RETURNS$
  204.  *
  205.  *     <lSuccess>, .t. if the call succeeds, .f. if there was 
  206.  *     no record found (failure).
  207.  *
  208.  *  $DESCRIPTION$
  209.  *
  210.  *     This call unlocks a logical record previously logged, 
  211.  *     but does not remove it from the log table.  See the 
  212.  *     FN_CLRLR() and FN_CLLRSET() functions.
  213.  *
  214.  *     For more information logical record locking, see the 
  215.  *     description for the FN_LOGLR() function.
  216.  *
  217.  *  $EXAMPLES$
  218.  *
  219.  *  $SEEALSO$
  220.  *      FN_LOGLR() FN_CLRLR() FN_LKLRSET() FN_RELLRSE() FN_CLLRSET()
  221.  *  $INCLUDE$
  222.  *
  223.  *  $END$
  224.  */
  225.  
  226.  
  227.  
  228. function fn_relLR( cRec )
  229.   return _fnRecOp( OP_REL, cRec )
  230.  
  231.  
  232.  
  233. /*  $DOC$
  234.  *  $FUNCNAME$
  235.  *     FN_CLRLR()
  236.  *  $CATEGORY$
  237.  *     Synchronization
  238.  *  $ONELINER$
  239.  *     Clear logical record
  240.  *  $SYNTAX$
  241.  *
  242.  *     fn_clrLR( <cRecord> ) -> lSuccess
  243.  *
  244.  *  $ARGUMENTS$
  245.  *
  246.  *     <cRecord>  - the name of the "record" to unlock and remove from
  247.  *                  the workstation's log table
  248.  *
  249.  *  $RETURNS$
  250.  *
  251.  *     <lSuccess>, .t. if the call succeeds, .f. if there was 
  252.  *     no record found (failure).
  253.  *
  254.  *  $DESCRIPTION$
  255.  *
  256.  *     This call unlocks a logical record previously logged, 
  257.  *     and removes it from the workstation's log table.
  258.  *
  259.  *     For more information logical record locking, see the 
  260.  *     description for the FN_LOGLR() function.
  261.  *
  262.  *  $EXAMPLES$
  263.  *
  264.  *  $SEEALSO$
  265.  *      FN_LOGLR() FN_RELLR() FN_LKLRSET() FN_RELLRSE() FN_CLLRSET()
  266.  *  $INCLUDE$
  267.  *
  268.  *  $END$
  269.  */
  270.  
  271.  
  272. function fn_clrLR( cRec )
  273.   return _fnRecOp( OP_CLR, cRec )
  274.  
  275. /* ------------------------------------------------------------------------ */
  276.  
  277. static function _fnRecOp( xOp, cRec )
  278.   local aRegs[ INT86_MAX_REGS ], lRes := .f.
  279.  
  280.   cRec        := iif( len( cRec ) > 99, substr( cRec, 1, 99 ), cRec )
  281.   aRegs[ AX ] := makehi( xOp )
  282.   aRegs[ DS ] := I2BYTE( len( cRec ) ) + cRec
  283.   aRegs[ DX ] := REG_DS
  284.  
  285.   lRes := ft_int86( INT21, aRegs )
  286.   if lRes
  287.      if UNSIGNED( LOWBYTE( aRegs[ AX ] ) ) # ESUCCESS
  288.         _fnSetErr( UNSIGNED( LOWBYTE( aRegs[ AX ] ) ) )
  289.         lRes := .f.
  290.      else
  291.         lRes := .t.
  292.         _fnSetErr( ESUCCESS )
  293.      endif
  294.   else
  295.      _fnSetErr( EINT86 )
  296.   endif
  297.  
  298.   return lRes
  299.  
  300. /* ------------------------------------------------------------------------ */
  301.  
  302.  
  303.  
  304. /*  $DOC$
  305.  *  $FUNCNAME$
  306.  *     FN_LKLRSET()
  307.  *  $CATEGORY$
  308.  *     Synchronization
  309.  *  $ONELINER$
  310.  *     Lock logical record set
  311.  *  $SYNTAX$
  312.  *
  313.  *     fn_lkLRSet( <nTimeOut>, <nLockDir> ) -> lSuccess
  314.  *
  315.  *  $ARGUMENTS$
  316.  *
  317.  *     <nTimeOut> is the amount of time to wait for the lock.
  318.  *     If the workstation is in "compatibility mode" (lock mode 0),
  319.  *     then a value of 0 = don't wait, and any other value means
  320.  *     wait forever.  0 is the default.
  321.  *
  322.  *     If the workstation is in "extended mode" (lock mode 1), then
  323.  *     <nTimeOut> is the number of 1/18th per second ticks to wait.
  324.  *     0 = don't wait (the default).
  325.  *
  326.  *     <nLockDir> is the "locking directive" and is only significant
  327.  *     if the workstation is in extended mode (lock mode 1), otherwise
  328.  *     it is ignored.  The following are the valid locking directives:
  329.  *
  330.  *          0 = Log and lock record with an exclusive lock.
  331.  *              This will log the record and lock it for exclusive use
  332.  *              by one user. He is the only one who can read and write
  333.  *              this record.
  334.  *          1 = Lock record with a shareable lock
  335.  *          3 = Log and lock record with a shareable, read-only lock.
  336.  *              This will log a record and lock it with a read-only lock.
  337.  *              While this record is locked anyone can read it, no one can
  338.  *              update it. If you wish to update this record with a write,
  339.  *              the read-only lock must be changed to an exclusive lock.
  340.  *
  341.  *  $RETURNS$
  342.  *
  343.  *     <lSuccess>, .t. if the call succeeds, .f. if it doesn't.
  344.  *     Check FN_ERROR() for specific error codes.  Valid error codes
  345.  *     are:
  346.  *
  347.  *               0  = Success
  348.  *             254  = Timeout failure
  349.  *             255  = Failure
  350.  *
  351.  *  $DESCRIPTION$
  352.  *
  353.  *     Attempts to lock all records in the current log table.  If
  354.  *     it can't lock them all, it will fail, leaving none of them 
  355.  *     locked.  
  356.  *
  357.  *     For more information logical record locking, see the 
  358.  *     description for the FN_LOGLR() function.
  359.  *
  360.  *  $EXAMPLES$
  361.  *
  362.  *  $SEEALSO$
  363.  *      FN_LOGLR() FN_RELLR() FN_CLRLR() FN_RELLRSE() FN_CLLRSET()
  364.  *  $INCLUDE$
  365.  *
  366.  *  $END$
  367.  */
  368.  
  369.  
  370. function fn_lkLRSet( nTimeout, nLockDir )
  371.   local aRegs[ INT86_MAX_REGS ], lRes := .f., nCurMode
  372.  
  373.   default nTimeout to 0,;
  374.           nLockDir to 0
  375.  
  376.   nCurMode := fn_getLMod()
  377.  
  378.   aRegs[ AX ] := makehi( OP_LOCK )
  379.  
  380.   if nCurMode == 1
  381.      aRegs[ AX ] += nLockDir
  382.      aRegs[ BP ] := nTimeout
  383.   else
  384.      aRegs[ DX ] := iif( nTimeOut # 0, 1, 0 )
  385.   endif
  386.  
  387.   if ft_int86( INT21, aRegs )
  388.      if UNSIGNED( LOWBYTE( aRegs[ AX ] ) ) # ESUCCESS
  389.         _fnSetErr( UNSIGNED( LOWBYTE( aRegs[ AX ] ) ) )
  390.      else
  391.         lRes := .t.
  392.         _fnSetErr( ESUCCESS )
  393.      endif
  394.   else
  395.      _fnSetErr( EINT86 )
  396.   endif
  397.      
  398.   return lRes
  399.  
  400.  
  401.  
  402.  
  403. /*  $DOC$
  404.  *  $FUNCNAME$
  405.  *     FN_RELLRSE()
  406.  *  $CATEGORY$
  407.  *     Synchronization
  408.  *  $ONELINER$
  409.  *     Release logical record set
  410.  *  $SYNTAX$
  411.  *
  412.  *     fn_relLRSe() -> lSuccess
  413.  *
  414.  *  $ARGUMENTS$
  415.  *
  416.  *     None
  417.  *
  418.  *  $RETURNS$
  419.  *
  420.  *     <lSuccess>, which should be ignored since the underlying API
  421.  *     returns nothing.
  422.  *
  423.  *  $DESCRIPTION$
  424.  *
  425.  *     This call unlocks all records in the log table, but leaves
  426.  *     them in the log table (for possible later locking, for example).
  427.  *     If you want to actually delete them, use the "clear" functions
  428.  *     FN_CLRLR() and FN_CLLRSET().
  429.  *
  430.  *     For more information logical record locking, see the 
  431.  *     description for the FN_LOGLR() function.
  432.  *
  433.  *  $EXAMPLES$
  434.  *
  435.  *  $SEEALSO$
  436.  *      FN_LOGLR() FN_RELLR() FN_CLRLR() FN_LKLRSET() FN_CLLRSET()
  437.  *  $INCLUDE$
  438.  *
  439.  *  $END$
  440.  */
  441.  
  442.  
  443. function fn_relLRSe()
  444.   return _fnReq( OP_RELSET, "", "" ) == ESUCCESS
  445.  
  446.  
  447. /*  $DOC$
  448.  *  $FUNCNAME$
  449.  *     FN_CLLRSET()
  450.  *  $CATEGORY$
  451.  *     Synchronization
  452.  *  $ONELINER$
  453.  *     Clear logical record set
  454.  *  $SYNTAX$
  455.  *
  456.  *     fn_clLRSet() -> lSuccess
  457.  *
  458.  *  $ARGUMENTS$
  459.  *
  460.  *     None
  461.  *
  462.  *  $RETURNS$
  463.  *
  464.  *     <lSuccess>, which should be ignored since the underlying 
  465.  *     API returns nothing. 
  466.  *
  467.  *  $DESCRIPTION$
  468.  *
  469.  *     Unlocks all logical records in the log table and removes them
  470.  *     from the log table as well.
  471.  *
  472.  *     For more information logical record locking, see the 
  473.  *     description for the FN_LOGLR() function.
  474.  *
  475.  *  $EXAMPLES$
  476.  *
  477.  *  $SEEALSO$
  478.  *      FN_LOGLR() FN_RELLR() FN_CLRLR() FN_LKLRSET() FN_RELLRSE()
  479.  *  $INCLUDE$
  480.  *
  481.  *  $END$
  482.  */
  483.  
  484.  
  485.  
  486. function fn_clLRSet()
  487.   return _fnReq( OP_CLRSET, "", "" ) == ESUCCESS
  488.