found and interesting problem :D
As many asking around why in Mono + Linux sometimes happens "unable to open database file" while opening SQLite database.
Well after few days we found a problem which was so hidden that I was going insane.
Consider the following code (please don't comment of the style as that is not the point!)
System.Data.SQLite.SQLiteConnectionStringBuilder sqcsb;
sqcsb = new System.Data.SQLite.SQLiteConnectionStringBuilder();
sqcsb.DataSource = "file.db";
sqcsb.SyncMode = System.Data.SQLite.SynchronizationModes.Full;
sqcsb.PageSize = 4096;
System.Data.SQLite.SQLiteConnection conn;
System.Data.SQLite.SQLiteCommand cmd;
System.Data.SQLite.SQLiteParameter param;
string sql = "update Smth set tt = @TT";
int i = 0;
while (true)
{
GC.Collect();
System.Diagnostics.Process proc = System.Diagnostics.Process.GetCurrentProcess();
Console.WriteLine("Memory:{0:0,0},Private: {1:0,0},Virtual: {2:0,0} Working: {3:0,0}, Paged: {4:0,0}",
GC.GetTotalMemory(true),
proc.PrivateMemorySize64,
proc.VirtualMemorySize64,
proc.WorkingSet64,
proc.PagedMemorySize64);
Console.WriteLine( "Testing DB..." + i++);
conn = new System.Data.SQLite.SQLiteConnection(sqcsb.ConnectionString);
conn.Open();
cmd = new System.Data.SQLite.SQLiteCommand(conn);
cmd.CommandText = sql;
param = new System.Data.SQLite.SQLiteParameter("@TT", DbType.String);
param.Value = "0";
cmd.Parameters.Add(param);
conn.Close();
conn.Dispose();
cmd.Dispose();
}
So what is the problem with above code?
The answer is that we are calling conn.Dispose() before cmd.Dispose() which on WINDOWS works without any problem, while on Mono and Linux it fails in around 1000 loops of the above code with Sqlite exception unable to open database file
Starting the process outputs at the beginning this:
Memory:671,744,Private: 5,091,328,Virtual: 19,202,048 Working: 9,617,408, Paged: 00
Testing DB...0
Memory:770,048,Private: 5,763,072,Virtual: 23,617,536 Working: 11,341,824, Paged: 00
Testing DB...1
Memory:770,048,Private: 5,763,072,Virtual: 23,617,536 Working: 11,341,824, Paged: 00
Testing DB...2
This is the last WriteLine output:
Memory:778,240,Private: 125,104,128,Virtual: 142,958,592 Working: 130,654,208, Paged: 00
Testing DB...1019
Unhandled Exception: System.Data.SQLite.SQLiteException: unable to open database file
at System.Data.SQLite.SQLite3.Open (System.String strFilename, SQLiteConnectionFlags connectionFlags, SQLiteOpenFlagsEnum openFlags, Int32 maxPoolSize, Boolean usePool) [0x00000] in <filename unknown>:0
at System.Data.SQLite.SQLiteConnection.Open () [0x00000] in <filename unknown>:0
Where you can see that PrivateMemory and VirtualMemory of the process are pretty high at the end when it crashes.
They increase on every open connection to db, meaning that something probably does not gets released from memory as it should!
So finding the hard way.. What solves the problem is... changing this:
conn.Dispose();
cmd.Dispose();
to:
cmd.Dispose();
conn.Dispose();
As i know that the above code is not by the book best practice, still a lot of users do not know why they should dispose everything in order as it results in the above problems!
So what i think happens is that when dispose of connection to db happens GC still detects a reference to connection in the command and that is why it postpones the collection, but after command is disposed it should dispose the connection but it does not, at least that is how i see it :D I could be wrong.
So please anyone with experience in GC and Mono why on MONO this is a problem while on windows Memory is not increasing either way we use dispose and does not cause any problems.
Thank you and best regards!