System.Data.SQLite
Check-in [adad8e2f33]
Not logged in

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:First attempt to reproduce the possible issue described in ticket [996d13cd87].
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | tkt-996d13cd87
Files: files | file ages | folders
SHA1: adad8e2f331d926adc69cad7141a4fdb400d81f0
User & Date: mistachkin 2012-04-28 09:50:35
Context
2012-04-28
12:21
Reform how the connection pool treats its connection handles. check-in: 4a6b21aeef user: mistachkin tags: tkt-996d13cd87
09:50
First attempt to reproduce the possible issue described in ticket [996d13cd87]. check-in: adad8e2f33 user: mistachkin tags: tkt-996d13cd87
09:45
Add another connection pool related diagnostic. check-in: d846d5cd0b user: mistachkin tags: trunk
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Added Tests/tkt-996d13cd87.eagle.































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
###############################################################################
#
# tkt-996d13cd87.eagle --
#
# Written by Joe Mistachkin.
# Released to the public domain, use at your own risk!
#
###############################################################################

package require Eagle
package require Eagle.Library
package require Eagle.Test

runTestPrologue

###############################################################################

package require System.Data.SQLite.Test
runSQLiteTestPrologue

###############################################################################

runTest {test tkt-996d13cd87-1.1 {SQLiteConnectionPool usage} -setup {
  set fileName tkt-996d13cd87-1.1.db
} -body {
  set id [object invoke Interpreter.GetActive NextId]
  set dataSource [file join [getDatabaseDirectory] $fileName]

  unset -nocomplain results errors

  set code [compileCSharpWith [subst {
    using System;
    using System.Data.SQLite;
    using System.Threading;

    namespace _Dynamic${id}
    {
      public static class Test${id}
      {
        public static void Main()
        {
          //
          // NOTE: This is the total number of test threads to create.
          //
          int count = 10;

          //
          // NOTE: Create the event that will be used to synchronize all the
          //       created threads so that they start doing their actual test
          //       "work" at approximately the same time.
          //
          using (ManualResetEvent goEvent = new ManualResetEvent(false))
          {
            //
            // NOTE: Create a (reusable) delegate that will contain the code
            //       that half the created threads are to execute.  This code
            //       will repeatedly create, open, and close a single database
            //       connection with pool enabled.
            //
            ThreadStart threadStart = delegate()
            {
              try
              {
                //
                // NOTE: Wait forever for the "GO" signal so that all threads
                //       can start working at approximately the same time.
                //
                goEvent.WaitOne();

                //
                // NOTE: Create a random number generator suitable for waiting
                //       a random number of milliseconds between each attempt
                //       to cause the race condition on a given thread.
                //
                Random random = new Random();

                //
                // NOTE: Repeatedly try to create, open, and close a pooled
                //       database connection and then wait a random number of
                //       milliseconds before doing it again.
                //
                for (int index = 0; index < count; index++)
                {
                  using (SQLiteConnection connection = new SQLiteConnection(
                      "Data Source=${dataSource};Pooling=True;"))
                  {
                    connection.Open();
                    connection.Close();
                  }

                  Thread.Sleep(random.Next(0, count));
                }
              }
              catch (Exception e)
              {
                Console.WriteLine(e);
              }
            };

            //
            // NOTE: Create a (reusable) delegate that will contain the code
            //       that half the created threads are to execute.  This code
            //       will repeatedly force a full garbage collection.
            //
            ThreadStart threadStart2 = delegate()
            {
              try
              {
                //
                // NOTE: Wait forever for the "GO" signal so that all threads
                //       can start working at approximately the same time.
                //
                goEvent.WaitOne();

                //
                // NOTE: Create a random number generator suitable for waiting
                //       a random number of milliseconds between each attempt
                //       to cause the race condition on a given thread.
                //
                Random random = new Random();

                //
                // NOTE: Repeatedly force a full garbage collection and then
                //       wait a random number of milliseconds before doing it
                //       again.
                //
                for (int index = 0; index < count; index++)
                {
                  GC.GetTotalMemory(true);
                  Thread.Sleep(random.Next(0, count));
                }
              }
              catch (Exception e)
              {
                Console.WriteLine(e);
              }
            };

            //
            // NOTE: Create the array of thread objects.
            //
            Thread\[\] thread = new Thread\[count\];

            //
            // NOTE: Create each of the test threads with a suitable stack
            //       size.  We must specify a stack size here because the
            //       default one for the process would be the same as the
            //       parent executable (the Eagle shell), which is 16MB,
            //       too large to be useful.
            //
            for (int index = 0; index < count; index++)
            {
              thread\[index\] = new Thread(
                  (index % 2) == 0 ? threadStart : threadStart2, 1048576);

              //
              // NOTE: Name each thread for a better debugging experience.
              //
              thread\[index\].Name = String.Format(
                  "[file rootname ${fileName}] #{0}", index);
            }

            //
            // NOTE: Start all the threads now.  They should not actually do
            //       any of the test "work" until we signal the event.
            //
            for (int index = 0; index < count; index++)
              thread\[index\].Start();

            //
            // NOTE: Send the signal that all threads should start doing
            //       their test "work" now.
            //
            goEvent.Set(); /* GO */

            //
            // NOTE: Wait forever for each thread to finish its test "work"
            //       and then die.
            //
            for (int index = 0; index < count; index++)
              thread\[index\].Join();
          }
        }
      }
    }
  }] true true true results errors System.Data.SQLite.dll]

  list $code $results \
      [expr {[info exists errors] ? $errors : ""}] \
      [expr {$code eq "Ok" ? [catch {
        object invoke _Dynamic${id}.Test${id} Main
      } result] : [set result ""]}] $result
} -cleanup {
  object invoke System.Data.SQLite.SQLiteConnection ClearAllPools
  object invoke GC GetTotalMemory true

  cleanupDb $fileName

  unset -nocomplain result results errors code dataSource id db fileName
} -constraints \
{eagle monoBug28 command.sql compile.DATA SQLite System.Data.SQLite} -match \
regexp -result {^Ok System#CodeDom#Compiler#CompilerResults#\d+ \{\} 0 \{\}$}}

###############################################################################

runSQLiteTestEpilogue
runTestEpilogue