litestack 0.2.3 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
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