Mono + Linux + SQlite-> bad practice -> result unable to open database file

若如初见. 提交于 2020-01-05 10:32:00

问题


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!

来源:https://stackoverflow.com/questions/17019618/mono-linux-sqlite-bad-practice-result-unable-to-open-database-file

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!