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,170 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "singleton"
4
+
5
+ module RubyDB
6
+ module Configuration
7
+ # Config - Main configuration access point
8
+ class Config
9
+ include Singleton
10
+
11
+ attr_reader :environment, :parser, :validation
12
+
13
+ def initialize
14
+ @environment = Environment.new
15
+ @parser = Parser.new
16
+ @validation = Validation.new
17
+ @loaded = false
18
+ @config_path = nil
19
+ @config = {}
20
+ @lock = Mutex.new
21
+ end
22
+
23
+ def self.load(config_path = nil)
24
+ instance.load(config_path)
25
+ end
26
+
27
+ def self.get(path)
28
+ instance.get(path)
29
+ end
30
+
31
+ def self.set(path, value)
32
+ instance.set(path, value)
33
+ end
34
+
35
+ def self.[](key)
36
+ instance[key]
37
+ end
38
+
39
+ def self.[]=(key, value)
40
+ instance[key] = value
41
+ end
42
+
43
+ def self.to_hash
44
+ instance.to_hash
45
+ end
46
+
47
+ def self.valid?
48
+ instance.valid?
49
+ end
50
+
51
+ def self.errors
52
+ instance.errors
53
+ end
54
+
55
+ def self.warnings
56
+ instance.warnings
57
+ end
58
+
59
+ def self.environment
60
+ instance.environment.name
61
+ end
62
+
63
+ def self.environment=(env)
64
+ instance.environment = env
65
+ end
66
+
67
+ def load(config_path = nil)
68
+ @lock.synchronize do
69
+ @config_path = config_path
70
+ @config = @environment.load(config_path)
71
+ @loaded = true
72
+ @config
73
+ end
74
+ end
75
+
76
+ def reload
77
+ config_path = @lock.synchronize do
78
+ @loaded = false
79
+ @config_path
80
+ end
81
+ load(config_path)
82
+ end
83
+
84
+ def get(path)
85
+ ensure_loaded
86
+ @environment.get(path)
87
+ end
88
+
89
+ def set(path, value)
90
+ ensure_loaded
91
+ @environment.set(path, value)
92
+ end
93
+
94
+ def [](key)
95
+ ensure_loaded
96
+ @environment[key]
97
+ end
98
+
99
+ def []=(key, value)
100
+ ensure_loaded
101
+ @environment[key] = value
102
+ end
103
+
104
+ def to_hash
105
+ ensure_loaded
106
+ @environment.to_hash
107
+ end
108
+
109
+ def valid?
110
+ ensure_loaded
111
+ @environment.valid?
112
+ end
113
+
114
+ def errors
115
+ ensure_loaded
116
+ @environment.errors
117
+ end
118
+
119
+ def warnings
120
+ ensure_loaded
121
+ @environment.warnings
122
+ end
123
+
124
+ def environment=(env)
125
+ @lock.synchronize do
126
+ @environment = Environment.new(env)
127
+ @loaded = false
128
+ end
129
+ end
130
+
131
+ def environment
132
+ @environment.name
133
+ end
134
+
135
+ def production?
136
+ @environment.production?
137
+ end
138
+
139
+ def development?
140
+ @environment.development?
141
+ end
142
+
143
+ def test?
144
+ @environment.test?
145
+ end
146
+
147
+ def staging?
148
+ @environment.staging?
149
+ end
150
+
151
+ def stats
152
+ {
153
+ loaded: @loaded,
154
+ config_path: @config_path,
155
+ environment: environment,
156
+ config_keys: @config.keys.size,
157
+ errors: errors.size,
158
+ warnings: warnings.size,
159
+ valid: valid?
160
+ }
161
+ end
162
+
163
+ private
164
+
165
+ def ensure_loaded
166
+ load unless @loaded
167
+ end
168
+ end
169
+ end
170
+ end
@@ -0,0 +1,179 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RubyDB
4
+ module Configuration
5
+ # Defaults - Default configuration values
6
+ class Defaults
7
+ DEFAULTS = {
8
+ # Server settings
9
+ server: {
10
+ host: "localhost",
11
+ port: 7432,
12
+ max_connections: 100,
13
+ min_workers: 2,
14
+ max_workers: 20,
15
+ worker_queue_size: 1000,
16
+ read_timeout: 30,
17
+ write_timeout: 30,
18
+ idle_timeout: 300,
19
+ max_request_size: 10 * 1024 * 1024, # 10MB
20
+ daemonize: false,
21
+ pid_file: "rubydb.pid",
22
+ log_level: "info"
23
+ },
24
+
25
+ # Storage settings
26
+ storage: {
27
+ data_dir: "data",
28
+ page_size: 8192,
29
+ buffer_pool_size: 1000,
30
+ wal_enabled: true,
31
+ wal_dir: "wal",
32
+ wal_segment_size: 16 * 1024 * 1024, # 16MB
33
+ wal_keep_segments: 100,
34
+ fsync: true,
35
+ compress: false
36
+ },
37
+
38
+ # Database settings
39
+ database: {
40
+ name: "rubydb",
41
+ encoding: "UTF8",
42
+ locale: "en_US.UTF-8",
43
+ default_isolation_level: "read_committed",
44
+ max_connections: 100,
45
+ statement_timeout: 30,
46
+ idle_in_transaction_timeout: 60
47
+ },
48
+
49
+ # Authentication settings
50
+ auth: {
51
+ method: "password",
52
+ session_timeout: 3600,
53
+ max_attempts: 5,
54
+ lockout_duration: 900,
55
+ password_algorithm: "sha256",
56
+ password_iterations: 10000,
57
+ salt_length: 16
58
+ },
59
+
60
+ # SSL settings
61
+ ssl: {
62
+ enabled: false,
63
+ cert_file: nil,
64
+ key_file: nil,
65
+ ca_file: nil,
66
+ verify_peer: false
67
+ },
68
+
69
+ # Replication settings
70
+ replication: {
71
+ enabled: false,
72
+ role: "standalone",
73
+ primary_host: nil,
74
+ primary_port: 7433,
75
+ sync_mode: "async",
76
+ sync_replicas: 1,
77
+ replication_port: 7434,
78
+ max_replicas: 10
79
+ },
80
+
81
+ # Backup settings
82
+ backup: {
83
+ backup_dir: "backups",
84
+ retention_days: 30,
85
+ max_backups: 10,
86
+ verify_after_backup: true,
87
+ include_wal: true,
88
+ include_schema: true,
89
+ compress: true,
90
+ compression_level: 6
91
+ },
92
+
93
+ # Logging settings
94
+ logging: {
95
+ log_dir: "log",
96
+ log_file: "rubydb.log",
97
+ log_level: "info",
98
+ log_format: "json",
99
+ rotate_size: 10 * 1024 * 1024, # 10MB
100
+ rotate_count: 10,
101
+ audit_log: true,
102
+ slow_query_threshold: 1000 # ms
103
+ },
104
+
105
+ # Monitoring settings
106
+ monitoring: {
107
+ enabled: true,
108
+ metrics_interval: 10,
109
+ health_check_interval: 30,
110
+ stats_collector: true,
111
+ prometheus: false,
112
+ prometheus_port: 9090
113
+ },
114
+
115
+ # Development settings
116
+ development: {
117
+ auto_migrate: true,
118
+ seed_data: false,
119
+ debug: false,
120
+ profile: false,
121
+ fake_data: false
122
+ }
123
+ }
124
+
125
+ def self.all
126
+ DEFAULTS
127
+ end
128
+
129
+ def self.get(path)
130
+ parts = path.to_s.split(".")
131
+ value = DEFAULTS
132
+ parts.each do |part|
133
+ value = value[part.to_sym]
134
+ return nil if value.nil?
135
+ end
136
+ value
137
+ end
138
+
139
+ def self.set(path, value)
140
+ parts = path.to_s.split(".")
141
+ target = DEFAULTS
142
+ parts[0...-1].each do |part|
143
+ target = target[part.to_sym]
144
+ return false if target.nil?
145
+ end
146
+ target[parts.last.to_sym] = value
147
+ true
148
+ end
149
+
150
+ def self.merge(overrides)
151
+ deep_merge(DEFAULTS, overrides)
152
+ end
153
+
154
+ def self.deep_merge(hash1, hash2)
155
+ result = hash1.dup
156
+ hash2.each do |key, value|
157
+ if value.is_a?(Hash) && result[key].is_a?(Hash)
158
+ result[key] = deep_merge(result[key], value)
159
+ else
160
+ result[key] = value
161
+ end
162
+ end
163
+ result
164
+ end
165
+
166
+ def self.to_hash
167
+ DEFAULTS
168
+ end
169
+
170
+ def self.keys
171
+ DEFAULTS.keys
172
+ end
173
+
174
+ def self.has_key?(key)
175
+ DEFAULTS.key?(key)
176
+ end
177
+ end
178
+ end
179
+ end
@@ -0,0 +1,152 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RubyDB
4
+ module Configuration
5
+ # Environment - Manages environment-specific configuration
6
+ class Environment
7
+ attr_reader :name, :config, :defaults
8
+
9
+ ENVIRONMENTS = [:development, :test, :production, :staging]
10
+
11
+ def initialize(name = nil)
12
+ @name = name || ENV["RUBYDB_ENV"] || "development"
13
+ @name = @name.to_sym
14
+ @defaults = Defaults.all
15
+ @config = {}
16
+ @loaded = false
17
+ @parser = Parser.new
18
+ @validation = Validation.new
19
+ end
20
+
21
+ def load(config_path = nil)
22
+ @config = {}
23
+
24
+ # Load defaults
25
+ @config = deep_merge(@config, @defaults)
26
+
27
+ # Load base config
28
+ if config_path
29
+ base_config = @parser.parse_file(config_path)
30
+ @config = deep_merge(@config, base_config)
31
+ end
32
+
33
+ # Load environment-specific config
34
+ env_config_path = config_path ? "#{config_path}.#{@name}" : nil
35
+ if env_config_path && File.exist?(env_config_path)
36
+ env_config = @parser.parse_file(env_config_path)
37
+ @config = deep_merge(@config, env_config)
38
+ end
39
+
40
+ # Load environment variables
41
+ env_config = @parser.parse_env
42
+ @config = deep_merge(@config, env_config)
43
+
44
+ # Validate
45
+ @validation.validate(@config)
46
+
47
+ @loaded = true
48
+ @config
49
+ end
50
+
51
+ def reload
52
+ @loaded = false
53
+ load
54
+ end
55
+
56
+ def [](key)
57
+ ensure_loaded
58
+ get_value(@config, key.to_s)
59
+ end
60
+
61
+ def []=(key, value)
62
+ ensure_loaded
63
+ set_value(@config, key.to_s, value)
64
+ end
65
+
66
+ def get(path)
67
+ ensure_loaded
68
+ get_value(@config, path.to_s)
69
+ end
70
+
71
+ def set(path, value)
72
+ ensure_loaded
73
+ set_value(@config, path.to_s, value)
74
+ end
75
+
76
+ def to_hash
77
+ ensure_loaded
78
+ @config.dup
79
+ end
80
+
81
+ def valid?
82
+ ensure_loaded
83
+ @validation.valid?
84
+ end
85
+
86
+ def errors
87
+ ensure_loaded
88
+ @validation.errors
89
+ end
90
+
91
+ def warnings
92
+ ensure_loaded
93
+ @validation.warnings
94
+ end
95
+
96
+ def production?
97
+ @name == :production
98
+ end
99
+
100
+ def development?
101
+ @name == :development
102
+ end
103
+
104
+ def test?
105
+ @name == :test
106
+ end
107
+
108
+ def staging?
109
+ @name == :staging
110
+ end
111
+
112
+ private
113
+
114
+ def ensure_loaded
115
+ load unless @loaded
116
+ end
117
+
118
+ def get_value(hash, path)
119
+ parts = path.split(".")
120
+ value = hash
121
+ parts.each do |part|
122
+ return nil unless value.is_a?(Hash) && value.key?(part.to_sym)
123
+ value = value[part.to_sym]
124
+ end
125
+ value
126
+ end
127
+
128
+ def set_value(hash, path, value)
129
+ parts = path.split(".")
130
+ target = hash
131
+ parts[0...-1].each do |part|
132
+ part = part.to_sym
133
+ target[part] ||= {}
134
+ target = target[part]
135
+ end
136
+ target[parts.last.to_sym] = value
137
+ end
138
+
139
+ def deep_merge(hash1, hash2)
140
+ result = hash1.dup
141
+ hash2.each do |key, value|
142
+ if value.is_a?(Hash) && result[key].is_a?(Hash)
143
+ result[key] = deep_merge(result[key], value)
144
+ else
145
+ result[key] = value
146
+ end
147
+ end
148
+ result
149
+ end
150
+ end
151
+ end
152
+ end
@@ -0,0 +1,185 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "yaml"
4
+ require "json"
5
+ require "erb"
6
+
7
+ module RubyDB
8
+ module Configuration
9
+ # Parser - Parses configuration from various sources
10
+ class Parser
11
+ attr_reader :errors, :warnings
12
+
13
+ def initialize
14
+ @errors = []
15
+ @warnings = []
16
+ end
17
+
18
+ def parse_file(file_path)
19
+ return {} unless File.exist?(file_path)
20
+
21
+ content = File.read(file_path)
22
+ parse_string(content, file_path)
23
+ end
24
+
25
+ def parse_string(content, source = nil)
26
+ @errors = []
27
+ @warnings = []
28
+
29
+ # Process ERB if present
30
+ if content.include?("<%")
31
+ content = ERB.new(content).result
32
+ end
33
+
34
+ # Try YAML first
35
+ begin
36
+ config = YAML.safe_load(content, symbolize_names: true)
37
+ return config if config.is_a?(Hash)
38
+ rescue Psych::SyntaxError => e
39
+ @warnings << "YAML parsing failed, trying JSON: #{e.message}"
40
+ end
41
+
42
+ # Try JSON
43
+ begin
44
+ config = JSON.parse(content, symbolize_names: true)
45
+ return config if config.is_a?(Hash)
46
+ rescue JSON::ParserError => e
47
+ @errors << "Failed to parse configuration: #{e.message}"
48
+ end
49
+
50
+ {}
51
+ end
52
+
53
+ def parse_env(prefix = "RUBYDB_")
54
+ config = {}
55
+
56
+ ENV.each do |key, value|
57
+ next unless key.start_with?(prefix)
58
+
59
+ # Convert RUBYDB_SERVER_HOST to server.host
60
+ path = key[prefix.length..-1].downcase.split("_").join(".")
61
+ set_nested_value(config, path, parse_value(value))
62
+ end
63
+
64
+ config
65
+ end
66
+
67
+ def parse_args(args)
68
+ config = {}
69
+ i = 0
70
+
71
+ while i < args.length
72
+ arg = args[i]
73
+
74
+ if arg.start_with?("--")
75
+ key = arg[2..-1]
76
+ value = args[i + 1] if i + 1 < args.length
77
+
78
+ if value && !value.start_with?("--")
79
+ set_nested_value(config, key, parse_value(value))
80
+ i += 2
81
+ else
82
+ set_nested_value(config, key, true)
83
+ i += 1
84
+ end
85
+ elsif arg.start_with?("-")
86
+ key = arg[1..-1]
87
+ value = args[i + 1] if i + 1 < args.length
88
+
89
+ if value && !value.start_with?("-")
90
+ set_nested_value(config, key, parse_value(value))
91
+ i += 2
92
+ else
93
+ set_nested_value(config, key, true)
94
+ i += 1
95
+ end
96
+ else
97
+ i += 1
98
+ end
99
+ end
100
+
101
+ config
102
+ end
103
+
104
+ def parse_url(url)
105
+ config = {}
106
+
107
+ return config unless url =~ /^rubydb:\/\/([^@]+@)?([^:]+):([0-9]+)\/(.+)$/
108
+
109
+ user_pass = $1
110
+ host = $2
111
+ port = $3.to_i
112
+ database = $4
113
+
114
+ config[:server] ||= {}
115
+ config[:server][:host] = host
116
+ config[:server][:port] = port
117
+
118
+ config[:database] ||= {}
119
+ config[:database][:name] = database
120
+
121
+ if user_pass
122
+ user, pass = user_pass.chomp("@").split(":")
123
+ config[:auth] ||= {}
124
+ config[:auth][:username] = user
125
+ config[:auth][:password] = pass if pass
126
+ end
127
+
128
+ config
129
+ end
130
+
131
+ def merge_configs(*configs)
132
+ result = {}
133
+ configs.compact.each do |config|
134
+ result = deep_merge(result, config)
135
+ end
136
+ result
137
+ end
138
+
139
+ private
140
+
141
+ def parse_value(value)
142
+ return true if value == "true"
143
+ return false if value == "false"
144
+ return nil if value == "null" || value == "nil"
145
+
146
+ if value =~ /^\d+$/
147
+ return value.to_i
148
+ end
149
+
150
+ if value =~ /^\d+\.\d+$/
151
+ return value.to_f
152
+ end
153
+
154
+ value
155
+ end
156
+
157
+ def set_nested_value(hash, path, value)
158
+ keys = path.split(".")
159
+ target = hash
160
+
161
+ keys[0...-1].each do |key|
162
+ key = key.to_sym
163
+ target[key] ||= {}
164
+ target = target[key]
165
+ end
166
+
167
+ target[keys.last.to_sym] = value
168
+ end
169
+
170
+ def deep_merge(hash1, hash2)
171
+ result = hash1.dup
172
+
173
+ hash2.each do |key, value|
174
+ if value.is_a?(Hash) && result[key].is_a?(Hash)
175
+ result[key] = deep_merge(result[key], value)
176
+ else
177
+ result[key] = value
178
+ end
179
+ end
180
+
181
+ result
182
+ end
183
+ end
184
+ end
185
+ end