We have found out during our SQLite implementation that SQLite databases will get locked without fully disposing any Sqlite Commands and Sqlite DataReaders.
As as result we are modifying our Try..Catch..End Try with Using...End Using.
Any datareaders within the Using..End Using are disposed after closing.
Commands are disposed with the End Using.
However many of our Try..Catch..End Try includes the "Exit Function" within the Catch portion.
Is there a way within the Using..End Using to Catch an exception, deal with it, exit the function, while still being able to dispose with the command like End Using does?
We are using a combination of c# and vb.net within our application/libraries
The documentation says that
the Using block guarantees disposal of the resources, no matter how you exit the block.
Related
We are using the SQLite.NET PCL in a Xamarin application.
When putting the database under pressure by doing inserts into multiple tables we are seeing BUSY exceptions being thrown.
Can anyone explain what the difference is between BUSY and LOCKED? And what causes the database to be BUSY?
Our code uses a single connection to the database created using the following code:
var connectionString = new SQLiteConnectionString(GetDefaultConnectionString(),
_databaseConfiguration.StoreTimeAsTicks);
var connectionWithLock = new SQLiteConnectionWithLock(new SQLitePlatformAndroid(), connectionString);
return new SQLiteAsyncConnection (() => { return connectionWithLock; });
So our problem turned out to be that although we had ensured within the class we'd written that it only created a single connection to the database we hadn't ensured that this class was a singleton, therefore we were still creating multiple connections to the database. Once we ensured it was a singleton then the busy errors stopped
What I've take from this is:
Locked means you have multiple threads trying to access the database, the code is inherently not thread safe.
Busy means you have a thread waiting on another thread to complete, your code is thread safe but you are seeing contention in using the database.
...current operation cannot proceed because the required resources are locked...
I am assuming that you are using async-style inserts and are on different threads and thus an insert is timing out waiting for the lock of a different insert to complete. You can use synchronous inserts to avoid this condition. I personally avoid this, when needed, by creating a FIFO queue and consuming that queue synchronously on a dedicated thread. You could also handle the condition by retrying your transaction X number of times before letting the Exception ripple up.
SQLiteBusyException is a special exception that is thrown whenever SQLite returns SQLITE_BUSY or SQLITE_IOERR_BLOCKED error code. These codes mean that the current operation cannot proceed because the required resources are locked.
When a timeout is set via SQLiteConnection.setBusyTimeout(long), SQLite will attempt to get the lock during the specified timeout before returning this error.
Ref: http://www.sqlite.org/lockingv3.html
Ref: http://sqlite.org/capi3ref.html#sqlite3_busy_timeout
I have applied the following solution which works in my case(mobile app).
Use sqlitepclraw.bundle_green nugget package with SqlitePCL.
Try to use the single connection throughout the app.
After creating the SQLiteConnection.
Apply busytime out using following call.
var connection = new SQLiteConnection(databasePath: path);
SQLite3.BusyTimeout(connection.Handle, 5000); // 5000 millisecond.
We have a new beta version of our software with some changes, but not around our database layer.
We've just started getting Error 3128 reported in our server logs. It seems that once it happens, it happens for as long as the app is open. The part of the code where it is most apparent is where we log data every second via SQLite. We've generated 47k errors on our server this month alone.
3128 Disk I/O error occurred. Indicates that an operation could not be completed because of a disk I/O error. This can happen if the runtime is attempting to delete a temporary file and another program (such as a virus protection application) is holding a lock on the file. This can also happen if the runtime is attempting to write data to a file and the data can't be written.
I don't know what could be causing this error. Maybe an anti-virus program? Maybe our app is getting confused and writing data on top of each other? We're using async connections.
It's causing lots of issues and we're at a loss. It has happened in our older version, but maybe 100 times in a month rather than 47,000 times. Either way I'd like to make it happen "0" times.
Possible solution: Exception Message: Some kind of disk I/O error occurred
Summary: There is probably not a problem with the database but a problem creating (or deleting) the temporary file once the database is opened. AIR may have permissions to the database, but not to create or delete files in the directory.
One answer that has worked for me is to use the PRAGMA statement to set the journal_mode value to something other than DELETE. You do this by issuing a PRAGMA statement in the same way you would issue a query statement.
PRAGMA journal_mode = OFF
Unfortunately, if the application crashes in the middle of a transaction when the OFF journaling mode is set, then the database file will very likely go corrupt.1.
1 http://www.sqlite.org/pragma.html#pragma_journal_mode
The solution was to make sure database delete, update, insert only happened one at at time by wrapping a little wrapper. On top of that, we had to watch for error 3128 and retry. I think this is because we have a trigger running that could lock the database after we inserted data.
We have a new beta version of our software with some changes, but not around our database layer.
We've just started getting Error 3128 reported in our server logs. It seems that once it happens, it happens for as long as the app is open. The part of the code where it is most apparent is where we log data every second via SQLite. We've generated 47k errors on our server this month alone.
3128 Disk I/O error occurred. Indicates that an operation could not be completed because of a disk I/O error. This can happen if the runtime is attempting to delete a temporary file and another program (such as a virus protection application) is holding a lock on the file. This can also happen if the runtime is attempting to write data to a file and the data can't be written.
I don't know what could be causing this error. Maybe an anti-virus program? Maybe our app is getting confused and writing data on top of each other? We're using async connections.
It's causing lots of issues and we're at a loss. It has happened in our older version, but maybe 100 times in a month rather than 47,000 times. Either way I'd like to make it happen "0" times.
Possible solution: Exception Message: Some kind of disk I/O error occurred
Summary: There is probably not a problem with the database but a problem creating (or deleting) the temporary file once the database is opened. AIR may have permissions to the database, but not to create or delete files in the directory.
One answer that has worked for me is to use the PRAGMA statement to set the journal_mode value to something other than DELETE. You do this by issuing a PRAGMA statement in the same way you would issue a query statement.
PRAGMA journal_mode = OFF
Unfortunately, if the application crashes in the middle of a transaction when the OFF journaling mode is set, then the database file will very likely go corrupt.1.
1 http://www.sqlite.org/pragma.html#pragma_journal_mode
The solution was to make sure database delete, update, insert only happened one at at time by wrapping a little wrapper. On top of that, we had to watch for error 3128 and retry. I think this is because we have a trigger running that could lock the database after we inserted data.
I am trying to confirm how the actual ADODB.Connection.Errors collection should actually work.
My interpretation at the moment is that the connection will hold all the errors for the all the procedures that have been executed on that connection.
So I should be able to say
on error resume next
... code goes here ... 2 or more command objects execute procedures against the database on the same connection
if con.Errors <> 0 then
loop through all the Errors objects (1 for each procedure that would've been executed on the connection)
end if
However I have implemented that basic structure and I only get the one error description? So I am looking for someone to confirm that is the case. Does the Errors collection hold more than one error for more than one procedure? Or is if multiple errors occurred for one procedure?
I can't seem to find any documentation that would indicate exactly what would happen in this case.
Thanks,
from Errors Collection (ADO) - MSDN:
Any operation involving ADO objects can generate one or more provider
errors. As each error occurs, one or more Error objects can be placed
in the Errors collection of the Connection object. When another ADO
operation generates an error, the Errors collection is cleared, and
the new set of Error objects can be placed in the Errors collection.
So, to catch all errors, seems to be need to check the collection after each possible error.
I have developed to applications in flex. The one application constantly retrieves data from the internet, while the other can be opened and closed when you want, both apps use the same database. The problem is that at random I get an Error #3119: Database file is currently locked. Is it not possible to have two stable connections in a Adobe AIR environment? Anyone has any solutions?
I think not. Not at once.
I know this is a really old question, but I ran into this issue myself and found a solution for it for those who may come across this. I hope this helps someone, because I know for me, all I could find on this topic was false information, like that given by Konrad. You can, in fact have multiple open database connections. Actually, in my application, I have an asynchronous connection used for writing data to the database (INSERT, UPDATE, DELETE), and a synchronous, read-only connection for reading from the database. On the asynchronous connection, for every execute, I always get an immediate lock by putting all statements in a transaction using
conn.begin(SQLTransactionLockType.IMMEDIATE);
This will allow you to read from the database while writing to it with another connection. Where I ran into a problem is when trying to read from the database from one connection after committing this async statement and before it actually finished writing the data. So, even though the documentation for SQLTransactionLockType.IMMEDIATE states you can still do reads while it is locked, you actually cannot while another statement is actively in the process of writing data.
I got around this by writing my own execute for the synchronous connection. It simply tries to execute, and if it fails due to Error #3119, try again until you succeed. Between each function call, the data will continue to be written to the database and eventually will no longer be busy. Here is the code for that function:
public static function execute(stmt:SQLStatement):void {
try {
stmt.execute();
} catch (e:SQLError) {
if(e.errorID == 3119) {
execute(stmt);
} else {
trace(e.details + "\n" + e.getStackTrace());
if(stmt.sqlConnection != null && stmt.sqlConnection.inTransaction) {
stmt.sqlConnection.rollback();
}
}
}
}
Another gotcha to watch out for with this error (if you're an idiot like me anyway) is to check if you've got the SQLite db file open in a db browser, which can lock the database, and cause this error (and hours of googling and irritation).