extralite 2.5 → 2.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (45) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -0
  3. data/CHANGELOG.md +34 -13
  4. data/Gemfile +4 -0
  5. data/Gemfile-bundle +1 -1
  6. data/LICENSE +1 -1
  7. data/README.md +1059 -247
  8. data/Rakefile +18 -0
  9. data/TODO.md +0 -7
  10. data/examples/kv_store.rb +49 -0
  11. data/examples/multi_fiber.rb +16 -0
  12. data/examples/on_progress.rb +9 -0
  13. data/examples/pubsub_store_polyphony.rb +194 -0
  14. data/examples/pubsub_store_threads.rb +204 -0
  15. data/ext/extralite/changeset.c +463 -0
  16. data/ext/extralite/common.c +177 -91
  17. data/ext/extralite/database.c +745 -276
  18. data/ext/extralite/extconf-bundle.rb +10 -4
  19. data/ext/extralite/extconf.rb +34 -34
  20. data/ext/extralite/extralite.h +104 -47
  21. data/ext/extralite/extralite_ext.c +6 -0
  22. data/ext/extralite/iterator.c +14 -86
  23. data/ext/extralite/query.c +171 -264
  24. data/extralite-bundle.gemspec +1 -1
  25. data/extralite.gemspec +1 -1
  26. data/gemspec.rb +10 -11
  27. data/lib/extralite/version.rb +1 -1
  28. data/lib/extralite.rb +69 -10
  29. data/lib/sequel/adapters/extralite.rb +1 -1
  30. data/test/helper.rb +9 -1
  31. data/test/perf_argv_transform.rb +74 -0
  32. data/test/perf_ary.rb +14 -12
  33. data/test/perf_hash.rb +17 -15
  34. data/test/perf_hash_prepared.rb +58 -0
  35. data/test/perf_hash_transform.rb +66 -0
  36. data/test/perf_polyphony.rb +74 -0
  37. data/test/test_changeset.rb +161 -0
  38. data/test/test_database.rb +720 -104
  39. data/test/test_extralite.rb +2 -2
  40. data/test/test_iterator.rb +28 -13
  41. data/test/test_query.rb +352 -110
  42. data/test/test_sequel.rb +4 -4
  43. metadata +24 -16
  44. data/Gemfile.lock +0 -37
  45. data/test/perf_prepared.rb +0 -64
data/gemspec.rb CHANGED
@@ -8,19 +8,18 @@ def common_spec(s)
8
8
  s.files = `git ls-files`.split
9
9
  s.homepage = 'https://github.com/digital-fabric/extralite'
10
10
  s.metadata = {
11
- "source_code_uri" => "https://github.com/digital-fabric/extralite",
12
- "documentation_uri" => "https://www.rubydoc.info/gems/extralite",
13
- "homepage_uri" => "https://github.com/digital-fabric/extralite",
14
- "changelog_uri" => "https://github.com/digital-fabric/extralite/blob/master/CHANGELOG.md"
11
+ 'homepage_uri' => 'https://github.com/digital-fabric/extralite',
12
+ 'documentation_uri' => 'https://www.rubydoc.info/gems/extralite',
13
+ 'changelog_uri' => 'https://github.com/digital-fabric/extralite/blob/master/CHANGELOG.md'
15
14
  }
16
- s.rdoc_options = ["--title", "extralite", "--main", "README.md"]
17
- s.extra_rdoc_files = ["README.md"]
18
- s.require_paths = ["lib"]
15
+ s.rdoc_options = ['--title', 'Extralite', '--main', 'README.md']
16
+ s.extra_rdoc_files = ['README.md']
17
+ s.require_paths = ['lib']
19
18
  s.required_ruby_version = '>= 3.0'
20
19
 
21
- s.add_development_dependency 'rake-compiler', '1.1.6'
22
- s.add_development_dependency 'minitest', '5.15.0'
20
+ s.add_development_dependency 'rake-compiler', '1.2.7'
21
+ s.add_development_dependency 'minitest', '5.21.2'
23
22
  s.add_development_dependency 'simplecov', '0.17.1'
24
- s.add_development_dependency 'yard', '0.9.27'
25
- s.add_development_dependency 'sequel', '5.51.0'
23
+ s.add_development_dependency 'yard', '0.9.34'
24
+ s.add_development_dependency 'sequel', '5.77.0'
26
25
  end
@@ -1,4 +1,4 @@
1
1
  module Extralite
2
2
  # Extralite version
3
- VERSION = '2.5'
3
+ VERSION = '2.7'
4
4
  end
data/lib/extralite.rb CHANGED
@@ -29,10 +29,10 @@ module Extralite
29
29
  class ParameterError < Error
30
30
  end
31
31
 
32
- # An SQLite database
32
+ # This class encapsulates an SQLite database connection.
33
33
  class Database
34
34
  # @!visibility private
35
- TABLES_SQL = <<~SQL
35
+ TABLES_SQL = (<<~SQL).freeze
36
36
  SELECT name FROM %<db>s.sqlite_master
37
37
  WHERE type ='table'
38
38
  AND name NOT LIKE 'sqlite_%%';
@@ -46,10 +46,11 @@ module Extralite
46
46
  # @param db [String] name of attached database
47
47
  # @return [Array] list of tables
48
48
  def tables(db = 'main')
49
- query_single_column(format(TABLES_SQL, db: db))
49
+ query_argv(format(TABLES_SQL, db: db))
50
50
  end
51
51
 
52
- # Gets or sets one or more pragmas:
52
+ # Gets or sets one or more database pragmas. For a list of available pragmas
53
+ # see: https://sqlite.org/pragma.html#toc
53
54
  #
54
55
  # db.pragma(:cache_size) # get
55
56
  # db.pragma(cache_size: -2000) # set
@@ -60,6 +61,11 @@ module Extralite
60
61
  value.is_a?(Hash) ? pragma_set(value) : pragma_get(value)
61
62
  end
62
63
 
64
+ # Error class used to roll back a transaction without propagating an
65
+ # exception.
66
+ class Rollback < Error
67
+ end
68
+
63
69
  # Starts a transaction and runs the given block. If an exception is raised
64
70
  # in the block, the transaction is rolled back. Otherwise, the transaction
65
71
  # is commited after running the block.
@@ -69,20 +75,73 @@ module Extralite
69
75
  # raise if db.query_single_value('select x from bar') > 42
70
76
  # end
71
77
  #
72
- # @param mode [Symbol, String] transaction mode (deferred, immediate or exclusive). Defaults to immediate.
78
+ # For more information on transactions see:
79
+ # https://sqlite.org/lang_transaction.html
80
+ #
81
+ # @param mode [Symbol, String] transaction mode (deferred, immediate or exclusive).
73
82
  # @return [Any] the given block's return value
74
83
  def transaction(mode = :immediate)
75
- execute "begin #{mode} transaction"
76
-
77
84
  abort = false
85
+ execute "begin #{mode} transaction"
78
86
  yield self
79
- rescue
87
+ rescue => e
80
88
  abort = true
81
- raise
89
+ e.is_a?(Rollback) ? nil : raise
82
90
  ensure
83
91
  execute(abort ? 'rollback' : 'commit')
84
92
  end
85
93
 
94
+ # Creates a savepoint with the given name. For more information on
95
+ # savepoints see: https://sqlite.org/lang_savepoint.html
96
+ #
97
+ # db.savepoint(:savepoint1)
98
+ # db.execute('insert into foo values (42)')
99
+ # db.rollback_to(:savepoint1)
100
+ # db.release(:savepoint1)
101
+ #
102
+ # @param name [String, Symbol] savepoint name
103
+ # @return [Extralite::Database] database
104
+ def savepoint(name)
105
+ execute "savepoint #{name}"
106
+ self
107
+ end
108
+
109
+ # Release a savepoint with the given name. For more information on
110
+ # savepoints see: https://sqlite.org/lang_savepoint.html
111
+ #
112
+ # @param name [String, Symbol] savepoint name
113
+ # @return [Extralite::Database] database
114
+ def release(name)
115
+ execute "release #{name}"
116
+ self
117
+ end
118
+
119
+ # Rolls back changes to a savepoint with the given name. For more
120
+ # information on savepoints see: https://sqlite.org/lang_savepoint.html
121
+ #
122
+ # @param name [String, Symbol] savepoint name
123
+ # @return [Extralite::Database] database
124
+ def rollback_to(name)
125
+ execute "rollback to #{name}"
126
+ self
127
+ end
128
+
129
+ # Rolls back the currently active transaction. This method should only be
130
+ # called from within a block passed to `Database#transaction`. This method
131
+ # raises a Extralite::Rollback exception, which will stop execution of the
132
+ # transaction block without propagating the exception.
133
+ #
134
+ # db.transaction do
135
+ # db.execute('insert into foo (42)')
136
+ # db.rollback!
137
+ # end
138
+ #
139
+ # @param name [String, Symbol] savepoint name
140
+ # @return [Extralite::Database] database
141
+ def rollback!
142
+ raise Rollback
143
+ end
144
+
86
145
  private
87
146
 
88
147
  def pragma_set(values)
@@ -91,7 +150,7 @@ module Extralite
91
150
  end
92
151
 
93
152
  def pragma_get(key)
94
- query_single_value("pragma #{key}")
153
+ query_single_argv("pragma #{key}")
95
154
  end
96
155
  end
97
156
 
@@ -362,7 +362,7 @@ module Sequel
362
362
  def fetch_rows(sql, &block)
363
363
  execute(sql) do |result, columns|
364
364
  self.columns = columns
365
- max = columns.size
365
+ # max = columns.size
366
366
  result.each(&block)
367
367
  end
368
368
  end
data/test/helper.rb CHANGED
@@ -7,4 +7,12 @@ require 'minitest/autorun'
7
7
  puts "sqlite3 version: #{Extralite.sqlite3_version}"
8
8
 
9
9
  IS_LINUX = RUBY_PLATFORM =~ /linux/
10
- SKIP_RACTOR_TESTS = !IS_LINUX || (RUBY_VERSION =~ /^3\.0/)
10
+ # Ractors are kinda flaky, there's no point in testing this
11
+ SKIP_RACTOR_TESTS = true #!IS_LINUX || (RUBY_VERSION =~ /^3\.[01]/)
12
+
13
+ module Minitest::Assertions
14
+ def assert_in_range exp_range, act
15
+ msg = message(msg) { "Expected #{mu_pp(act)} to be in range #{mu_pp(exp_range)}" }
16
+ assert exp_range.include?(act), msg
17
+ end
18
+ end
@@ -0,0 +1,74 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Run on Ruby 3.3 with YJIT enabled
4
+
5
+ require 'bundler/inline'
6
+
7
+ gemfile do
8
+ source 'https://rubygems.org'
9
+ gem 'extralite', path: '..'
10
+ gem 'benchmark-ips'
11
+ end
12
+
13
+ require 'benchmark/ips'
14
+ require 'fileutils'
15
+
16
+ DB_PATH = "/tmp/extralite_sqlite3_perf-#{Time.now.to_i}-#{rand(10000)}.db"
17
+ puts "DB_PATH = #{DB_PATH.inspect}"
18
+
19
+ $extralite_db = Extralite::Database.new(DB_PATH, gvl_release_threshold: -1)
20
+
21
+ def prepare_database(count)
22
+ $extralite_db.query('create table if not exists foo (b text)')
23
+ $extralite_db.query('delete from foo')
24
+ $extralite_db.query('begin')
25
+ count.times { $extralite_db.query('insert into foo (b) values (?)', "hello#{rand(1000)}" )}
26
+ $extralite_db.query('commit')
27
+ end
28
+
29
+ class Model
30
+ def initialize(h)
31
+ @h = h
32
+ end
33
+
34
+ def values
35
+ @h
36
+ end
37
+ end
38
+
39
+ TRANSFORM = ->(b) { { b: b } }
40
+
41
+ def extralite_run_ary_map(count)
42
+ results = []
43
+ $extralite_db.query_ary('select * from foo') { |(b)| results << { b: b } }
44
+ raise unless results.size == count
45
+ end
46
+
47
+ def extralite_run_argv_map(count)
48
+ results = []
49
+ $extralite_db.query_argv('select * from foo') { |b| results << { b: b } }
50
+ raise unless results.size == count
51
+ end
52
+
53
+ def extralite_run_transform(count)
54
+ results = $extralite_db.query_argv(TRANSFORM, 'select * from foo')
55
+ raise unless results.size == count
56
+ end
57
+
58
+ [10, 1000, 100000].each do |c|
59
+ puts "Record count: #{c}"
60
+ prepare_database(c)
61
+
62
+ bm = Benchmark.ips do |x|
63
+ x.config(:time => 5, :warmup => 2)
64
+
65
+ x.report("ary_map") { extralite_run_ary_map(c) }
66
+ x.report("argv_map") { extralite_run_argv_map(c) }
67
+ x.report("transform") { extralite_run_transform(c) }
68
+
69
+ x.compare!
70
+ end
71
+ puts;
72
+ bm.entries.each { |e| puts "#{e.label}: #{(e.ips * c).round.to_i} rows/s" }
73
+ puts;
74
+ end
data/test/perf_ary.rb CHANGED
@@ -15,26 +15,25 @@ require 'fileutils'
15
15
  DB_PATH = "/tmp/extralite_sqlite3_perf-#{Time.now.to_i}-#{rand(10000)}.db"
16
16
  puts "DB_PATH = #{DB_PATH.inspect}"
17
17
 
18
+ $sqlite3_db = SQLite3::Database.new(DB_PATH)
19
+ $extralite_db = Extralite::Database.new(DB_PATH, gvl_release_threshold: -1)
18
20
 
19
21
  def prepare_database(count)
20
22
  db = Extralite::Database.new(DB_PATH)
21
- db.query('create table if not exists foo ( a integer primary key, b text )')
22
- db.query('delete from foo')
23
- db.query('begin')
24
- count.times { db.query('insert into foo (b) values (?)', "hello#{rand(1000)}" )}
25
- db.query('commit')
26
- db.close
23
+ $extralite_db.query('create table if not exists foo ( a integer primary key, b text )')
24
+ $extralite_db.query('delete from foo')
25
+ $extralite_db.query('begin')
26
+ count.times { $extralite_db.query('insert into foo (b) values (?)', "hello#{rand(1000)}" )}
27
+ $extralite_db.query('commit')
27
28
  end
28
29
 
29
30
  def sqlite3_run(count)
30
- db = SQLite3::Database.new(DB_PATH)
31
- results = db.execute('select * from foo')
31
+ results = $sqlite3_db.execute('select * from foo')
32
32
  raise unless results.size == count
33
33
  end
34
34
 
35
35
  def extralite_run(count)
36
- db = Extralite::Database.new(DB_PATH)
37
- results = db.query_ary('select * from foo')
36
+ results = $extralite_db.query('select * from foo')
38
37
  raise unless results.size == count
39
38
  end
40
39
 
@@ -43,12 +42,15 @@ end
43
42
 
44
43
  prepare_database(c)
45
44
 
46
- Benchmark.ips do |x|
47
- x.config(:time => 3, :warmup => 1)
45
+ bm = Benchmark.ips do |x|
46
+ x.config(:time => 5, :warmup => 2)
48
47
 
49
48
  x.report("sqlite3") { sqlite3_run(c) }
50
49
  x.report("extralite") { extralite_run(c) }
51
50
 
52
51
  x.compare!
53
52
  end
53
+ puts;
54
+ bm.entries.each { |e| puts "#{e.label}: #{(e.ips * c).round.to_i} rows/s" }
55
+ puts;
54
56
  end
data/test/perf_hash.rb CHANGED
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ # Run on Ruby 3.3 with YJIT enabled
4
+
3
5
  require 'bundler/inline'
4
6
 
5
7
  gemfile do
@@ -15,40 +17,40 @@ require 'fileutils'
15
17
  DB_PATH = "/tmp/extralite_sqlite3_perf-#{Time.now.to_i}-#{rand(10000)}.db"
16
18
  puts "DB_PATH = #{DB_PATH.inspect}"
17
19
 
20
+ $sqlite3_db = SQLite3::Database.new(DB_PATH, results_as_hash: true)
21
+ $extralite_db = Extralite::Database.new(DB_PATH, gvl_release_threshold: -1)
22
+
18
23
  def prepare_database(count)
19
- db = Extralite::Database.new(DB_PATH)
20
- db.query('create table if not exists foo ( a integer primary key, b text )')
21
- db.query('delete from foo')
22
- db.query('begin')
23
- count.times { db.query('insert into foo (b) values (?)', "hello#{rand(1000)}" )}
24
- db.query('commit')
25
- db.close
24
+ $extralite_db.query('create table if not exists foo ( a integer primary key, b text )')
25
+ $extralite_db.query('delete from foo')
26
+ $extralite_db.query('begin')
27
+ count.times { $extralite_db.query('insert into foo (b) values (?)', "hello#{rand(1000)}" )}
28
+ $extralite_db.query('commit')
26
29
  end
27
30
 
28
31
  def sqlite3_run(count)
29
- db = SQLite3::Database.new(DB_PATH, :results_as_hash => true)
30
- results = db.execute('select * from foo')
32
+ results = $sqlite3_db.execute('select * from foo')
31
33
  raise unless results.size == count
32
34
  end
33
35
 
34
36
  def extralite_run(count)
35
- db = Extralite::Database.new(DB_PATH)
36
- results = db.query('select * from foo')
37
+ results = $extralite_db.query('select * from foo')
37
38
  raise unless results.size == count
38
39
  end
39
40
 
40
41
  [10, 1000, 100000].each do |c|
41
42
  puts "Record count: #{c}"
42
-
43
43
  prepare_database(c)
44
44
 
45
- Benchmark.ips do |x|
46
- x.config(:time => 3, :warmup => 1)
45
+ bm = Benchmark.ips do |x|
46
+ x.config(:time => 5, :warmup => 2)
47
47
 
48
48
  x.report("sqlite3") { sqlite3_run(c) }
49
49
  x.report("extralite") { extralite_run(c) }
50
50
 
51
51
  x.compare!
52
52
  end
53
- puts; puts;
53
+ puts;
54
+ bm.entries.each { |e| puts "#{e.label}: #{(e.ips * c).round.to_i} rows/s" }
55
+ puts;
54
56
  end
@@ -0,0 +1,58 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'bundler/inline'
4
+
5
+ gemfile do
6
+ source 'https://rubygems.org'
7
+ gem 'extralite', path: '..'
8
+ gem 'sqlite3'
9
+ gem 'benchmark-ips'
10
+ end
11
+
12
+ require 'benchmark/ips'
13
+ require 'fileutils'
14
+
15
+ DB_PATH = "/tmp/extralite_sqlite3_perf-#{Time.now.to_i}-#{rand(10000)}.db"
16
+ puts "DB_PATH = #{DB_PATH.inspect}"
17
+
18
+ def prepare_database(count)
19
+ $sqlite3_db = SQLite3::Database.new(DB_PATH, results_as_hash: true)
20
+ $extralite_db = Extralite::Database.new(DB_PATH, gvl_release_threshold: -1)
21
+
22
+ $extralite_db.query('create table if not exists foo ( a integer primary key, b text )')
23
+ $extralite_db.query('delete from foo')
24
+ $extralite_db.query('begin')
25
+ count.times { $extralite_db.query('insert into foo (b) values (?)', "hello#{rand(1000)}" )}
26
+ $extralite_db.query('commit')
27
+
28
+ $sqlite3_stmt = $sqlite3_db.prepare('select * from foo')
29
+ $extralite_q = $extralite_db.prepare('select * from foo')
30
+ end
31
+
32
+ def sqlite3_run(count)
33
+ results = $sqlite3_stmt.execute
34
+ raise unless results.to_a.size == count
35
+ end
36
+
37
+ def extralite_run(count)
38
+ results = $extralite_q.to_a
39
+ raise unless results.size == count
40
+ end
41
+
42
+ [10, 1000, 100000].each do |c|
43
+ puts "Record count: #{c}"
44
+
45
+ prepare_database(c)
46
+
47
+ bm = Benchmark.ips do |x|
48
+ x.config(:time => 5, :warmup => 2)
49
+
50
+ x.report("sqlite3") { sqlite3_run(c) }
51
+ x.report("extralite") { extralite_run(c) }
52
+
53
+ x.compare!
54
+ end
55
+ puts;
56
+ bm.entries.each { |e| puts "#{e.label}: #{(e.ips * c).round.to_i} rows/s" }
57
+ puts;
58
+ end
@@ -0,0 +1,66 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Run on Ruby 3.3 with YJIT enabled
4
+
5
+ require 'bundler/inline'
6
+
7
+ gemfile do
8
+ source 'https://rubygems.org'
9
+ gem 'extralite', path: '..'
10
+ gem 'benchmark-ips'
11
+ end
12
+
13
+ require 'benchmark/ips'
14
+ require 'fileutils'
15
+
16
+ DB_PATH = "/tmp/extralite_sqlite3_perf-#{Time.now.to_i}-#{rand(10000)}.db"
17
+ puts "DB_PATH = #{DB_PATH.inspect}"
18
+
19
+ $extralite_db = Extralite::Database.new(DB_PATH, gvl_release_threshold: -1)
20
+
21
+ def prepare_database(count)
22
+ $extralite_db.query('create table if not exists foo ( a integer primary key, b text )')
23
+ $extralite_db.query('delete from foo')
24
+ $extralite_db.query('begin')
25
+ count.times { $extralite_db.query('insert into foo (b) values (?)', "hello#{rand(1000)}" )}
26
+ $extralite_db.query('commit')
27
+ end
28
+
29
+ class Model
30
+ def initialize(h)
31
+ @h = h
32
+ end
33
+
34
+ def values
35
+ @h
36
+ end
37
+ end
38
+
39
+ TRANSFORM = ->(h) { Model.new(h) }
40
+
41
+ def extralite_run_map(count)
42
+ results = $extralite_db.query('select * from foo').map(&TRANSFORM)
43
+ raise unless results.size == count
44
+ end
45
+
46
+ def extralite_run_transform(count)
47
+ results = $extralite_db.query(TRANSFORM, 'select * from foo')
48
+ raise unless results.size == count
49
+ end
50
+
51
+ [10, 1000, 100000].each do |c|
52
+ puts "Record count: #{c}"
53
+ prepare_database(c)
54
+
55
+ bm = Benchmark.ips do |x|
56
+ x.config(:time => 5, :warmup => 2)
57
+
58
+ x.report("map") { extralite_run_map(c) }
59
+ x.report("transform") { extralite_run_transform(c) }
60
+
61
+ x.compare!
62
+ end
63
+ puts;
64
+ bm.entries.each { |e| puts "#{e.label}: #{(e.ips * c).round.to_i} rows/s" }
65
+ puts;
66
+ end
@@ -0,0 +1,74 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Run on Ruby 3.3 with YJIT enabled
4
+
5
+ require 'bundler/inline'
6
+ gemfile do
7
+ gem 'polyphony'
8
+ gem 'extralite', path: '.'
9
+ gem 'benchmark-ips'
10
+ end
11
+
12
+ require 'benchmark/ips'
13
+ require 'polyphony'
14
+
15
+ DB_PATH = "/tmp/extralite_sqlite3_perf-#{Time.now.to_i}-#{rand(10000)}.db"
16
+ puts "DB_PATH = #{DB_PATH.inspect}"
17
+
18
+ $db1 = Extralite::Database.new(DB_PATH, gvl_release_threshold: -1)
19
+ $db2 = Extralite::Database.new(DB_PATH, gvl_release_threshold: 0)
20
+ $db3 = Extralite::Database.new(DB_PATH)
21
+
22
+ $snooze_count = 0
23
+ $db3.on_progress(25) { $snooze_count += 1; snooze }
24
+
25
+ def prepare_database(count)
26
+ $db1.execute('create table if not exists foo ( a integer primary key, b text )')
27
+ $db1.transaction do
28
+ $db1.execute('delete from foo')
29
+ rows = count.times.map { "hello#{rand(1000)}" }
30
+ $db1.batch_execute('insert into foo (b) values (?)', rows)
31
+ end
32
+ end
33
+
34
+ def extralite_run1(count)
35
+ results = $db1.query('select * from foo')
36
+ raise unless results.size == count
37
+ end
38
+
39
+ def extralite_run2(count)
40
+ results = $db2.query('select * from foo')
41
+ raise unless results.size == count
42
+ end
43
+
44
+ def extralite_run3(count)
45
+ results = $db3.query('select * from foo')
46
+ raise unless results.size == count
47
+ end
48
+
49
+ [10, 1000, 100000].each do |c|
50
+ puts "Record count: #{c}"
51
+ prepare_database(c)
52
+
53
+ bm = Benchmark.ips do |x|
54
+ x.config(:time => 3, :warmup => 1)
55
+
56
+ x.report('GVL threshold -1') { extralite_run1(c) }
57
+ x.report('GVL threshold 0') { extralite_run2(c) }
58
+ $snooze_count = 0
59
+ x.report('on_progress 1000') { extralite_run3(c) }
60
+
61
+ x.compare!
62
+ end
63
+ puts;
64
+ bm.entries.each do |e|
65
+ score = (e.ips * c).round.to_i
66
+ if e.label == 'on_progress 1000'
67
+ snooze_rate = ($snooze_count / e.seconds).to_i
68
+ puts "#{e.label}: #{score} rows/s snoozes: #{snooze_rate} i/s"
69
+ else
70
+ puts "#{e.label}: #{score} rows/s"
71
+ end
72
+ end
73
+ puts;
74
+ end