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

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

Overview
Comment:Update test case for ticket [996d13cd87] to run with and without connection pooling enabled.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: ead1f27df0c18866084608f1afc92e7498235ab3
User & Date: mistachkin 2012-05-03 17:46:01
Context
2012-05-03
19:21
Check each weak reference object from the queue prior to attempting to fetch its target. check-in: 2a6ee97694 user: mistachkin tags: trunk
17:46
Update test case for ticket [996d13cd87] to run with and without connection pooling enabled. check-in: ead1f27df0 user: mistachkin tags: trunk
17:15
Obtain a lock on the connection handle prior to finalizing a statement and/or finishing a backup object. check-in: fbf498a216 user: mistachkin tags: trunk
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to Tests/tkt-996d13cd87.eagle.

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
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224


225
226


227
228
229
230
231
232
233
234
235
236
237
238
239





240
241
242
243
244
###############################################################################

package require System.Data.SQLite.Test
runSQLiteTestPrologue

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

runTest {test tkt-996d13cd87-1.1 {SQLiteConnectionPool stress} -setup {




  set fileName tkt-996d13cd87-1.1.db






} -body {
  set id [object invoke Interpreter.GetActive NextId]
  set dataSource [file join [getDatabaseDirectory] $fileName]

  set sql { \
    CREATE TABLE t1(x TEXT); \
    INSERT INTO t1 (x) VALUES(RANDOMBLOB(1000)); \
  }

  unset -nocomplain results errors

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

    namespace _Dynamic${id}
    {
      public static class Test${id}
      {
        public static int Main()
        {
          //
          // NOTE: This is the total number of exceptions caught by all the
          //       test threads.
          //
          int errors = 0;

          //
          // NOTE: This is the total number of test threads to create.
          //
          int count = 100;

          //
          // NOTE: This is the total number of times we should force a full
          //       garbage collection.
          //
          int gcCount = 2;

          //
          // 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: 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 threadStart1 = delegate()
            {
              try
              {
                //
                // NOTE: Wait forever for the "GO" signal so that all threads
                //       can start working at approximately the same time.
                //
                goEvent.WaitOne();

                //
                // NOTE: Repeatedly try to create, open, and close a pooled
                //       database connection and then wait a random number of
                //       milliseconds before doing it again.
                //
                Thread.Sleep(random.Next(0, 500));

                SQLiteConnection connection = new SQLiteConnection(
                    "Data Source=${dataSource};Pooling=True;");

                connection.Open();

                using (SQLiteCommand command = new SQLiteCommand("${sql}",
                    connection))
                {
                  command.ExecuteNonQuery();
                }

                connection.Close();
                connection = null;
              }
              catch (Exception e)
              {
                Interlocked.Increment(ref errors);
                Trace.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: Wait a random number of milliseconds before forcing a
                //       full garbage collection.
                //
                for (int index = 0; index < gcCount; index++)
                {
                  Thread.Sleep(random.Next(0, 1000));
                  GC.GetTotalMemory(true);
                }
              }
              catch (Exception e)
              {
                Interlocked.Increment(ref errors);
                Trace.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++)
            {
              //
              // NOTE: Figure out what kind of thread to create (i.e. one
              //       that uses a connection or one that calls the GC).
              //
              ThreadStart threadStart;

              if (index == 0)
                threadStart = threadStart2;
              else
                threadStart = threadStart1;

              thread\[index\] = new Thread(threadStart, 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();
          }

          //
          // NOTE: Return the total number of exceptions caught by the test
          //       threads.
          //
          return errors;
        }
      }
    }
  }] 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 \


      [expr {[object invoke -flags +NonPublic \
          System.Data.SQLite.SQLiteConnectionPool _poolOpened] > 0}] \


      [expr {[object invoke -flags +NonPublic \
          System.Data.SQLite.SQLiteConnectionPool _poolClosed] > 0}]
} -cleanup {
  object invoke System.Data.SQLite.SQLiteConnection ClearAllPools
  object invoke GC GetTotalMemory true

  cleanupDb $fileName

  unset -nocomplain result results errors code sql 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 \d+ True\
True$}}






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

runSQLiteTestEpilogue
runTestEpilogue







|
>
>
>
>
|
>
>
>
>
>
>
|
|
|

|
|
|
|

|

|
|
|
|
|

|
|
|
|
|
|
|
|
|
|
|

|
|
|
|

|
|
|
|
|

|
|
|
|
|
|

|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|

|
|
|
|
|
|

|
|

|

|
|
|
|
|

|
|
|
|
|
|
|
|
|

|
|
|
|
|
|
|
|
|
|
|
|
|
|

|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|

|
|
|
|

|
|
|
|
|
|
|
|
|
|
|
|
|
|

|
|
|
|

|

|
|
|
|
|
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>



<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
|
|
|
|
|
|
|
|

|
|
|
|
|
>
>
|
|
>
>
|
|
|
|
|

|

|
|
|
|
<
>
>
>
>
>





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
208
209
210
211
212
213
214
215
216
217
218
219
220





















221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252

253
254
255
256
257
258
259
260
261
262
###############################################################################

package require System.Data.SQLite.Test
runSQLiteTestPrologue

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

for {set i 1} {$i < 3} {incr i} {
  set pooling [expr {$i == 2 ? True : False}]

  runTest {test [appendArgs tkt-996d13cd87-1. $i] {SQLiteConnection stress} \
      -setup {
    set fileName [appendArgs tkt-996d13cd87-1. $i .db]

    object invoke -flags +NonPublic \
        System.Data.SQLite.SQLiteConnectionPool _poolOpened 0

    object invoke -flags +NonPublic \
        System.Data.SQLite.SQLiteConnectionPool _poolClosed 0
  } -body {
    set id [object invoke Interpreter.GetActive NextId]
    set dataSource [file join [getDatabaseDirectory] $fileName]

    set sql { \
      CREATE TABLE t1(x TEXT); \
      INSERT INTO t1 (x) VALUES(RANDOMBLOB(1000)); \
    }

    unset -nocomplain results errors

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

      namespace _Dynamic${id}
      {
        public static class Test${id}
        {
          public static int Main()
          {
            //
            // NOTE: This is the total number of exceptions caught by all the
            //       test threads.
            //
            int errors = 0;

            //
            // NOTE: This is the total number of test threads to create.
            //
            int count = 100;

            //
            // NOTE: This is the total number of times we should force a full
            //       garbage collection.
            //
            int gcCount = 2;

            //
            // 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: 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 (or without) pooling enabled.
              //
              ThreadStart threadStart1 = delegate()
              {
                try
                {
                  //
                  // NOTE: Wait forever for the "GO" signal so that all threads
                  //       can start working at approximately the same time.
                  //
                  goEvent.WaitOne();

                  //
                  // NOTE: Repeatedly try to create, open, and close a pooled
                  //       database connection and then wait a random number of
                  //       milliseconds before doing it again.
                  //
                  Thread.Sleep(random.Next(0, 500));

                  SQLiteConnection connection = new SQLiteConnection(
                      "Data Source=${dataSource};Pooling=${pooling};");

                  connection.Open();

                  using (SQLiteCommand command = new SQLiteCommand("${sql}",
                      connection))
                  {
                    command.ExecuteNonQuery();
                  }

                  connection.Close();
                  connection = null;
                }
                catch (Exception e)
                {
                  Interlocked.Increment(ref errors);
                  Trace.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: Wait a random number of milliseconds before forcing
                  //       a full garbage collection.
                  //
                  for (int index = 0; index < gcCount; index++)
                  {
                    Thread.Sleep(random.Next(0, 1000));
                    GC.GetTotalMemory(true);
                  }
                }
                catch (Exception e)
                {
                  Interlocked.Increment(ref errors);
                  Trace.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++)
              {
                //
                // NOTE: Figure out what kind of thread to create (i.e. one
                //       that uses a connection or one that calls the GC).
                //
                ThreadStart threadStart;

                if (index == 0)
                  threadStart = threadStart2;
                else
                  threadStart = threadStart1;

                thread\[index\] = new Thread(threadStart, 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();
            }

            //





















            // NOTE: Return the total number of exceptions caught by the test
            //       threads.
            //
            return errors;
          }
        }
      }
    }] 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 \
        [expr {$pooling ? [object invoke -flags +NonPublic \
            System.Data.SQLite.SQLiteConnectionPool _poolOpened] > 0 : \
            [object invoke -flags +NonPublic \
            System.Data.SQLite.SQLiteConnectionPool _poolOpened] == 0}] \
        [expr {$pooling ? [object invoke -flags +NonPublic \
            System.Data.SQLite.SQLiteConnectionPool _poolClosed] > 0 : \
            [object invoke -flags +NonPublic \
            System.Data.SQLite.SQLiteConnectionPool _poolClosed] == 0}]
  } -cleanup {
    object invoke System.Data.SQLite.SQLiteConnection ClearAllPools
    object invoke GC GetTotalMemory true

    cleanupDb $fileName

    unset -nocomplain result results errors code sql 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 \d+ True True$}}

}

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

unset -nocomplain pooling i

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

runSQLiteTestEpilogue
runTestEpilogue