litestack 0.2.3 → 0.3.0

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 (43) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +16 -0
  3. data/Gemfile +2 -0
  4. data/README.md +5 -11
  5. data/assets/event_page.png +0 -0
  6. data/assets/index_page.png +0 -0
  7. data/assets/topic_page.png +0 -0
  8. data/bench/bench_jobs_rails.rb +1 -1
  9. data/bench/bench_jobs_raw.rb +1 -1
  10. data/bin/liteboard +81 -0
  11. data/lib/action_cable/subscription_adapter/litecable.rb +1 -11
  12. data/lib/generators/litestack/install/USAGE +11 -0
  13. data/lib/generators/litestack/install/install_generator.rb +35 -0
  14. data/lib/generators/litestack/install/templates/cable.yml +11 -0
  15. data/lib/generators/litestack/install/templates/database.yml +34 -0
  16. data/lib/litestack/liteboard/liteboard.rb +305 -0
  17. data/lib/litestack/liteboard/views/event.erb +32 -0
  18. data/lib/litestack/liteboard/views/index.erb +54 -0
  19. data/lib/litestack/liteboard/views/layout.erb +303 -0
  20. data/lib/litestack/liteboard/views/litecable.erb +118 -0
  21. data/lib/litestack/liteboard/views/litecache.erb +144 -0
  22. data/lib/litestack/liteboard/views/litedb.erb +168 -0
  23. data/lib/litestack/liteboard/views/litejob.erb +151 -0
  24. data/lib/litestack/liteboard/views/topic.erb +48 -0
  25. data/lib/litestack/litecable.rb +25 -35
  26. data/lib/litestack/litecable.sql.yml +1 -1
  27. data/lib/litestack/litecache.rb +31 -28
  28. data/lib/litestack/litedb.rb +124 -1
  29. data/lib/litestack/litejob.rb +2 -2
  30. data/lib/litestack/litejobqueue.rb +8 -8
  31. data/lib/litestack/litemetric.rb +177 -88
  32. data/lib/litestack/litemetric.sql.yml +312 -42
  33. data/lib/litestack/litemetric_collector.sql.yml +56 -0
  34. data/lib/litestack/litequeue.rb +28 -29
  35. data/lib/litestack/litequeue.sql.yml +11 -0
  36. data/lib/litestack/litesupport.rb +137 -57
  37. data/lib/litestack/railtie.rb +10 -0
  38. data/lib/litestack/version.rb +1 -1
  39. data/lib/litestack.rb +1 -0
  40. data/lib/sequel/adapters/litedb.rb +1 -1
  41. data/template.rb +7 -0
  42. metadata +81 -5
  43. data/lib/litestack/metrics_app.rb +0 -5
@@ -4,47 +4,66 @@ require 'sqlite3'
4
4
  require 'logger'
5
5
  require 'oj'
6
6
  require 'yaml'
7
+ require 'pathname'
8
+ require 'fileutils'
7
9
 
8
10
  module Litesupport
9
11
 
10
12
  class Error < StandardError; end
11
13
 
12
- # cache the environment we are running in
13
- # it is an error to change the environment for a process
14
- # or for a child forked from that process
15
- def self.environment
16
- @env ||= detect_environment
17
- end
18
-
19
14
  def self.max_contexts
20
- return 50 if environment == :fiber || environment == :polyphony
15
+ return 50 if scheduler == :fiber || scheduler == :polyphony
21
16
  5
22
17
  end
23
-
24
- # identify which environment we are running in
25
- # we currently support :fiber, :polyphony, :iodine & :threaded
26
- # in the future we might want to expand to other environments
18
+
19
+ # Detect the Rack or Rails environment.
27
20
  def self.detect_environment
21
+ if defined? Rails
22
+ Rails.env
23
+ elsif ENV["RACK_ENV"]
24
+ ENV["RACK_ENV"]
25
+ elsif ENV["APP_ENV"]
26
+ ENV["APP_ENV"]
27
+ else
28
+ "development"
29
+ end
30
+ end
31
+
32
+ def self.environment
33
+ @environment ||= detect_environment
34
+ end
35
+
36
+ # cache the scheduler we are running in
37
+ # it is an error to change the scheduler for a process
38
+ # or for a child forked from that process
39
+ def self.scheduler
40
+ @scehduler ||= detect_scheduler
41
+ end
42
+
43
+ # identify which scheduler we are running in
44
+ # we currently support :fiber, :polyphony, :iodine & :threaded
45
+ # in the future we might want to expand to other schedulers
46
+ def self.detect_scheduler
28
47
  return :fiber if Fiber.scheduler
29
48
  return :polyphony if defined? Polyphony
30
49
  return :iodine if defined? Iodine
31
- return :threaded # fall back for all other environments
50
+ return :threaded # fall back for all other schedulers
32
51
  end
33
52
 
34
53
  # spawn a new execution context
35
54
  def self.spawn(&block)
36
- if self.environment == :fiber
55
+ if self.scheduler == :fiber
37
56
  Fiber.schedule(&block)
38
- elsif self.environment == :polyphony
57
+ elsif self.scheduler == :polyphony
39
58
  spin(&block)
40
- elsif self.environment == :threaded or self.environment == :iodine
59
+ elsif self.scheduler == :threaded or self.scheduler == :iodine
41
60
  Thread.new(&block)
42
61
  end
43
62
  # we should never reach here
44
63
  end
45
-
64
+
46
65
  def self.context
47
- if environment == :fiber || environment == :poylphony
66
+ if scheduler == :fiber || scheduler == :poylphony
48
67
  Fiber.current.storage
49
68
  else
50
69
  Thread.current
@@ -52,7 +71,7 @@ module Litesupport
52
71
  end
53
72
 
54
73
  def self.current_context
55
- if environment == :fiber || environment == :poylphony
74
+ if scheduler == :fiber || scheduler == :poylphony
56
75
  Fiber.current
57
76
  else
58
77
  Thread.current
@@ -61,10 +80,10 @@ module Litesupport
61
80
 
62
81
  # switch the execution context to allow others to run
63
82
  def self.switch
64
- if self.environment == :fiber
83
+ if self.scheduler == :fiber
65
84
  Fiber.scheduler.yield
66
85
  true
67
- elsif self.environment == :polyphony
86
+ elsif self.scheduler == :polyphony
68
87
  Fiber.current.schedule
69
88
  Thread.current.switch_fiber
70
89
  true
@@ -80,12 +99,12 @@ module Litesupport
80
99
  @@mutex ||= Mutex.new
81
100
  end
82
101
 
83
- # bold assumption, we will only synchronize threaded code
84
- # if some code explicitly wants to synchronize a fiber
102
+ # bold assumption, we will only synchronize threaded code!
103
+ # If some code explicitly wants to synchronize a fiber
85
104
  # they must send (true) as a parameter to this method
86
105
  # else it is a no-op for fibers
87
106
  def self.synchronize(fiber_sync = false, &block)
88
- if self.environment == :fiber or self.environment == :polyphony
107
+ if self.scheduler == :fiber or self.scheduler == :polyphony
89
108
  yield # do nothing, just run the block as is
90
109
  else
91
110
  self.mutex.synchronize(&block)
@@ -103,7 +122,30 @@ module Litesupport
103
122
  end
104
123
  db
105
124
  end
106
-
125
+
126
+ # Databases will be stored by default at this path.
127
+ def self.root
128
+ @root ||= ensure_root_volume detect_root
129
+ end
130
+
131
+ # Default path where we'll store all of the databases.
132
+ def self.detect_root
133
+ path = if ENV["LITESTACK_DATA_PATH"]
134
+ ENV["LITESTACK_DATA_PATH"]
135
+ elsif defined? Rails
136
+ "./db"
137
+ else
138
+ "."
139
+ end
140
+
141
+ Pathname.new(path).join(Litesupport.environment)
142
+ end
143
+
144
+ def self.ensure_root_volume(path)
145
+ FileUtils.mkdir_p path unless path.exist?
146
+ path
147
+ end
148
+
107
149
  class Mutex
108
150
 
109
151
  def initialize
@@ -111,7 +153,7 @@ module Litesupport
111
153
  end
112
154
 
113
155
  def synchronize(&block)
114
- if Litesupport.environment == :threaded || Litesupport.environment == :iodine
156
+ if Litesupport.scheduler == :threaded || Litesupport.scheduler == :iodine
115
157
  @mutex.synchronize{ block.call }
116
158
  else
117
159
  block.call
@@ -120,21 +162,6 @@ module Litesupport
120
162
 
121
163
  end
122
164
 
123
- module Forkable
124
-
125
- def _fork(*args)
126
- ppid = Process.pid
127
- result = super
128
- if Process.pid != ppid
129
- # trigger a restart of all connections owned by Litesupport::Pool
130
- end
131
- result
132
- end
133
-
134
- end
135
-
136
- #::Process.singleton_class.prepend(::Litesupport::Forkable)
137
-
138
165
  class Pool
139
166
 
140
167
  def initialize(count, &block)
@@ -188,7 +215,7 @@ module Litesupport
188
215
  def _fork(*args)
189
216
  ppid = Process.pid
190
217
  result = super
191
- if Process.pid != ppid && [:threaded, :iodine].include?(Litesupport.environment)
218
+ if Process.pid != ppid && [:threaded, :iodine].include?(Litesupport.scheduler)
192
219
  ForkListener.listeners.each{|l| l.call }
193
220
  end
194
221
  result
@@ -201,6 +228,11 @@ module Litesupport
201
228
  include Forkable
202
229
 
203
230
  # close, setup, run_stmt and run_sql assume a single connection was created
231
+
232
+ def options
233
+ @options
234
+ end
235
+
204
236
  def close
205
237
  @running = false
206
238
  @conn.acquire do |q|
@@ -209,6 +241,22 @@ module Litesupport
209
241
  end
210
242
  end
211
243
 
244
+ def size
245
+ run_sql("SELECT size.page_size * count.page_count FROM pragma_page_size() AS size, pragma_page_count() AS count")[0][0].to_f / (1024*1024)
246
+ end
247
+
248
+ def journal_mode
249
+ run_method(:journal_mode)
250
+ end
251
+
252
+ def synchronous
253
+ run_method(:synchronous)
254
+ end
255
+
256
+ def path
257
+ run_method(:filename)
258
+ end
259
+
212
260
  private # all methods are private
213
261
 
214
262
  def init(options = {})
@@ -224,22 +272,14 @@ module Litesupport
224
272
  Litesupport::ForkListener.listen do
225
273
  setup
226
274
  end
227
- end
228
-
275
+ end
276
+
229
277
  def configure(options = {})
230
- # detect environment (production, development, etc.)
231
- env = "development"
232
- if defined? Rails
233
- env = ENV["RAILS_ENV"]
234
- elsif ENV["RACK_ENV"]
235
- env = ENV["RACK_ENV"]
236
- elsif ENV["APP_ENV"]
237
- env = ENV["RACK_ENV"]
238
- end
278
+ # detect enviornment (production, development, etc.)
239
279
  defaults = self.class::DEFAULT_OPTIONS rescue {}
240
280
  @options = defaults.merge(options)
241
281
  config = YAML.load_file(@options[:config_path]) rescue {} # an empty hash won't hurt
242
- config = config[env] if config[env] # if there is a config for the current environment defined then use it, otherwise use the top level declaration
282
+ config = config[Litesupport.environment] if config[Litesupport.environment] # if there is a config for the current enviornment defined then use it, otherwise use the top level declaration
243
283
  config.keys.each do |k| # symbolize keys
244
284
  config[k.to_sym] = config[k]
245
285
  config.delete k
@@ -266,7 +306,7 @@ module Litesupport
266
306
  def exit_callback
267
307
  close
268
308
  end
269
-
309
+
270
310
  def run_stmt(stmt, *args)
271
311
  @conn.acquire{|q| q.stmts[stmt].execute!(*args) }
272
312
  end
@@ -275,12 +315,21 @@ module Litesupport
275
315
  @conn.acquire{|q| q.execute(sql, *args) }
276
316
  end
277
317
 
318
+ def run_method(method, *args)
319
+ @conn.acquire{|q| q.send(method, *args)}
320
+ end
321
+
322
+ def run_stmt_method(stmt, method, *args)
323
+ @conn.acquire{|q| q.stmts[stmt].send(method, *args)}
324
+ end
325
+
326
+
278
327
  def create_pooled_connection(count = 1)
279
328
  Litesupport::Pool.new(1){create_connection}
280
329
  end
281
330
 
282
331
  # common db object options
283
- def create_connection
332
+ def create_connection(path_to_sql_file = nil)
284
333
  conn = SQLite3::Database.new(@options[:path])
285
334
  conn.busy_handler{ Litesupport.switch || sleep(rand * 0.002) }
286
335
  conn.journal_mode = "WAL"
@@ -290,9 +339,40 @@ module Litesupport
290
339
  class << conn
291
340
  attr_reader :stmts
292
341
  end
342
+ yield conn if block_given?
343
+ # use the <client>.sql.yml file to define the schema and compile prepared statements
344
+ unless path_to_sql_file.nil?
345
+ sql = YAML.load_file(path_to_sql_file)
346
+ version = conn.get_first_value("PRAGMA user_version")
347
+ sql["schema"].each_pair do |v, obj|
348
+ if v > version
349
+ conn.transaction do
350
+ obj.each do |k, s|
351
+ begin
352
+ conn.execute(s)
353
+ rescue Exception => e
354
+ STDERR.puts "Error parsing #{k}"
355
+ STDERR.puts s
356
+ raise e
357
+ end
358
+ end
359
+ conn.user_version = v
360
+ end
361
+ end
362
+ end
363
+ sql["stmts"].each do |k, v|
364
+ begin
365
+ conn.stmts[k.to_sym] = conn.prepare(v)
366
+ rescue Exception => e
367
+ STDERR.puts "Error parsing #{k}"
368
+ STDERR.puts v
369
+ raise e
370
+ end
371
+ end
372
+ end
293
373
  conn
294
374
  end
295
-
375
+
296
376
  end
297
377
 
298
378
  end
@@ -0,0 +1,10 @@
1
+ require "rails/railtie"
2
+
3
+ module Litestack
4
+ class Railtie < ::Rails::Railtie
5
+ initializer :disable_production_sqlite_warning do |app|
6
+ # The whole point of this gem is to use sqlite3 in production.
7
+ app.config.active_record.sqlite3_production_warning = false
8
+ end
9
+ end
10
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Litestack
4
- VERSION = "0.2.3"
4
+ VERSION = "0.3.0"
5
5
  end
data/lib/litestack.rb CHANGED
@@ -16,6 +16,7 @@ require_relative "./railties/rails/commands/dbconsole" if defined? Rails && defi
16
16
  require_relative "./active_support/cache/litecache" if defined? ActiveSupport
17
17
  require_relative "./active_job/queue_adapters/litejob_adapter" if defined? ActiveJob
18
18
  require_relative "./action_cable/subscription_adapter/litecable" if defined? ActionCable
19
+ require_relative "./litestack/railtie" if defined? Rails::Railtie
19
20
 
20
21
  module Litestack
21
22
  class NotImplementedError < Exception; end
@@ -15,7 +15,7 @@ module Sequel
15
15
 
16
16
  def connect(server)
17
17
 
18
- Sequel.extension :fiber_concurrency if [:fiber, :polyphony].include? Litesupport.environment
18
+ Sequel.extension :fiber_concurrency if [:fiber, :polyphony].include? Litesupport.scheduler
19
19
 
20
20
  opts = server_opts(server)
21
21
  opts[:database] = ':memory:' if blank_object?(opts[:database])
data/template.rb ADDED
@@ -0,0 +1,7 @@
1
+ # Run `rails new my-app -m https://raw.githubusercontent.com/bradgessler/litestack/master/template.rb`
2
+ # to create a new Rails app with Litestack pre-installed.
3
+ gem "litestack", github: "bradgessler/litestack"
4
+
5
+ after_bundle do
6
+ generate "litestack:install"
7
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: litestack
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.3
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Mohamed Hassan
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-05-18 00:00:00.000000000 Z
11
+ date: 2023-08-13 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: sqlite3
@@ -38,10 +38,67 @@ dependencies:
38
38
  - - ">="
39
39
  - !ruby/object:Gem::Version
40
40
  version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rack
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: hanami-router
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: tilt
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: erubi
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :runtime
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
41
97
  description:
42
98
  email:
43
99
  - oldmoe@gmail.com
44
- executables: []
100
+ executables:
101
+ - liteboard
45
102
  extensions: []
46
103
  extra_rdoc_files: []
47
104
  files:
@@ -52,12 +109,15 @@ files:
52
109
  - README.md
53
110
  - Rakefile
54
111
  - WHYLITESTACK.md
112
+ - assets/event_page.png
113
+ - assets/index_page.png
55
114
  - assets/litecable_logo_teal.png
56
115
  - assets/litecache_logo_teal.png
57
116
  - assets/litedb_logo_teal.png
58
117
  - assets/litejob_logo_teal.png
59
118
  - assets/litestack_logo_teal.png
60
119
  - assets/litestack_logo_teal_large.png
120
+ - assets/topic_page.png
61
121
  - bench/bench.rb
62
122
  - bench/bench_cache_rails.rb
63
123
  - bench/bench_cache_raw.rb
@@ -67,11 +127,25 @@ files:
67
127
  - bench/rails_job.rb
68
128
  - bench/skjob.rb
69
129
  - bench/uljob.rb
130
+ - bin/liteboard
70
131
  - lib/action_cable/subscription_adapter/litecable.rb
71
132
  - lib/active_job/queue_adapters/litejob_adapter.rb
72
133
  - lib/active_record/connection_adapters/litedb_adapter.rb
73
134
  - lib/active_support/cache/litecache.rb
135
+ - lib/generators/litestack/install/USAGE
136
+ - lib/generators/litestack/install/install_generator.rb
137
+ - lib/generators/litestack/install/templates/cable.yml
138
+ - lib/generators/litestack/install/templates/database.yml
74
139
  - lib/litestack.rb
140
+ - lib/litestack/liteboard/liteboard.rb
141
+ - lib/litestack/liteboard/views/event.erb
142
+ - lib/litestack/liteboard/views/index.erb
143
+ - lib/litestack/liteboard/views/layout.erb
144
+ - lib/litestack/liteboard/views/litecable.erb
145
+ - lib/litestack/liteboard/views/litecache.erb
146
+ - lib/litestack/liteboard/views/litedb.erb
147
+ - lib/litestack/liteboard/views/litejob.erb
148
+ - lib/litestack/liteboard/views/topic.erb
75
149
  - lib/litestack/litecable.rb
76
150
  - lib/litestack/litecable.sql.yml
77
151
  - lib/litestack/litecache.rb
@@ -82,15 +156,17 @@ files:
82
156
  - lib/litestack/litejobqueue.rb
83
157
  - lib/litestack/litemetric.rb
84
158
  - lib/litestack/litemetric.sql.yml
159
+ - lib/litestack/litemetric_collector.sql.yml
85
160
  - lib/litestack/litequeue.rb
86
161
  - lib/litestack/litequeue.sql.yml
87
162
  - lib/litestack/litesupport.rb
88
- - lib/litestack/metrics_app.rb
163
+ - lib/litestack/railtie.rb
89
164
  - lib/litestack/version.rb
90
165
  - lib/railties/rails/commands/dbconsole.rb
91
166
  - lib/sequel/adapters/litedb.rb
92
167
  - lib/sequel/adapters/shared/litedb.rb
93
168
  - samples/ultrajob.yaml
169
+ - template.rb
94
170
  homepage: http://github.com/oldmoe/litestack
95
171
  licenses:
96
172
  - MIT
@@ -115,7 +191,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
115
191
  - !ruby/object:Gem::Version
116
192
  version: '0'
117
193
  requirements: []
118
- rubygems_version: 3.4.8
194
+ rubygems_version: 3.4.17
119
195
  signing_key:
120
196
  specification_version: 4
121
197
  summary: A SQLite based, lightning fast, super efficient and dead simple to setup
@@ -1,5 +0,0 @@
1
- require_relative '../lib/litestack/litemetrics'
2
-
3
- metric = Litemetrics.instance
4
-
5
- puts metric.ids