home *** CD-ROM | disk | FTP | other *** search
- NUMBER : 3089
- PRODUCT : BDE
- VERSION : All
- OS : Windows
- DATE : August 15, 1996
-
- TITLE : Sharing Violation Error with Paradox Tables
-
- Description:
- This error is most commonly caused by a "Lock File
- Contention". A lock file contention occurs in this
- situation:
- One user, User "A", is accessing one or more Paradox
- tables in a directory. "A" is closing the last table
- in the directory. The BDE detects that "A" is the last
- program accessing the tables in the directory. Since
- "A" is the last user on the tables, the .LCK files are
- going to be deleted. At this time, User "B" attempts
- to open a table in the same directory as "A" (who is
- about to delete the .LCK files). "B" opens the .LCK
- files to write an entry to. This is when "A" tries to
- delete the .LCK files that "B" has now opened. This
- will cause a sharing violation on the .LCK files. The
- share violation usually occurs on the last client to
- close the table.
-
- Solutions:
- One solution is to override Windows error routines
- and ignore the error. In all test cases, then a
- sharing violation occurs, the table is still opened or
- closed.
- Another solution is to keep the .LCK files in the
- table's directories. If the BDE detects that more
- than one Application (or Session) is using the tables,
- it will not attempt to delete the .LCK files therefore
- solving the problem.
-
- 1) C / C++ / Delphi / Paradox:
- Use the Windows API SetErrorMode passing the
- SEM_FAILCRITICALERRORS constant. You would only need
- to do this before opening and closing a table and
- then check to see if the table has actually been open.
- Please see Routine 1a and 1b below for a basic Delphi
- (any version) routine or Routine 2a and 2b for
- C / C++ routines. Paradox users will need to call
- into the appropriate DLL where SetErrorMode resides.
-
-
- 2) C / C++ / Delphi / Paradox:
- Create a "Dummy" Paradox table in each table
- directory that the application uses. Example:
- executable is in directory C:\MyProg. This executable
- opens tables in two different directories - C:\MyTables
- and D:\TempTbl. Create a "Dummy" table with the
- Database Desktop, or any other Paradox table creation
- utility, in both the C:\MyTables and D:\TempTbl
- directories. Once the tables are created, create an
- application that opens each of the "Dummy" programs at
- startup. Leave this program running at all times. If
- the executable can be placed on a server machine, like
- Windows NT, that is optimal. In this scenario,
- whenever applications are accessing the data, the
- server also has the "Dummy" tables open.
-
-
- 3) C / C++ / Delphi / Paradox:
- Leave at least one table during the entire
- application's run. Open one table during startup and
- close the table at exit. You could even open a
- "Dummy" table described above.
-
-
- 4) C / C++ / Delphi:
- Use DbiAcqPersistTableLock BDE function to create
- a lock on a table that does not exist (Delphi or C++
- only).
-
- Syntax:
- (Delphi) Check(DbiAcqPersistTableLock(Database1.Handle,
- 'NoTable1.DB', szPARADOX));
-
- (C++) rslt = DbiAcqPersistTableLock(hDb, 'NoTable2.DB',
- szPARADOX);
-
- NOTE: Each instance of the application must have a
- unique, non-existent table name or an attempt to place
- a lock in the directory will fail. If this method is
- used, an algorithm must be used to guarantee a unique
- table name. If a user can only run one instance of
- the program at a time, the network user name can be
- used as a table name.
-
-
- 5) Paradox ObjectPAL:
- If your application is apt to cause .LCK files to be
- created and deleted often, the easiest (and least
- resource-intensive) way to prevent this is to place a
- read lock on a non-existent table within the directory
- when your application starts up. (Paradox allows us
- to place semaphore locks on tables that don't exist.)
- Since read locks don't conflict with one another, all
- users can do this, and the net result will be that the
- .LCK file will not be deleted until the last user
- exits the system.
-
- Syntax:
- At program startup:
- Table.attach("DummyTbl.db")
- Table.lock(Read)
-
- At program shut-down:
- Table.unlock(Read)
- Table.unAttach
-
-
-
- NOTES - These are observations on the problem:
-
- 1) The problem does not seem to occur on NT
- workstation machines. The application can be either
- 16 or 32 bit. SetErrorMode seems to work with both
- cases.
-
-
- 2) The problem is more likely to occur if the
- network protocol is netBEUI. If possible use netBIOS
- or IPX/SPX.
-
-
- 3) Constant closing and opening of tables will cause
- this error more often.
-
-
- 4) The error most commonly occurs on the close of the
- table, not the open. In this situation the closing
- application tries to delete files that another
- application now has open.
-
-
- Example Routines:
-
- Routine 1a) (Delphi Table Open Routine)
- ----------------------------------------
- procedure TForm1.OpenTable(MyTable: TTable);
- begin
- { Set the error mode to ignore critical errors }
- SetErrorMode(SEM_FAILCRITICALERRORS);
- { Open the table and check if it was opened }
- MyTable.Open;
- if MyTable.Active = False then
- begin
- { Retry opening the table }
- MyTable.Open;
- { If an error happens again, raise an exception }
- if MyTable.Active = False then
- raise
- EDatabaseError.Create('Error Opening table');
- end;
- { Set the error mode back to the default }
- SetErrorMode(0);
- end;
-
-
- Routine 1b) (Delphi Table Close Routine)
- -----------------------------------------
- procedure TForm1.CloseTable(MyTable: TTable);
- begin
- { Set the error mode to ignore critical errors }
- SetErrorMode(SEM_FAILCRITICALERRORS);
- { Close the table and check if it was closed }
- MyTable.Close;
- if MyTable.Active = True then
- begin
- { Retry closing the table }
- MyTable.Close;
- { If an error happens again, raise an exception }
- if MyTable.Active = True then
- raise
- EDatabaseError.Create('Error Closing table');
- end;
- { Set the error mode back to the default }
- SetErrorMode(0);
- end;
-
-
- Routine 2a) (C / C++ Table Open Routine)
- -----------------------------------------
- DbiResult OpenTable(hDBIDb hTmpDb, pCHAR szTblName,
- phDBICur phTmpCur)
- {
- DBIResult rslt;
-
- // Set the error mode to ignore critical errors
- SetErrorMode(SEM_FAILCRITICALERRORS);
-
- // Open the table and check if it was opened
- rslt = DbiOpenTable(hTmpDb, szTblName, NULL,
- NULL, NULL, NULL, dbiREADWRITE, dbiOPENSHARED,
- xltFIELD, FALSE, NULL, phTmpCur);
- if (rslt != DBIERR_NONE)
-
- // Retry opening the table
- rslt = DbiOpenTable(hTmpDb, szTblName, NULL,
- NULL, NULL, NULL, dbiREADWRITE, dbiOPENSHARED,
- xltFIELD, FALSE, NULL, phTmpCur);
-
- // Set the error mode back to the default
- SetErrorMode(0);
- return rslt;
- }
-
-
- Routine 2b) (C / C++ Table Open Routine)
- ----------------------------------------
- DBIResult CloseTable(phDBICur phTmpCur)
- {
- DBIResult rslt;
-
- // Set the error mode to ignore critical errors
- SetErrorMode(SEM_FAILCRITICALERRORS);
-
- // Close the table and check if it was closed
- rslt = DbiCloseCursor(phTmpCur);
- if (rslt != DBIERR_NONE)
-
- // Retry closing the table
- rslt = DbiCloseCursor(phTmpCur);
-
- // Set the error mode back to the default
- SetErrorMode(0);
- return rslt;
- }
-
-
- DISCLAIMER: You have the right to use this technical information
- subject to the terms of the No-Nonsense License Statement that
- you received with the Borland product to which this information
- pertains.
-