rubydb 0.1.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 (436) hide show
  1. checksums.yaml +7 -0
  2. data/.gitattributes +20 -0
  3. data/.github/ISSUE_TEMPLATE/bug.yml +0 -0
  4. data/.github/ISSUE_TEMPLATE/feature.yml +0 -0
  5. data/.github/ISSUE_TEMPLATE/performance.yml +0 -0
  6. data/.github/ISSUE_TEMPLATE/security.yml +0 -0
  7. data/.github/PULL_REQUEST_TEMPLATE.md +15 -0
  8. data/.github/dependabot.yml +0 -0
  9. data/.github/workflows/benchmark.yml +26 -0
  10. data/.github/workflows/compatibility.yml +63 -0
  11. data/.github/workflows/fuzz.yml +33 -0
  12. data/.github/workflows/lint.yml +21 -0
  13. data/.github/workflows/operations.yml +24 -0
  14. data/.github/workflows/production-validation.yml +111 -0
  15. data/.github/workflows/release.yml +77 -0
  16. data/.github/workflows/security.yml +37 -0
  17. data/.github/workflows/test.yml +26 -0
  18. data/.github/workflows/workload.yml +58 -0
  19. data/.gitignore +43 -0
  20. data/.rspec +4 -0
  21. data/.rubocop.yml +44 -0
  22. data/.ruby-version +1 -0
  23. data/.standard.yml +14 -0
  24. data/ARCHITECTURE.md +21 -0
  25. data/CHANGELOG.md +31 -0
  26. data/CODE_OF_CONDUCT.md +13 -0
  27. data/CONTRIBUTING.md +29 -0
  28. data/GOVERNANCE.md +16 -0
  29. data/Gemfile +17 -0
  30. data/Gemfile.lock +71 -0
  31. data/LICENSE +60 -0
  32. data/README.md +162 -0
  33. data/ROADMAP.md +27 -0
  34. data/Rakefile +71 -0
  35. data/SECURITY.md +54 -0
  36. data/SUPPORT.md +14 -0
  37. data/adapters/activerecord/Gemfile +11 -0
  38. data/adapters/activerecord/README.md +9 -0
  39. data/adapters/activerecord/lib/active_record/connection_adapters/rubydb_adapter.rb +887 -0
  40. data/adapters/activerecord/rubydb-activerecord.gemspec +27 -0
  41. data/adapters/activerecord/spec/rubydb_adapter_integration_spec.rb +151 -0
  42. data/adapters/ruby/README.md +18 -0
  43. data/adapters/sequel/README.md +11 -0
  44. data/bin/rubydb +19 -0
  45. data/bin/rubydb-server +126 -0
  46. data/config/development.yml +0 -0
  47. data/config/monitoring/prometheus-alerts.yml +39 -0
  48. data/config/production.yml +36 -0
  49. data/config/test.yml +0 -0
  50. data/docs/README.md +71 -0
  51. data/docs/architecture/concurrency.md +14 -0
  52. data/docs/architecture/current-state.md +125 -0
  53. data/docs/architecture/execution-engine.md +25 -0
  54. data/docs/architecture/indexes.md +19 -0
  55. data/docs/architecture/mvcc.md +19 -0
  56. data/docs/architecture/overview.md +13 -0
  57. data/docs/architecture/pages.md +11 -0
  58. data/docs/architecture/production-roadmap.md +82 -0
  59. data/docs/architecture/query-planner.md +20 -0
  60. data/docs/architecture/recovery.md +18 -0
  61. data/docs/architecture/sql-engine.md +12 -0
  62. data/docs/architecture/storage-engine.md +14 -0
  63. data/docs/architecture/transactions.md +10 -0
  64. data/docs/architecture/wal.md +28 -0
  65. data/docs/cli-cheatsheet.md +98 -0
  66. data/docs/cli.md +275 -0
  67. data/docs/contributing/architecture.md +9 -0
  68. data/docs/contributing/benchmarking.md +14 -0
  69. data/docs/contributing/development.md +16 -0
  70. data/docs/contributing/release-process.md +49 -0
  71. data/docs/contributing/testing.md +16 -0
  72. data/docs/debugging.md +229 -0
  73. data/docs/developer/branching.md +10 -0
  74. data/docs/developer/database-diff.md +10 -0
  75. data/docs/developer/local-development.md +17 -0
  76. data/docs/developer/snapshots.md +9 -0
  77. data/docs/developer/temporal-data.md +10 -0
  78. data/docs/developer-guide.md +297 -0
  79. data/docs/getting-started/first-database.md +16 -0
  80. data/docs/getting-started/first-query.md +13 -0
  81. data/docs/getting-started/installation.md +19 -0
  82. data/docs/getting-started/local-to-production.md +300 -0
  83. data/docs/getting-started/quickstart.md +17 -0
  84. data/docs/getting-started/rails.md +16 -0
  85. data/docs/hardening_backlog.md +93 -0
  86. data/docs/lessons-learned.md +112 -0
  87. data/docs/operations/backups.md +33 -0
  88. data/docs/operations/disaster-recovery.md +31 -0
  89. data/docs/operations/failover.md +30 -0
  90. data/docs/operations/monitoring.md +25 -0
  91. data/docs/operations/production-guide.md +295 -0
  92. data/docs/operations/production-runbook.md +45 -0
  93. data/docs/operations/replication.md +33 -0
  94. data/docs/operations/restore.md +6 -0
  95. data/docs/operations/runbook.md +34 -0
  96. data/docs/operations/upgrades.md +14 -0
  97. data/docs/operations/workload-testing.md +17 -0
  98. data/docs/production-readiness.md +118 -0
  99. data/docs/production_validation.md +150 -0
  100. data/docs/rails/active-record.md +11 -0
  101. data/docs/rails/compatibility-guide.md +90 -0
  102. data/docs/rails/database-yml.md +92 -0
  103. data/docs/rails/installation.md +17 -0
  104. data/docs/rails/migrations.md +17 -0
  105. data/docs/rails/production.md +82 -0
  106. data/docs/rails/troubleshooting.md +18 -0
  107. data/docs/release.md +59 -0
  108. data/docs/server/architecture.md +10 -0
  109. data/docs/server/authentication.md +10 -0
  110. data/docs/server/configuration.md +16 -0
  111. data/docs/server/connection-pooling.md +10 -0
  112. data/docs/server/deployment.md +10 -0
  113. data/docs/server/protocol.md +12 -0
  114. data/docs/sql/compatibility-guide.md +82 -0
  115. data/docs/sql/compatibility.md +39 -0
  116. data/docs/sql/data-types.md +10 -0
  117. data/docs/sql/functions.md +9 -0
  118. data/docs/sql/joins.md +9 -0
  119. data/docs/sql/operators.md +9 -0
  120. data/docs/sql/sqlite-compatibility.md +21 -0
  121. data/docs/sql/syntax.md +10 -0
  122. data/docs/sql/transactions.md +10 -0
  123. data/docs/troubleshooting.md +244 -0
  124. data/exe/rubydb +23 -0
  125. data/lib/rubydb/backup/archive.rb +334 -0
  126. data/lib/rubydb/backup/backup.rb +401 -0
  127. data/lib/rubydb/backup/incremental.rb +353 -0
  128. data/lib/rubydb/backup/restore.rb +290 -0
  129. data/lib/rubydb/backup/snapshot.rb +267 -0
  130. data/lib/rubydb/backup/verification.rb +279 -0
  131. data/lib/rubydb/branching/branch.rb +181 -0
  132. data/lib/rubydb/branching/branch_manager.rb +311 -0
  133. data/lib/rubydb/branching/branch_metadata.rb +140 -0
  134. data/lib/rubydb/branching/checkout.rb +166 -0
  135. data/lib/rubydb/branching/copy_on_write.rb +272 -0
  136. data/lib/rubydb/branching/diff.rb +138 -0
  137. data/lib/rubydb/branching/merge.rb +285 -0
  138. data/lib/rubydb/build_info.rb +15 -0
  139. data/lib/rubydb/catalog/catalog.rb +391 -0
  140. data/lib/rubydb/catalog/column.rb +112 -0
  141. data/lib/rubydb/catalog/constraint.rb +180 -0
  142. data/lib/rubydb/catalog/database.rb +184 -0
  143. data/lib/rubydb/catalog/index.rb +97 -0
  144. data/lib/rubydb/catalog/schema.rb +103 -0
  145. data/lib/rubydb/catalog/sequence.rb +90 -0
  146. data/lib/rubydb/catalog/system_catalog.rb +698 -0
  147. data/lib/rubydb/catalog/table.rb +178 -0
  148. data/lib/rubydb/catalog/trigger.rb +102 -0
  149. data/lib/rubydb/catalog/view.rb +66 -0
  150. data/lib/rubydb/cli/application.rb +163 -0
  151. data/lib/rubydb/cli/commands/backup.rb +81 -0
  152. data/lib/rubydb/cli/commands/branch.rb +72 -0
  153. data/lib/rubydb/cli/commands/checkout.rb +54 -0
  154. data/lib/rubydb/cli/commands/create.rb +58 -0
  155. data/lib/rubydb/cli/commands/diff.rb +77 -0
  156. data/lib/rubydb/cli/commands/doctor.rb +74 -0
  157. data/lib/rubydb/cli/commands/drop.rb +57 -0
  158. data/lib/rubydb/cli/commands/init.rb +102 -0
  159. data/lib/rubydb/cli/commands/inspect.rb +95 -0
  160. data/lib/rubydb/cli/commands/merge.rb +63 -0
  161. data/lib/rubydb/cli/commands/migrate.rb +62 -0
  162. data/lib/rubydb/cli/commands/restart.rb +39 -0
  163. data/lib/rubydb/cli/commands/restore.rb +121 -0
  164. data/lib/rubydb/cli/commands/shell.rb +365 -0
  165. data/lib/rubydb/cli/commands/snapshot.rb +79 -0
  166. data/lib/rubydb/cli/commands/start.rb +82 -0
  167. data/lib/rubydb/cli/commands/status.rb +92 -0
  168. data/lib/rubydb/cli/commands/stop.rb +47 -0
  169. data/lib/rubydb/cli/commands/vacuum.rb +58 -0
  170. data/lib/rubydb/cli/formatter.rb +221 -0
  171. data/lib/rubydb/cli/output.rb +168 -0
  172. data/lib/rubydb/client/client.rb +304 -0
  173. data/lib/rubydb/client/connection.rb +415 -0
  174. data/lib/rubydb/client/connection_pool.rb +168 -0
  175. data/lib/rubydb/client/connection_url.rb +96 -0
  176. data/lib/rubydb/client/prepared_statement.rb +60 -0
  177. data/lib/rubydb/client/result.rb +123 -0
  178. data/lib/rubydb/client/statement.rb +52 -0
  179. data/lib/rubydb/client/transaction.rb +130 -0
  180. data/lib/rubydb/concurrency/concurrency.rb +19 -0
  181. data/lib/rubydb/concurrency/deadlock_detector.rb +150 -0
  182. data/lib/rubydb/concurrency/latch.rb +101 -0
  183. data/lib/rubydb/concurrency/lock_graph.rb +165 -0
  184. data/lib/rubydb/concurrency/mutex.rb +183 -0
  185. data/lib/rubydb/concurrency/rw_lock.rb +180 -0
  186. data/lib/rubydb/concurrency/scheduler.rb +250 -0
  187. data/lib/rubydb/concurrency/worker_pool.rb +143 -0
  188. data/lib/rubydb/configuration/config.rb +170 -0
  189. data/lib/rubydb/configuration/defaults.rb +179 -0
  190. data/lib/rubydb/configuration/environment.rb +152 -0
  191. data/lib/rubydb/configuration/parser.rb +185 -0
  192. data/lib/rubydb/configuration/validation.rb +221 -0
  193. data/lib/rubydb/constants.rb +74 -0
  194. data/lib/rubydb/constraints/check.rb +181 -0
  195. data/lib/rubydb/constraints/constraint.rb +101 -0
  196. data/lib/rubydb/constraints/foreign_key.rb +130 -0
  197. data/lib/rubydb/constraints/not_null.rb +64 -0
  198. data/lib/rubydb/constraints/primary_key.rb +99 -0
  199. data/lib/rubydb/constraints/unique.rb +108 -0
  200. data/lib/rubydb/constraints/validator.rb +350 -0
  201. data/lib/rubydb/errors/authentication_error.rb +10 -0
  202. data/lib/rubydb/errors/authorization_error.rb +23 -0
  203. data/lib/rubydb/errors/client_error.rb +10 -0
  204. data/lib/rubydb/errors/configuration_error.rb +10 -0
  205. data/lib/rubydb/errors/connection_error.rb +10 -0
  206. data/lib/rubydb/errors/constraint_error.rb +23 -0
  207. data/lib/rubydb/errors/corruption_error.rb +10 -0
  208. data/lib/rubydb/errors/database_error.rb +10 -0
  209. data/lib/rubydb/errors/error.rb +20 -0
  210. data/lib/rubydb/errors/execution_error.rb +10 -0
  211. data/lib/rubydb/errors/parser_error.rb +10 -0
  212. data/lib/rubydb/errors/recovery_error.rb +10 -0
  213. data/lib/rubydb/errors/replication_error.rb +10 -0
  214. data/lib/rubydb/errors/server_error.rb +6 -0
  215. data/lib/rubydb/errors/storage_error.rb +10 -0
  216. data/lib/rubydb/errors/transaction_error.rb +10 -0
  217. data/lib/rubydb/execution/aggregate_executor.rb +138 -0
  218. data/lib/rubydb/execution/delete_executor.rb +112 -0
  219. data/lib/rubydb/execution/distinct_executor.rb +135 -0
  220. data/lib/rubydb/execution/executor.rb +1192 -0
  221. data/lib/rubydb/execution/expression.rb +193 -0
  222. data/lib/rubydb/execution/index_scan.rb +142 -0
  223. data/lib/rubydb/execution/insert_executor.rb +217 -0
  224. data/lib/rubydb/execution/join_executor.rb +249 -0
  225. data/lib/rubydb/execution/limit_executor.rb +85 -0
  226. data/lib/rubydb/execution/optimizer.rb +215 -0
  227. data/lib/rubydb/execution/plan.rb +361 -0
  228. data/lib/rubydb/execution/planner.rb +546 -0
  229. data/lib/rubydb/execution/predicate.rb +235 -0
  230. data/lib/rubydb/execution/scan.rb +49 -0
  231. data/lib/rubydb/execution/sequential_scan.rb +63 -0
  232. data/lib/rubydb/execution/sort_executor.rb +185 -0
  233. data/lib/rubydb/execution/update_executor.rb +162 -0
  234. data/lib/rubydb/functions/aggregate.rb +70 -0
  235. data/lib/rubydb/functions/date_functions.rb +278 -0
  236. data/lib/rubydb/functions/function.rb +85 -0
  237. data/lib/rubydb/functions/json_functions.rb +215 -0
  238. data/lib/rubydb/functions/numeric_functions.rb +346 -0
  239. data/lib/rubydb/functions/scalar.rb +52 -0
  240. data/lib/rubydb/functions/string_functions.rb +383 -0
  241. data/lib/rubydb/functions/system_functions.rb +246 -0
  242. data/lib/rubydb/history/as_of.rb +238 -0
  243. data/lib/rubydb/history/change.rb +105 -0
  244. data/lib/rubydb/history/history.rb +131 -0
  245. data/lib/rubydb/history/history_manager.rb +229 -0
  246. data/lib/rubydb/history/temporal_query.rb +202 -0
  247. data/lib/rubydb/history/timeline.rb +144 -0
  248. data/lib/rubydb/indexes/btree.rb +186 -0
  249. data/lib/rubydb/indexes/btree_cursor.rb +258 -0
  250. data/lib/rubydb/indexes/btree_node.rb +385 -0
  251. data/lib/rubydb/indexes/hash_index.rb +150 -0
  252. data/lib/rubydb/indexes/index.rb +71 -0
  253. data/lib/rubydb/indexes/index_manager.rb +406 -0
  254. data/lib/rubydb/indexes/index_scan.rb +470 -0
  255. data/lib/rubydb/migrations/migration.rb +254 -0
  256. data/lib/rubydb/migrations/migration_lock.rb +146 -0
  257. data/lib/rubydb/migrations/migration_manager.rb +176 -0
  258. data/lib/rubydb/migrations/migration_version.rb +71 -0
  259. data/lib/rubydb/migrations/schema_diff.rb +211 -0
  260. data/lib/rubydb/migrations/schema_version.rb +64 -0
  261. data/lib/rubydb/monitoring/events.rb +160 -0
  262. data/lib/rubydb/monitoring/health.rb +222 -0
  263. data/lib/rubydb/monitoring/logger.rb +193 -0
  264. data/lib/rubydb/monitoring/metrics.rb +359 -0
  265. data/lib/rubydb/monitoring/performance.rb +176 -0
  266. data/lib/rubydb/monitoring/statistics.rb +170 -0
  267. data/lib/rubydb/mvcc/garbage_collector.rb +199 -0
  268. data/lib/rubydb/mvcc/mvcc.rb +16 -0
  269. data/lib/rubydb/mvcc/snapshot.rb +147 -0
  270. data/lib/rubydb/mvcc/vacuum.rb +180 -0
  271. data/lib/rubydb/mvcc/version.rb +106 -0
  272. data/lib/rubydb/mvcc/version_store.rb +398 -0
  273. data/lib/rubydb/mvcc/visibility.rb +109 -0
  274. data/lib/rubydb/protocol/capabilities.rb +125 -0
  275. data/lib/rubydb/protocol/decoder.rb +145 -0
  276. data/lib/rubydb/protocol/encoder.rb +136 -0
  277. data/lib/rubydb/protocol/handshake.rb +305 -0
  278. data/lib/rubydb/protocol/message.rb +121 -0
  279. data/lib/rubydb/protocol/protocol.rb +277 -0
  280. data/lib/rubydb/protocol/version.rb +54 -0
  281. data/lib/rubydb/rails/adapter.rb +239 -0
  282. data/lib/rubydb/rails/connection.rb +314 -0
  283. data/lib/rubydb/rails/database_statements.rb +122 -0
  284. data/lib/rubydb/rails/migration.rb +131 -0
  285. data/lib/rubydb/rails/quoting.rb +109 -0
  286. data/lib/rubydb/rails/result.rb +120 -0
  287. data/lib/rubydb/rails/schema_statements.rb +339 -0
  288. data/lib/rubydb/rails/transaction.rb +105 -0
  289. data/lib/rubydb/rails/type.rb +126 -0
  290. data/lib/rubydb/recovery/checkpoint.rb +257 -0
  291. data/lib/rubydb/recovery/consistency.rb +467 -0
  292. data/lib/rubydb/recovery/corruption_detector.rb +5 -0
  293. data/lib/rubydb/recovery/crash_recovery.rb +387 -0
  294. data/lib/rubydb/recovery/recovery_manager.rb +206 -0
  295. data/lib/rubydb/recovery/redo.rb +237 -0
  296. data/lib/rubydb/recovery/undo.rb +206 -0
  297. data/lib/rubydb/replication/failover.rb +5 -0
  298. data/lib/rubydb/replication/fencing.rb +63 -0
  299. data/lib/rubydb/replication/primary.rb +450 -0
  300. data/lib/rubydb/replication/replica.rb +384 -0
  301. data/lib/rubydb/replication/replication_log.rb +200 -0
  302. data/lib/rubydb/replication/replication_manager.rb +308 -0
  303. data/lib/rubydb/replication/replication_slot.rb +295 -0
  304. data/lib/rubydb/replication/replication_stream.rb +201 -0
  305. data/lib/rubydb/rubydb.rb +560 -0
  306. data/lib/rubydb/security/access_control.rb +254 -0
  307. data/lib/rubydb/security/audit_log.rb +213 -0
  308. data/lib/rubydb/security/authentication.rb +302 -0
  309. data/lib/rubydb/security/authorization.rb +282 -0
  310. data/lib/rubydb/security/credentials.rb +196 -0
  311. data/lib/rubydb/security/password.rb +215 -0
  312. data/lib/rubydb/security/permissions.rb +74 -0
  313. data/lib/rubydb/security/role.rb +101 -0
  314. data/lib/rubydb/security/user.rb +86 -0
  315. data/lib/rubydb/server/connection.rb +366 -0
  316. data/lib/rubydb/server/connection_pool.rb +193 -0
  317. data/lib/rubydb/server/lifecycle.rb +228 -0
  318. data/lib/rubydb/server/listener.rb +136 -0
  319. data/lib/rubydb/server/request_handler.rb +276 -0
  320. data/lib/rubydb/server/server.rb +364 -0
  321. data/lib/rubydb/server/session.rb +369 -0
  322. data/lib/rubydb/server/worker.rb +210 -0
  323. data/lib/rubydb/server/worker_pool.rb +168 -0
  324. data/lib/rubydb/sql/ast/alter_table.rb +169 -0
  325. data/lib/rubydb/sql/ast/begin_transaction.rb +47 -0
  326. data/lib/rubydb/sql/ast/commit.rb +37 -0
  327. data/lib/rubydb/sql/ast/constraint.rb +83 -0
  328. data/lib/rubydb/sql/ast/create_database.rb +41 -0
  329. data/lib/rubydb/sql/ast/create_index.rb +61 -0
  330. data/lib/rubydb/sql/ast/create_schema.rb +52 -0
  331. data/lib/rubydb/sql/ast/create_table.rb +187 -0
  332. data/lib/rubydb/sql/ast/delete.rb +54 -0
  333. data/lib/rubydb/sql/ast/drop_database.rb +41 -0
  334. data/lib/rubydb/sql/ast/drop_index.rb +41 -0
  335. data/lib/rubydb/sql/ast/drop_schema.rb +49 -0
  336. data/lib/rubydb/sql/ast/drop_table.rb +49 -0
  337. data/lib/rubydb/sql/ast/explain.rb +64 -0
  338. data/lib/rubydb/sql/ast/expression.rb +604 -0
  339. data/lib/rubydb/sql/ast/insert.rb +82 -0
  340. data/lib/rubydb/sql/ast/node.rb +42 -0
  341. data/lib/rubydb/sql/ast/rollback.rb +63 -0
  342. data/lib/rubydb/sql/ast/savepoint.rb +59 -0
  343. data/lib/rubydb/sql/ast/select.rb +88 -0
  344. data/lib/rubydb/sql/ast/set_operation.rb +20 -0
  345. data/lib/rubydb/sql/ast/trigger.rb +29 -0
  346. data/lib/rubydb/sql/ast/update.rb +88 -0
  347. data/lib/rubydb/sql/ast/vacuum.rb +19 -0
  348. data/lib/rubydb/sql/ast/view.rb +32 -0
  349. data/lib/rubydb/sql/ast/with.rb +32 -0
  350. data/lib/rubydb/sql/grammar.rb +86 -0
  351. data/lib/rubydb/sql/keywords.rb +156 -0
  352. data/lib/rubydb/sql/lexer.rb +214 -0
  353. data/lib/rubydb/sql/operators.rb +100 -0
  354. data/lib/rubydb/sql/parser.rb +1185 -0
  355. data/lib/rubydb/sql/planner/analyzer.rb +302 -0
  356. data/lib/rubydb/sql/planner/binder.rb +550 -0
  357. data/lib/rubydb/sql/planner/type_checker.rb +431 -0
  358. data/lib/rubydb/sql/token.rb +210 -0
  359. data/lib/rubydb/storage/buffer_frame.rb +44 -0
  360. data/lib/rubydb/storage/buffer_pool.rb +155 -0
  361. data/lib/rubydb/storage/database_lock.rb +74 -0
  362. data/lib/rubydb/storage/deserializer.rb +342 -0
  363. data/lib/rubydb/storage/engine.rb +2338 -0
  364. data/lib/rubydb/storage/file_manager.rb +187 -0
  365. data/lib/rubydb/storage/free_space_map.rb +81 -0
  366. data/lib/rubydb/storage/page.rb +94 -0
  367. data/lib/rubydb/storage/page_allocator.rb +855 -0
  368. data/lib/rubydb/storage/page_header.rb +67 -0
  369. data/lib/rubydb/storage/page_manager.rb +131 -0
  370. data/lib/rubydb/storage/record.rb +58 -0
  371. data/lib/rubydb/storage/row.rb +78 -0
  372. data/lib/rubydb/storage/serializer.rb +51 -0
  373. data/lib/rubydb/storage/storage_layout.rb +151 -0
  374. data/lib/rubydb/storage/storage_manager.rb +114 -0
  375. data/lib/rubydb/storage/tuple.rb +461 -0
  376. data/lib/rubydb/storage/visibility_map.rb +984 -0
  377. data/lib/rubydb/transactions/commit_manager.rb +220 -0
  378. data/lib/rubydb/transactions/isolation.rb +98 -0
  379. data/lib/rubydb/transactions/lock.rb +76 -0
  380. data/lib/rubydb/transactions/lock_manager.rb +362 -0
  381. data/lib/rubydb/transactions/savepoint.rb +143 -0
  382. data/lib/rubydb/transactions/transaction.rb +215 -0
  383. data/lib/rubydb/transactions/transaction_id.rb +84 -0
  384. data/lib/rubydb/transactions/transaction_log.rb +257 -0
  385. data/lib/rubydb/transactions/transaction_manager.rb +435 -0
  386. data/lib/rubydb/types/bigint.rb +36 -0
  387. data/lib/rubydb/types/blob.rb +37 -0
  388. data/lib/rubydb/types/boolean.rb +34 -0
  389. data/lib/rubydb/types/date.rb +39 -0
  390. data/lib/rubydb/types/decimal.rb +48 -0
  391. data/lib/rubydb/types/float.rb +34 -0
  392. data/lib/rubydb/types/integer.rb +36 -0
  393. data/lib/rubydb/types/json.rb +41 -0
  394. data/lib/rubydb/types/null.rb +34 -0
  395. data/lib/rubydb/types/smallint.rb +36 -0
  396. data/lib/rubydb/types/text.rb +37 -0
  397. data/lib/rubydb/types/time.rb +46 -0
  398. data/lib/rubydb/types/timestamp.rb +39 -0
  399. data/lib/rubydb/types/type.rb +119 -0
  400. data/lib/rubydb/types/uuid.rb +47 -0
  401. data/lib/rubydb/types/varchar.rb +37 -0
  402. data/lib/rubydb/version.rb +33 -0
  403. data/lib/rubydb/wal/archive.rb +193 -0
  404. data/lib/rubydb/wal/checkpoint.rb +183 -0
  405. data/lib/rubydb/wal/lsn.rb +94 -0
  406. data/lib/rubydb/wal/reader.rb +260 -0
  407. data/lib/rubydb/wal/record.rb +105 -0
  408. data/lib/rubydb/wal/segment.rb +193 -0
  409. data/lib/rubydb/wal/wal.rb +452 -0
  410. data/lib/rubydb/wal/writer.rb +236 -0
  411. data/lib/rubydb.rb +7 -0
  412. data/packaging/docker/Dockerfile +36 -0
  413. data/packaging/docker/docker-compose.failover.yml +43 -0
  414. data/packaging/docker/entrypoint.sh +15 -0
  415. data/packaging/homebrew/rubydb.rb +19 -0
  416. data/packaging/systemd/rubydb.service +22 -0
  417. data/rubydb.gemspec +57 -0
  418. data/scripts/benchmark +7 -0
  419. data/scripts/durability_drill +37 -0
  420. data/scripts/format +0 -0
  421. data/scripts/fuzz +63 -0
  422. data/scripts/lint +0 -0
  423. data/scripts/release +50 -0
  424. data/scripts/release_check +43 -0
  425. data/scripts/replication_failover_drill +250 -0
  426. data/scripts/replication_network_failover_drill +255 -0
  427. data/scripts/restore_drill +45 -0
  428. data/scripts/security +0 -0
  429. data/scripts/setup +0 -0
  430. data/scripts/test +0 -0
  431. data/scripts/test-chaos +0 -0
  432. data/scripts/test-crash +0 -0
  433. data/scripts/test-integration +0 -0
  434. data/scripts/test-unit +0 -0
  435. data/visibility_map.json +1 -0
  436. metadata +538 -0
@@ -0,0 +1,112 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RubyDB
4
+ module Catalog
5
+ # Column - represents a table column
6
+ class Column
7
+ attr_reader :name, :type, :options
8
+ attr_accessor :default, :nullable, :position
9
+
10
+ def initialize(name, type, **options)
11
+ @name = name
12
+ @type = type
13
+ @options = options
14
+ @default = options[:default]
15
+ @nullable = options.fetch(:null, true)
16
+ @position = options[:position]
17
+ @primary_key = options[:primary_key] || false
18
+ @unique = options[:unique] || false
19
+ @precision = options[:precision]
20
+ @scale = options[:scale]
21
+ @limit = options[:limit]
22
+ @created_at = Time.now
23
+ @modified_at = Time.now
24
+ end
25
+
26
+ def primary_key?
27
+ @primary_key
28
+ end
29
+
30
+ def unique?
31
+ @unique
32
+ end
33
+
34
+ def nullable?
35
+ @nullable
36
+ end
37
+
38
+ def has_default?
39
+ !@default.nil?
40
+ end
41
+
42
+ def type_class
43
+ case @type
44
+ when Symbol
45
+ @type
46
+ when Hash
47
+ @type[:type]
48
+ else
49
+ @type
50
+ end
51
+ end
52
+
53
+ def type_params
54
+ case @type
55
+ when Hash
56
+ @type.reject { |k| k == :type }
57
+ else
58
+ {}
59
+ end
60
+ end
61
+
62
+ def to_s
63
+ "#{@name} #{@type.to_s.upcase}"
64
+ end
65
+
66
+ def inspect
67
+ "#<Column name=#{@name} type=#{@type} primary_key=#{@primary_key} nullable=#{@nullable}>"
68
+ end
69
+
70
+ # --- Serialization ---
71
+
72
+ def serialize
73
+ {
74
+ name: @name,
75
+ type: @type,
76
+ default: @default,
77
+ nullable: @nullable,
78
+ position: @position,
79
+ primary_key: @primary_key,
80
+ unique: @unique,
81
+ precision: @precision,
82
+ scale: @scale,
83
+ limit: @limit,
84
+ created_at: @created_at.iso8601,
85
+ modified_at: @modified_at.iso8601
86
+ }
87
+ end
88
+
89
+ def self.deserialize(data)
90
+ column = new(
91
+ data[:name],
92
+ data[:type],
93
+ default: data[:default],
94
+ null: data[:nullable],
95
+ position: data[:position],
96
+ primary_key: data[:primary_key] || false,
97
+ unique: data[:unique] || false,
98
+ precision: data[:precision],
99
+ scale: data[:scale],
100
+ limit: data[:limit]
101
+ )
102
+ column.send(:created_at=, Time.parse(data[:created_at])) if data[:created_at]
103
+ column.send(:modified_at=, Time.parse(data[:modified_at])) if data[:modified_at]
104
+ column
105
+ end
106
+
107
+ protected
108
+
109
+ attr_writer :created_at, :modified_at
110
+ end
111
+ end
112
+ end
@@ -0,0 +1,180 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RubyDB
4
+ module Catalog
5
+ # Base constraint class
6
+ class Constraint
7
+ attr_reader :name, :type
8
+
9
+ def initialize(name, type)
10
+ @name = name
11
+ @type = type
12
+ @created_at = Time.now
13
+ end
14
+
15
+ def to_s
16
+ "#{@type} CONSTRAINT #{@name}"
17
+ end
18
+
19
+ def serialize
20
+ {
21
+ name: @name,
22
+ type: @type,
23
+ created_at: @created_at.iso8601
24
+ }
25
+ end
26
+
27
+ def self.deserialize(data)
28
+ case data[:type]
29
+ when "PRIMARY_KEY"
30
+ PrimaryKeyConstraint.deserialize(data)
31
+ when "FOREIGN_KEY"
32
+ ForeignKeyConstraint.deserialize(data)
33
+ when "UNIQUE"
34
+ UniqueConstraint.deserialize(data)
35
+ when "NOT_NULL"
36
+ NotNullConstraint.deserialize(data)
37
+ when "CHECK"
38
+ CheckConstraint.deserialize(data)
39
+ else
40
+ new(data[:name], data[:type])
41
+ end
42
+ end
43
+
44
+ protected
45
+
46
+ attr_writer :created_at
47
+ end
48
+
49
+ # PRIMARY KEY constraint
50
+ class PrimaryKeyConstraint < Constraint
51
+ attr_reader :columns
52
+
53
+ def initialize(name, columns)
54
+ super(name, "PRIMARY_KEY")
55
+ @columns = columns.is_a?(Array) ? columns : [columns]
56
+ end
57
+
58
+ def to_s
59
+ "PRIMARY KEY (#{@columns.join(", ")})"
60
+ end
61
+
62
+ def serialize
63
+ super.merge(columns: @columns)
64
+ end
65
+
66
+ def self.deserialize(data)
67
+ new(data[:name], data[:columns])
68
+ end
69
+ end
70
+
71
+ # FOREIGN KEY constraint
72
+ class ForeignKeyConstraint < Constraint
73
+ attr_reader :columns, :reference_table, :reference_columns
74
+ attr_reader :on_delete, :on_update
75
+
76
+ def initialize(name, columns, reference_table, reference_columns: [:id], on_delete: nil, on_update: nil)
77
+ super(name, "FOREIGN_KEY")
78
+ @columns = columns.is_a?(Array) ? columns : [columns]
79
+ @reference_table = reference_table
80
+ @reference_columns = reference_columns.is_a?(Array) ? reference_columns : [reference_columns]
81
+ @on_delete = on_delete
82
+ @on_update = on_update
83
+ end
84
+
85
+ def to_s
86
+ sql = "FOREIGN KEY (#{@columns.join(", ")}) REFERENCES #{@reference_table}(#{@reference_columns.join(", ")})"
87
+ sql << " ON DELETE #{@on_delete}" if @on_delete
88
+ sql << " ON UPDATE #{@on_update}" if @on_update
89
+ sql
90
+ end
91
+
92
+ def serialize
93
+ super.merge(
94
+ columns: @columns,
95
+ reference_table: @reference_table,
96
+ reference_columns: @reference_columns,
97
+ on_delete: @on_delete,
98
+ on_update: @on_update
99
+ )
100
+ end
101
+
102
+ def self.deserialize(data)
103
+ new(
104
+ data[:name],
105
+ data[:columns],
106
+ data[:reference_table],
107
+ reference_columns: data[:reference_columns] || [:id],
108
+ on_delete: data[:on_delete],
109
+ on_update: data[:on_update]
110
+ )
111
+ end
112
+ end
113
+
114
+ # UNIQUE constraint
115
+ class UniqueConstraint < Constraint
116
+ attr_reader :columns
117
+
118
+ def initialize(name, columns)
119
+ super(name, "UNIQUE")
120
+ @columns = columns.is_a?(Array) ? columns : [columns]
121
+ end
122
+
123
+ def to_s
124
+ "UNIQUE (#{@columns.join(", ")})"
125
+ end
126
+
127
+ def serialize
128
+ super.merge(columns: @columns)
129
+ end
130
+
131
+ def self.deserialize(data)
132
+ new(data[:name], data[:columns])
133
+ end
134
+ end
135
+
136
+ # NOT NULL constraint
137
+ class NotNullConstraint < Constraint
138
+ attr_reader :column
139
+
140
+ def initialize(name, column)
141
+ super(name, "NOT_NULL")
142
+ @column = column
143
+ end
144
+
145
+ def to_s
146
+ "#{@column} NOT NULL"
147
+ end
148
+
149
+ def serialize
150
+ super.merge(column: @column)
151
+ end
152
+
153
+ def self.deserialize(data)
154
+ new(data[:name], data[:column])
155
+ end
156
+ end
157
+
158
+ # CHECK constraint
159
+ class CheckConstraint < Constraint
160
+ attr_reader :expression
161
+
162
+ def initialize(name, expression)
163
+ super(name, "CHECK")
164
+ @expression = expression
165
+ end
166
+
167
+ def to_s
168
+ "CHECK (#{@expression})"
169
+ end
170
+
171
+ def serialize
172
+ super.merge(expression: @expression.to_s)
173
+ end
174
+
175
+ def self.deserialize(data)
176
+ new(data[:name], data[:expression])
177
+ end
178
+ end
179
+ end
180
+ end
@@ -0,0 +1,184 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RubyDB
4
+ module Catalog
5
+ # Database - contains schemas, tables, sequences, views, triggers
6
+ class Database
7
+ attr_reader :name, :tables, :schemas, :sequences, :views, :triggers, :created_at, :modified_at
8
+
9
+ def initialize(name)
10
+ @name = name
11
+ @tables = {}
12
+ @schemas = { "public" => PublicSchema.new }
13
+ @sequences = {}
14
+ @views = {}
15
+ @triggers = {}
16
+ @created_at = Time.now
17
+ @modified_at = Time.now
18
+ @options = {}
19
+ end
20
+
21
+ # --- Table Methods ---
22
+
23
+ def add_table(table)
24
+ @tables[table.name] = table
25
+ @modified_at = Time.now
26
+ table
27
+ end
28
+
29
+ def drop_table(name)
30
+ table = @tables.delete(name)
31
+ @modified_at = Time.now
32
+ table
33
+ end
34
+
35
+ def find_table(name)
36
+ @tables[name]
37
+ end
38
+
39
+ def table_exists?(name)
40
+ @tables.key?(name)
41
+ end
42
+
43
+ def tables
44
+ @tables.values
45
+ end
46
+
47
+ def create_schema(name, if_not_exists: false, authorization: nil)
48
+ if @schemas.key?(name)
49
+ return if if_not_exists
50
+ raise DatabaseError, "Schema '#{name}' already exists"
51
+ end
52
+ @schemas[name] = Schema.new(name, owner: authorization)
53
+ end
54
+
55
+ def drop_schema(name, if_exists: false, cascade: false)
56
+ unless @schemas.key?(name)
57
+ return if if_exists
58
+ raise DatabaseError, "Schema '#{name}' does not exist"
59
+ end
60
+ schema = @schemas[name]
61
+ if !cascade && schema.tables.any?
62
+ raise DatabaseError, "Schema '#{name}' is not empty"
63
+ end
64
+ @schemas.delete(name)
65
+ end
66
+
67
+ def find_schema(name)
68
+ @schemas[name]
69
+ end
70
+
71
+ # --- Sequence Methods ---
72
+
73
+ def add_sequence(sequence)
74
+ @sequences[sequence.name] = sequence
75
+ @modified_at = Time.now
76
+ sequence
77
+ end
78
+
79
+ def drop_sequence(name)
80
+ sequence = @sequences.delete(name)
81
+ @modified_at = Time.now
82
+ sequence
83
+ end
84
+
85
+ def find_sequence(name)
86
+ @sequences[name]
87
+ end
88
+
89
+ def sequence_exists?(name)
90
+ @sequences.key?(name)
91
+ end
92
+
93
+ # --- View Methods ---
94
+
95
+ def add_view(view)
96
+ @views[view.name] = view
97
+ @modified_at = Time.now
98
+ view
99
+ end
100
+
101
+ def drop_view(name)
102
+ view = @views.delete(name)
103
+ @modified_at = Time.now
104
+ view
105
+ end
106
+
107
+ def find_view(name)
108
+ @views[name]
109
+ end
110
+
111
+ def view_exists?(name)
112
+ @views.key?(name)
113
+ end
114
+
115
+ # --- Trigger Methods ---
116
+
117
+ def add_trigger(trigger)
118
+ @triggers[trigger.name] = trigger
119
+ @modified_at = Time.now
120
+ trigger
121
+ end
122
+
123
+ def drop_trigger(name)
124
+ trigger = @triggers.delete(name)
125
+ @modified_at = Time.now
126
+ trigger
127
+ end
128
+
129
+ def find_trigger(name)
130
+ @triggers[name]
131
+ end
132
+
133
+ def trigger_exists?(name)
134
+ @triggers.key?(name)
135
+ end
136
+
137
+ # --- Serialization ---
138
+
139
+ def serialize
140
+ {
141
+ name: @name,
142
+ created_at: @created_at.iso8601,
143
+ modified_at: @modified_at.iso8601,
144
+ tables: @tables.transform_values(&:serialize),
145
+ schemas: @schemas.transform_values(&:serialize),
146
+ sequences: @sequences.transform_values(&:serialize),
147
+ views: @views.transform_values(&:serialize),
148
+ triggers: @triggers.transform_values(&:serialize),
149
+ options: @options
150
+ }
151
+ end
152
+
153
+ def self.deserialize(data)
154
+ db = new(data[:name])
155
+ data[:schemas]&.each { |name, schema_data| db.schemas[name.to_s] = Schema.deserialize(schema_data) }
156
+ db.send(:created_at=, Time.parse(data[:created_at])) if data[:created_at]
157
+ db.send(:modified_at=, Time.parse(data[:modified_at])) if data[:modified_at]
158
+
159
+ data[:tables]&.each do |name, table_data|
160
+ db.instance_variable_get(:@tables)[name.to_s] = Table.deserialize(table_data)
161
+ end
162
+
163
+ data[:sequences]&.each do |name, seq_data|
164
+ db.sequences[name.to_s] = Sequence.deserialize(seq_data)
165
+ end
166
+
167
+ data[:views]&.each do |name, view_data|
168
+ db.views[name.to_s] = View.deserialize(view_data)
169
+ end
170
+
171
+ data[:triggers]&.each do |name, trigger_data|
172
+ db.triggers[name.to_s] = Trigger.deserialize(trigger_data)
173
+ end
174
+
175
+ db.send(:options=, data[:options]) if data[:options]
176
+ db
177
+ end
178
+
179
+ protected
180
+
181
+ attr_writer :created_at, :modified_at, :options
182
+ end
183
+ end
184
+ end
@@ -0,0 +1,97 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RubyDB
4
+ module Catalog
5
+ # Index - represents a database index
6
+ class Index
7
+ attr_reader :name, :table_name, :columns, :unique, :options
8
+ attr_accessor :size
9
+
10
+ def initialize(name, table_name, columns, unique: false, **options)
11
+ @name = name
12
+ @table_name = table_name
13
+ @columns = columns.is_a?(Array) ? columns : [columns]
14
+ @unique = unique
15
+ @options = options
16
+ @size = 0
17
+ @created_at = Time.now
18
+ @modified_at = Time.now
19
+ @type = options[:type] || :btree
20
+ @where = options[:where]
21
+ @include_columns = options[:include] || []
22
+ @fills = options[:fills] || []
23
+ end
24
+
25
+ def btree?
26
+ @type == :btree
27
+ end
28
+
29
+ def hash?
30
+ @type == :hash
31
+ end
32
+
33
+ def gin?
34
+ @type == :gin
35
+ end
36
+
37
+ def gist?
38
+ @type == :gist
39
+ end
40
+
41
+ def partial?
42
+ !@where.nil?
43
+ end
44
+
45
+ def covering?
46
+ @include_columns.any?
47
+ end
48
+
49
+ def to_s
50
+ "#{@name} ON #{@table_name}(#{@columns.join(", ")})"
51
+ end
52
+
53
+ def inspect
54
+ "#<Index name=#{@name} table=#{@table_name} columns=[#{@columns.join(", ")}] unique=#{@unique}>"
55
+ end
56
+
57
+ # --- Serialization ---
58
+
59
+ def serialize
60
+ {
61
+ name: @name,
62
+ table_name: @table_name,
63
+ columns: @columns,
64
+ unique: @unique,
65
+ type: @type,
66
+ where: @where,
67
+ include: @include_columns,
68
+ fills: @fills,
69
+ size: @size,
70
+ created_at: @created_at.iso8601,
71
+ modified_at: @modified_at.iso8601
72
+ }
73
+ end
74
+
75
+ def self.deserialize(data)
76
+ index = new(
77
+ data[:name],
78
+ data[:table_name],
79
+ data[:columns],
80
+ unique: data[:unique] || false,
81
+ type: data[:type] || :btree,
82
+ where: data[:where],
83
+ include: data[:include] || [],
84
+ fills: data[:fills] || []
85
+ )
86
+ index.size = data[:size] if data[:size]
87
+ index.send(:created_at=, Time.parse(data[:created_at])) if data[:created_at]
88
+ index.send(:modified_at=, Time.parse(data[:modified_at])) if data[:modified_at]
89
+ index
90
+ end
91
+
92
+ protected
93
+
94
+ attr_writer :created_at, :modified_at
95
+ end
96
+ end
97
+ end
@@ -0,0 +1,103 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RubyDB
4
+ module Catalog
5
+ # Schema - contains tables, views, etc. (PostgreSQL-style schema)
6
+ class Schema
7
+ attr_reader :name, :tables, :views, :sequences, :owner
8
+
9
+ def initialize(name, owner: nil)
10
+ @name = name
11
+ @owner = owner
12
+ @tables = {}
13
+ @views = {}
14
+ @sequences = {}
15
+ @created_at = Time.now
16
+ end
17
+
18
+ def add_table(table)
19
+ @tables[table.name] = table
20
+ table
21
+ end
22
+
23
+ def drop_table(name)
24
+ @tables.delete(name)
25
+ end
26
+
27
+ def find_table(name)
28
+ @tables[name]
29
+ end
30
+
31
+ def table_exists?(name)
32
+ @tables.key?(name)
33
+ end
34
+
35
+ def add_view(view)
36
+ @views[view.name] = view
37
+ view
38
+ end
39
+
40
+ def drop_view(name)
41
+ @views.delete(name)
42
+ end
43
+
44
+ def find_view(name)
45
+ @views[name]
46
+ end
47
+
48
+ def add_sequence(sequence)
49
+ @sequences[sequence.name] = sequence
50
+ sequence
51
+ end
52
+
53
+ def drop_sequence(name)
54
+ @sequences.delete(name)
55
+ end
56
+
57
+ def find_sequence(name)
58
+ @sequences[name]
59
+ end
60
+
61
+ def serialize
62
+ {
63
+ name: @name,
64
+ owner: @owner,
65
+ created_at: @created_at.iso8601,
66
+ tables: @tables.transform_values(&:serialize),
67
+ views: @views.transform_values(&:serialize),
68
+ sequences: @sequences.transform_values(&:serialize)
69
+ }
70
+ end
71
+
72
+ def self.deserialize(data)
73
+ schema = new(data[:name], owner: data[:owner])
74
+ schema.send(:created_at=, Time.parse(data[:created_at])) if data[:created_at]
75
+
76
+ data[:tables]&.each do |name, table_data|
77
+ schema.tables[name.to_s] = Table.deserialize(table_data)
78
+ end
79
+
80
+ data[:views]&.each do |name, view_data|
81
+ schema.views[name.to_s] = View.deserialize(view_data)
82
+ end
83
+
84
+ data[:sequences]&.each do |name, seq_data|
85
+ schema.sequences[name.to_s] = Sequence.deserialize(seq_data)
86
+ end
87
+
88
+ schema
89
+ end
90
+
91
+ protected
92
+
93
+ attr_writer :created_at
94
+ end
95
+
96
+ # Default schemas
97
+ class PublicSchema < Schema
98
+ def initialize
99
+ super("public")
100
+ end
101
+ end
102
+ end
103
+ end