home *** CD-ROM | disk | FTP | other *** search
/ CD Shareware Magazine 1996 December / CD_shareware_12-96.iso / WIN / Programa / TI3089.ZIP / TI3089.ASC < prev   
Encoding:
Text File  |  1996-08-15  |  7.6 KB  |  239 lines

  1.    NUMBER  :  3089
  2.   PRODUCT  :  BDE
  3.   VERSION  :  All
  4.        OS  :  Windows
  5.      DATE  :  August 15, 1996                         
  6.  
  7.     TITLE  :  Sharing Violation Error with Paradox Tables
  8.  
  9. Description:
  10.    This error is most commonly caused by a "Lock File
  11. Contention".  A lock file contention occurs in this 
  12. situation:
  13.    One user, User "A", is accessing one or more Paradox
  14. tables in a directory.  "A" is closing the last table 
  15. in the directory.  The BDE detects that "A" is the last 
  16. program accessing the tables in the directory.  Since 
  17. "A" is the last user on the tables, the .LCK files are 
  18. going to be deleted.  At this time, User "B" attempts 
  19. to open a table in the same directory as "A" (who is 
  20. about to delete the .LCK files).  "B" opens the .LCK 
  21. files to write an entry to.  This is when "A" tries to 
  22. delete the .LCK files that "B" has now opened.  This 
  23. will cause a sharing violation on the .LCK files.  The 
  24. share violation usually occurs on the last client to 
  25. close the table.
  26.  
  27. Solutions:
  28.    One solution is to override Windows error routines 
  29. and ignore the error.  In all test cases, then a 
  30. sharing violation occurs, the table is still opened or 
  31. closed.
  32.    Another solution is to keep the .LCK files in the 
  33. table's directories.  If the BDE detects that more 
  34. than one Application (or Session) is using the tables, 
  35. it will not attempt to delete the .LCK files therefore 
  36. solving the problem.
  37.  
  38. 1)  C / C++ / Delphi / Paradox:
  39. Use the Windows API SetErrorMode passing the 
  40. SEM_FAILCRITICALERRORS constant.  You would only need 
  41. to do this before opening and closing a table and 
  42. then check to see if the table has actually been open.  
  43. Please see Routine 1a and 1b below for a basic Delphi 
  44. (any version) routine or Routine 2a and 2b for 
  45. C / C++ routines.  Paradox users will need to call
  46. into the appropriate DLL where SetErrorMode resides.
  47.  
  48.  
  49. 2)  C / C++ / Delphi / Paradox:
  50. Create a "Dummy" Paradox table in each table 
  51. directory that the application uses. Example:  
  52. executable is in directory C:\MyProg.  This executable 
  53. opens tables in two different directories - C:\MyTables 
  54. and D:\TempTbl.  Create a "Dummy" table with the
  55. Database Desktop, or any other Paradox table creation 
  56. utility, in both the C:\MyTables and D:\TempTbl 
  57. directories.  Once the tables are created, create an 
  58. application that opens each of the "Dummy" programs at 
  59. startup.  Leave this program running at all times.  If 
  60. the executable can be placed on a server machine, like 
  61. Windows NT, that is optimal.  In this scenario,  
  62. whenever applications are accessing the data, the 
  63. server also has the "Dummy" tables open.  
  64.  
  65.  
  66. 3)  C / C++ / Delphi / Paradox:
  67. Leave at least one table during the entire 
  68. application's run.  Open one table during startup and 
  69. close the table at exit.  You could even open a 
  70. "Dummy" table described above.
  71.  
  72.  
  73. 4)  C / C++ / Delphi:
  74. Use DbiAcqPersistTableLock BDE function to create 
  75. a lock on a table that does not exist (Delphi or C++ 
  76. only).  
  77.  
  78. Syntax: 
  79. (Delphi) Check(DbiAcqPersistTableLock(Database1.Handle, 
  80. 'NoTable1.DB', szPARADOX));  
  81.  
  82. (C++) rslt = DbiAcqPersistTableLock(hDb, 'NoTable2.DB', 
  83. szPARADOX);
  84.  
  85. NOTE: Each instance of the application must have a 
  86. unique, non-existent table name or an attempt to place 
  87. a lock in the directory will fail.  If this method is 
  88. used, an algorithm must be used to guarantee a unique 
  89. table name.  If a user can only run one instance of 
  90. the program at a time, the network user name can be 
  91. used as a table name.
  92.  
  93.  
  94. 5)  Paradox ObjectPAL:
  95. If your application is apt to cause .LCK files to be 
  96. created and deleted often, the easiest (and least 
  97. resource-intensive) way to prevent this is to place a 
  98. read lock on a non-existent table within the directory 
  99. when your application starts up.  (Paradox allows us 
  100. to place semaphore locks on tables that don't exist.)  
  101. Since read locks don't conflict with one another, all
  102. users can do this, and the net result will be that the 
  103. .LCK file will not be deleted until the last user 
  104. exits the system.
  105.  
  106. Syntax: 
  107. At program startup:
  108. Table.attach("DummyTbl.db")
  109. Table.lock(Read)
  110.  
  111. At program shut-down:
  112. Table.unlock(Read)
  113. Table.unAttach
  114.  
  115.  
  116.  
  117. NOTES - These are observations on the problem:
  118.  
  119. 1)  The problem does not seem to occur on NT 
  120. workstation machines.  The application can be either 
  121. 16 or 32 bit.  SetErrorMode seems to work with both 
  122. cases.
  123.  
  124.  
  125. 2)  The problem is more likely to occur if the 
  126. network protocol is netBEUI.  If possible use netBIOS 
  127. or IPX/SPX.
  128.  
  129.  
  130. 3)  Constant closing and opening of tables will cause 
  131. this error more often.
  132.  
  133.  
  134. 4)  The error most commonly occurs on the close of the 
  135. table, not the open.  In this situation the closing 
  136. application tries to delete files that another 
  137. application now has open.
  138.  
  139.  
  140. Example Routines:
  141.  
  142. Routine 1a)  (Delphi Table Open Routine)
  143. ----------------------------------------
  144. procedure TForm1.OpenTable(MyTable: TTable);
  145. begin
  146.   { Set the error mode to ignore critical errors }
  147.   SetErrorMode(SEM_FAILCRITICALERRORS);
  148.   { Open the table and check if it was opened }
  149.   MyTable.Open;
  150.   if MyTable.Active = False then
  151.   begin
  152.     { Retry opening the table }
  153.     MyTable.Open;
  154.     { If an error happens again, raise an exception }
  155.     if MyTable.Active = False then
  156.       raise 
  157.         EDatabaseError.Create('Error Opening table');
  158.   end;
  159.   { Set the error mode back to the default }
  160.   SetErrorMode(0);
  161. end;
  162.  
  163.  
  164. Routine 1b)  (Delphi Table Close Routine)
  165. -----------------------------------------
  166. procedure TForm1.CloseTable(MyTable: TTable);
  167. begin
  168.   { Set the error mode to ignore critical errors }
  169.   SetErrorMode(SEM_FAILCRITICALERRORS);
  170.   { Close the table and check if it was closed }
  171.   MyTable.Close;
  172.   if MyTable.Active = True then
  173.   begin
  174.     { Retry closing the table }
  175.     MyTable.Close;
  176.     { If an error happens again, raise an exception }
  177.     if MyTable.Active = True then
  178.       raise 
  179.         EDatabaseError.Create('Error Closing table');
  180.   end;
  181.   { Set the error mode back to the default }
  182.   SetErrorMode(0);
  183. end;
  184.  
  185.  
  186. Routine 2a)  (C / C++ Table Open Routine)
  187. -----------------------------------------
  188. DbiResult OpenTable(hDBIDb hTmpDb, pCHAR szTblName,
  189.                phDBICur phTmpCur)
  190. {
  191.    DBIResult   rslt;
  192.  
  193.    // Set the error mode to ignore critical errors
  194.    SetErrorMode(SEM_FAILCRITICALERRORS);
  195.  
  196.    // Open the table and check if it was opened
  197.    rslt = DbiOpenTable(hTmpDb, szTblName, NULL, 
  198.       NULL, NULL, NULL, dbiREADWRITE, dbiOPENSHARED, 
  199.       xltFIELD, FALSE, NULL, phTmpCur);
  200.    if (rslt != DBIERR_NONE)
  201.  
  202.       // Retry opening the table
  203.       rslt = DbiOpenTable(hTmpDb, szTblName, NULL, 
  204.          NULL, NULL, NULL, dbiREADWRITE, dbiOPENSHARED, 
  205.          xltFIELD, FALSE, NULL, phTmpCur);
  206.  
  207.    // Set the error mode back to the default
  208.    SetErrorMode(0);
  209.    return rslt;
  210. }
  211.  
  212.  
  213. Routine 2b) (C / C++ Table Open Routine)
  214. ----------------------------------------
  215. DBIResult CloseTable(phDBICur phTmpCur)
  216. {
  217.    DBIResult   rslt;
  218.  
  219.    // Set the error mode to ignore critical errors
  220.    SetErrorMode(SEM_FAILCRITICALERRORS);
  221.  
  222.    // Close the table and check if it was closed
  223.    rslt = DbiCloseCursor(phTmpCur);
  224.    if (rslt != DBIERR_NONE)
  225.  
  226.       // Retry closing the table
  227.       rslt = DbiCloseCursor(phTmpCur);
  228.  
  229.    // Set the error mode back to the default
  230.    SetErrorMode(0);
  231.    return rslt;
  232. }
  233.  
  234.  
  235. DISCLAIMER: You have the right to use this technical information
  236. subject to the terms of the No-Nonsense License Statement that
  237. you received with the Borland product to which this information
  238. pertains.
  239.