rubydb 0.1.5 → 0.1.6

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 (88) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +4 -0
  3. data/CHANGELOG.md +14 -0
  4. data/Gemfile.lock +1 -1
  5. data/README.md +296 -227
  6. data/Rakefile +6 -1
  7. data/accelerator/bin/SHA256SUMS +6 -0
  8. data/accelerator/bin/rubydb-accelerator-darwin-amd64 +0 -0
  9. data/accelerator/bin/rubydb-accelerator-darwin-arm64 +0 -0
  10. data/accelerator/bin/rubydb-accelerator-linux-amd64 +0 -0
  11. data/accelerator/bin/rubydb-accelerator-linux-arm64 +0 -0
  12. data/accelerator/bin/rubydb-accelerator-windows-amd64.exe +0 -0
  13. data/accelerator/bin/rubydb-accelerator-windows-arm64.exe +0 -0
  14. data/accelerator/cmd/rubydb-accelerator/main.go +11 -0
  15. data/accelerator/go.mod +3 -0
  16. data/accelerator/internal/execution/aggregate.go +94 -0
  17. data/accelerator/internal/execution/distinct.go +22 -0
  18. data/accelerator/internal/execution/filter.go +73 -0
  19. data/accelerator/internal/execution/join.go +79 -0
  20. data/accelerator/internal/execution/operators.go +167 -0
  21. data/accelerator/internal/execution/scan.go +20 -0
  22. data/accelerator/internal/execution/sort.go +62 -0
  23. data/accelerator/internal/execution/types.go +136 -0
  24. data/accelerator/internal/execution/value.go +67 -0
  25. data/accelerator/internal/memory/arena.go +47 -0
  26. data/accelerator/internal/memory/reuse.go +22 -0
  27. data/accelerator/internal/metrics/registry.go +67 -0
  28. data/accelerator/internal/parallel/bounded_queue.go +56 -0
  29. data/accelerator/internal/parallel/scheduler.go +47 -0
  30. data/accelerator/internal/parallel/worker_pool.go +53 -0
  31. data/accelerator/internal/protocol/cancellation.go +48 -0
  32. data/accelerator/internal/protocol/columnar.go +263 -0
  33. data/accelerator/internal/protocol/frame.go +187 -0
  34. data/accelerator/internal/runtime/worker.go +521 -0
  35. data/accelerator/internal/storage/page_reader.go +81 -0
  36. data/accelerator/internal/storage/snapshot_scan.go +539 -0
  37. data/accelerator/internal/wal/checksum.go +13 -0
  38. data/accelerator/internal/wal/compression.go +41 -0
  39. data/accelerator/internal/wal/group_commit.go +24 -0
  40. data/accelerator/internal/wal/record_encoder.go +40 -0
  41. data/adapters/activerecord/README.md +8 -3
  42. data/adapters/activerecord/lib/active_record/connection_adapters/rubydb_adapter.rb +50 -42
  43. data/adapters/activerecord/rubydb-activerecord.gemspec +1 -1
  44. data/docs/README.md +3 -1
  45. data/docs/architecture/go-accelerator.md +179 -0
  46. data/docs/cli.md +24 -0
  47. data/docs/contributing/benchmarking.md +16 -0
  48. data/docs/developer/local-development.md +32 -0
  49. data/docs/release.md +2 -2
  50. data/lessons/02-local-development.md +2 -2
  51. data/lessons/04-rails-complex-apps.md +2 -2
  52. data/lessons/05-rubydb-production-server.md +2 -2
  53. data/lessons/07-hybrid-microservices.md +175 -90
  54. data/lessons/10-release-readiness.md +184 -117
  55. data/lessons/11-community-adapter.md +323 -0
  56. data/lessons/12-rails-ecommerce-pressure.md +263 -0
  57. data/lib/rubydb/accelerator/client.rb +451 -0
  58. data/lib/rubydb/accelerator/error.rb +22 -0
  59. data/lib/rubydb/accelerator/manager.rb +606 -0
  60. data/lib/rubydb/accelerator.rb +13 -0
  61. data/lib/rubydb/cli/application.rb +6 -1
  62. data/lib/rubydb/cli/commands/accelerator.rb +72 -0
  63. data/lib/rubydb/cli/commands/doctor.rb +3 -0
  64. data/lib/rubydb/client/client.rb +7 -0
  65. data/lib/rubydb/client/connection.rb +15 -0
  66. data/lib/rubydb/client/result.rb +5 -1
  67. data/lib/rubydb/configuration/defaults.rb +12 -0
  68. data/lib/rubydb/configuration/validation.rb +8 -1
  69. data/lib/rubydb/execution/accelerator_dispatch.rb +30 -0
  70. data/lib/rubydb/execution/cost_model.rb +72 -0
  71. data/lib/rubydb/execution/executor.rb +373 -11
  72. data/lib/rubydb/execution/operator_selection.rb +57 -0
  73. data/lib/rubydb/execution/physical_plan.rb +47 -0
  74. data/lib/rubydb/execution/planner.rb +12 -46
  75. data/lib/rubydb/execution/sort_executor.rb +22 -8
  76. data/lib/rubydb/indexes/btree.rb +31 -2
  77. data/lib/rubydb/rubydb.rb +7 -1
  78. data/lib/rubydb/server/session.rb +45 -0
  79. data/lib/rubydb/storage/engine.rb +74 -12
  80. data/lib/rubydb/storage/snapshot_reader.rb +167 -0
  81. data/lib/rubydb/version.rb +1 -1
  82. data/lib/rubydb/wal/archive.rb +17 -0
  83. data/lib/rubydb/wal/wal.rb +1 -0
  84. data/rubydb.gemspec +12 -2
  85. data/scripts/build_accelerator +49 -0
  86. data/scripts/release +34 -4
  87. data/scripts/replication_failover_drill +2 -2
  88. metadata +49 -1
@@ -0,0 +1,49 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require "fileutils"
5
+ require "digest"
6
+ require "rbconfig"
7
+
8
+ root = File.expand_path("..", __dir__)
9
+ accelerator = File.join(root, "accelerator")
10
+ output_dir = File.join(accelerator, "bin")
11
+ FileUtils.mkdir_p(output_dir)
12
+
13
+ go = ENV["GO"]
14
+ if go.nil? || go.empty?
15
+ candidates = [
16
+ File.join(ENV.fetch("ProgramFiles", "C:/Program Files"), "Go", "bin", "go.exe"),
17
+ File.join(ENV.fetch("ProgramW6432", "C:/Program Files"), "Go", "bin", "go.exe"),
18
+ "go"
19
+ ]
20
+ go = candidates.find { |candidate| candidate == "go" || File.file?(candidate) }
21
+ end
22
+
23
+ abort "Go compiler not found. Set GO to the go executable or install Go." unless go
24
+
25
+ targets = ENV.fetch("RUBYDB_ACCELERATOR_TARGETS", "windows-amd64,windows-arm64,linux-amd64,linux-arm64,darwin-amd64,darwin-arm64").split(",").map(&:strip).reject(&:empty?)
26
+ targets = ["#{ENV.fetch("GOOS", RbConfig::CONFIG["host_os"].to_s.match?(/mswin|mingw|cygwin/i) ? "windows" : "linux")}-#{ENV.fetch("GOARCH", "amd64")}"] if ENV["RUBYDB_ACCELERATOR_TARGETS"] == "current"
27
+
28
+ targets.each do |target|
29
+ os, arch = target.split("-", 2)
30
+ abort "Invalid accelerator target #{target.inspect}; use os-arch" unless os && arch
31
+
32
+ extension = (os == "windows") ? ".exe" : ""
33
+ output = File.join(output_dir, "rubydb-accelerator-#{os}-#{arch}#{extension}")
34
+ env = {"GOOS" => os, "GOARCH" => arch, "CGO_ENABLED" => "0"}
35
+ command = [go, "build", "-trimpath", "-ldflags=-s -w", "-o", output, "./cmd/rubydb-accelerator"]
36
+ puts "Building #{os}/#{arch} -> #{output}"
37
+ Dir.chdir(accelerator) do
38
+ abort "Go build failed for #{target}" unless system(env, *command)
39
+ end
40
+ FileUtils.chmod(0o755, output) unless os == "windows"
41
+ end
42
+
43
+ manifest = Dir[File.join(output_dir, "rubydb-accelerator-*")].sort.filter_map do |path|
44
+ next unless File.file?(path)
45
+
46
+ "#{Digest::SHA256.file(path).hexdigest} #{File.basename(path)}"
47
+ end
48
+ File.write(File.join(output_dir, "SHA256SUMS"), "#{manifest.join("\n")}\n")
49
+ puts "RubyDB accelerator binaries are ready in #{output_dir}"
data/scripts/release CHANGED
@@ -2,6 +2,7 @@
2
2
  # frozen_string_literal: true
3
3
 
4
4
  require "digest"
5
+ require "fileutils"
5
6
  require "rbconfig"
6
7
  require "rubygems"
7
8
 
@@ -9,13 +10,14 @@ root = File.expand_path("..", __dir__)
9
10
  Dir.chdir(root)
10
11
 
11
12
  abort "release metadata preflight failed" unless system(RbConfig.ruby, File.join(root, "scripts", "release_check"))
13
+ abort "Go accelerator build failed" unless system(RbConfig.ruby, File.join(root, "scripts", "build_accelerator"))
12
14
 
13
15
  release_descriptors = [
14
16
  "rubydb.gemspec",
15
17
  "adapters/activerecord/rubydb-activerecord.gemspec",
16
18
  "packaging/homebrew/rubydb.rb"
17
19
  ]
18
- untracked_runtime_files = `git ls-files --others --exclude-standard -- lib exe rubydb.gemspec`.lines.map(&:chomp)
20
+ untracked_runtime_files = `git ls-files --others --exclude-standard -- lib exe accelerator rubydb.gemspec`.lines.map(&:chomp)
19
21
  unless untracked_runtime_files.empty?
20
22
  abort "Runtime files are untracked and would be omitted from the gem: #{untracked_runtime_files.join(", ")}. Commit them before publishing."
21
23
  end
@@ -42,14 +44,42 @@ expected = File.read(checksum_path).split.first
42
44
  actual = Digest::SHA512.file(gem_path).hexdigest
43
45
  abort "Checksum verification failed" unless expected == actual
44
46
 
47
+ # Build the ActiveRecord adapter alongside the core release. Its version is
48
+ # intentionally independent so Rails applications can pin the adapter while
49
+ # remaining on the RubyDB 0.1.x compatibility line.
50
+ adapter_dir = File.join(root, "adapters", "activerecord")
51
+ adapter_spec = Dir.chdir(adapter_dir) { Gem::Specification.load("rubydb-activerecord.gemspec") }
52
+ abort "Unable to load ActiveRecord adapter gemspec" unless adapter_spec
53
+ adapter_pkg_dir = File.join(adapter_dir, "pkg")
54
+ FileUtils.mkdir_p(adapter_pkg_dir)
55
+ adapter_gem_path = File.join(adapter_pkg_dir, "rubydb-activerecord-#{adapter_spec.version}.gem")
56
+ abort "ActiveRecord adapter gem build failed" unless system(
57
+ "gem", "build", "-V", "rubydb-activerecord.gemspec", "--output", adapter_gem_path,
58
+ chdir: adapter_dir
59
+ )
60
+ adapter_checksum_dir = File.join(root, "checksums")
61
+ FileUtils.mkdir_p(adapter_checksum_dir)
62
+ adapter_checksum_path = File.join(adapter_checksum_dir, "#{File.basename(adapter_gem_path)}.sha512")
63
+ adapter_expected = Digest::SHA512.file(adapter_gem_path).hexdigest
64
+ File.write(adapter_checksum_path, "#{adapter_expected} #{File.basename(adapter_gem_path)}\n")
65
+ abort "ActiveRecord adapter checksum verification failed" unless
66
+ Digest::SHA512.file(adapter_gem_path).hexdigest == File.read(adapter_checksum_path).split.first
67
+ puts "Adapter #{adapter_spec.name} #{adapter_spec.version} built to #{adapter_gem_path}."
68
+ puts "Adapter checksum written to #{adapter_checksum_path}"
69
+
45
70
  if ENV["RUBYDB_PUBLISH"] == "1"
71
+ puts "RubyGems 2FA/OTP settings: https://rubygems.org/profile/edit"
72
+ puts "If prompted for an OTP, enter the current code from your authenticator."
46
73
  api_key = ENV.fetch("GEM_HOST_API_KEY", "")
47
74
  credentials_path = Gem.configuration.credentials_path
48
75
  credentials_available = File.file?(credentials_path) && !File.zero?(credentials_path)
49
76
  abort "Set GEM_HOST_API_KEY or configure RubyGems credentials at #{credentials_path}" if api_key.empty? && !credentials_available
50
- abort "gem push failed" unless system("gem", "push", gem_path)
51
- puts "Published #{gem_path}"
77
+ [gem_path, adapter_gem_path].each do |artifact|
78
+ abort "gem push failed for #{artifact}" unless system("gem", "push", artifact)
79
+ puts "Published #{artifact}"
80
+ end
52
81
  else
53
82
  puts "Release artifact verified: #{gem_path}"
54
- puts "To publish: RUBYDB_PUBLISH=1 GEM_HOST_API_KEY=<RubyGems API key> ruby scripts/release"
83
+ puts "Release artifact verified: #{adapter_gem_path}"
84
+ puts "To publish both: RUBYDB_PUBLISH=1 GEM_HOST_API_KEY=<RubyGems API key> ruby scripts/release"
55
85
  end
@@ -125,7 +125,7 @@ def spawn_node(role, directory, port, fence_path)
125
125
  {stdin: stdin, stdout: stdout, stderr: stderr, wait: wait_thread, stderr_thread: stderr_thread}
126
126
  end
127
127
 
128
- def read_event(node, timeout: 10)
128
+ def read_event(node, timeout: 60)
129
129
  Timeout.timeout(timeout) do
130
130
  loop do
131
131
  ready = IO.select([node[:stdout]], nil, nil, 0.1)
@@ -145,7 +145,7 @@ def command(node, name, payload = {})
145
145
  read_event(node)
146
146
  end
147
147
 
148
- def wait_until(timeout: 30)
148
+ def wait_until(timeout: 60)
149
149
  Timeout.timeout(timeout) do
150
150
  loop do
151
151
  return true if yield
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rubydb
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.5
4
+ version: 0.1.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - Aldane Hutchinson
@@ -154,6 +154,40 @@ files:
154
154
  - Rakefile
155
155
  - SECURITY.md
156
156
  - SUPPORT.md
157
+ - accelerator/bin/SHA256SUMS
158
+ - accelerator/bin/rubydb-accelerator-darwin-amd64
159
+ - accelerator/bin/rubydb-accelerator-darwin-arm64
160
+ - accelerator/bin/rubydb-accelerator-linux-amd64
161
+ - accelerator/bin/rubydb-accelerator-linux-arm64
162
+ - accelerator/bin/rubydb-accelerator-windows-amd64.exe
163
+ - accelerator/bin/rubydb-accelerator-windows-arm64.exe
164
+ - accelerator/cmd/rubydb-accelerator/main.go
165
+ - accelerator/go.mod
166
+ - accelerator/internal/execution/aggregate.go
167
+ - accelerator/internal/execution/distinct.go
168
+ - accelerator/internal/execution/filter.go
169
+ - accelerator/internal/execution/join.go
170
+ - accelerator/internal/execution/operators.go
171
+ - accelerator/internal/execution/scan.go
172
+ - accelerator/internal/execution/sort.go
173
+ - accelerator/internal/execution/types.go
174
+ - accelerator/internal/execution/value.go
175
+ - accelerator/internal/memory/arena.go
176
+ - accelerator/internal/memory/reuse.go
177
+ - accelerator/internal/metrics/registry.go
178
+ - accelerator/internal/parallel/bounded_queue.go
179
+ - accelerator/internal/parallel/scheduler.go
180
+ - accelerator/internal/parallel/worker_pool.go
181
+ - accelerator/internal/protocol/cancellation.go
182
+ - accelerator/internal/protocol/columnar.go
183
+ - accelerator/internal/protocol/frame.go
184
+ - accelerator/internal/runtime/worker.go
185
+ - accelerator/internal/storage/page_reader.go
186
+ - accelerator/internal/storage/snapshot_scan.go
187
+ - accelerator/internal/wal/checksum.go
188
+ - accelerator/internal/wal/compression.go
189
+ - accelerator/internal/wal/group_commit.go
190
+ - accelerator/internal/wal/record_encoder.go
157
191
  - adapters/activerecord/Gemfile
158
192
  - adapters/activerecord/README.md
159
193
  - adapters/activerecord/lib/active_record/connection_adapters/rubydb_adapter.rb
@@ -171,6 +205,7 @@ files:
171
205
  - docs/architecture/concurrency.md
172
206
  - docs/architecture/current-state.md
173
207
  - docs/architecture/execution-engine.md
208
+ - docs/architecture/go-accelerator.md
174
209
  - docs/architecture/indexes.md
175
210
  - docs/architecture/mvcc.md
176
211
  - docs/architecture/overview.md
@@ -252,7 +287,13 @@ files:
252
287
  - lessons/08-migrations-backups-recovery.md
253
288
  - lessons/09-observability-security-scale.md
254
289
  - lessons/10-release-readiness.md
290
+ - lessons/11-community-adapter.md
291
+ - lessons/12-rails-ecommerce-pressure.md
255
292
  - lib/rubydb.rb
293
+ - lib/rubydb/accelerator.rb
294
+ - lib/rubydb/accelerator/client.rb
295
+ - lib/rubydb/accelerator/error.rb
296
+ - lib/rubydb/accelerator/manager.rb
256
297
  - lib/rubydb/backup/archive.rb
257
298
  - lib/rubydb/backup/backup.rb
258
299
  - lib/rubydb/backup/incremental.rb
@@ -279,6 +320,7 @@ files:
279
320
  - lib/rubydb/catalog/trigger.rb
280
321
  - lib/rubydb/catalog/view.rb
281
322
  - lib/rubydb/cli/application.rb
323
+ - lib/rubydb/cli/commands/accelerator.rb
282
324
  - lib/rubydb/cli/commands/backup.rb
283
325
  - lib/rubydb/cli/commands/branch.rb
284
326
  - lib/rubydb/cli/commands/checkout.rb
@@ -345,7 +387,9 @@ files:
345
387
  - lib/rubydb/errors/server_error.rb
346
388
  - lib/rubydb/errors/storage_error.rb
347
389
  - lib/rubydb/errors/transaction_error.rb
390
+ - lib/rubydb/execution/accelerator_dispatch.rb
348
391
  - lib/rubydb/execution/aggregate_executor.rb
392
+ - lib/rubydb/execution/cost_model.rb
349
393
  - lib/rubydb/execution/delete_executor.rb
350
394
  - lib/rubydb/execution/distinct_executor.rb
351
395
  - lib/rubydb/execution/executor.rb
@@ -354,7 +398,9 @@ files:
354
398
  - lib/rubydb/execution/insert_executor.rb
355
399
  - lib/rubydb/execution/join_executor.rb
356
400
  - lib/rubydb/execution/limit_executor.rb
401
+ - lib/rubydb/execution/operator_selection.rb
357
402
  - lib/rubydb/execution/optimizer.rb
403
+ - lib/rubydb/execution/physical_plan.rb
358
404
  - lib/rubydb/execution/plan.rb
359
405
  - lib/rubydb/execution/planner.rb
360
406
  - lib/rubydb/execution/predicate.rb
@@ -502,6 +548,7 @@ files:
502
548
  - lib/rubydb/storage/record.rb
503
549
  - lib/rubydb/storage/row.rb
504
550
  - lib/rubydb/storage/serializer.rb
551
+ - lib/rubydb/storage/snapshot_reader.rb
505
552
  - lib/rubydb/storage/storage_layout.rb
506
553
  - lib/rubydb/storage/storage_manager.rb
507
554
  - lib/rubydb/storage/tuple.rb
@@ -547,6 +594,7 @@ files:
547
594
  - packaging/systemd/rubydb.service
548
595
  - rubydb.gemspec
549
596
  - scripts/benchmark
597
+ - scripts/build_accelerator
550
598
  - scripts/durability_drill
551
599
  - scripts/format
552
600
  - scripts/fuzz