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,254 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "set"
4
+
5
+ module RubyDB
6
+ module Security
7
+ # AccessControl - Main access control system
8
+ class AccessControl
9
+ attr_reader :authentication, :authorization, :user_store
10
+ attr_reader :role_store, :stats
11
+
12
+ def initialize(config = {})
13
+ @config = config
14
+ @user_store = {}
15
+ @role_store = {}
16
+ @authentication = Authentication.new(config[:auth] || {})
17
+ @authorization = Authorization.new(config[:authz] || {})
18
+ @password_hasher = Password.new(config[:password] || {})
19
+ @audit_log = AuditLog.new(config[:audit] || {})
20
+ @stats = {
21
+ access_checks: 0,
22
+ granted: 0,
23
+ denied: 0,
24
+ user_operations: 0,
25
+ role_operations: 0
26
+ }
27
+ @lock = Mutex.new
28
+
29
+ # Create default admin user if none exists
30
+ create_default_users if config[:create_defaults] != false
31
+ end
32
+
33
+ def create_user(username, password, options = {})
34
+ @lock.synchronize do
35
+ @stats[:user_operations] += 1
36
+
37
+ if @user_store.key?(username)
38
+ raise SecurityError, "User '#{username}' already exists"
39
+ end
40
+
41
+ salt = @password_hasher.generate_salt
42
+ password_hash = @password_hasher.hash(password, salt)
43
+
44
+ user = User.new(username, {
45
+ password_hash: password_hash,
46
+ salt: salt,
47
+ email: options[:email],
48
+ full_name: options[:full_name],
49
+ superuser: options[:superuser] || false,
50
+ active: options[:active] != false,
51
+ expires_at: options[:expires_at],
52
+ metadata: options[:metadata]
53
+ })
54
+
55
+ @user_store[username] = user
56
+ @audit_log.log(:user_created, username: username)
57
+
58
+ user
59
+ end
60
+ end
61
+
62
+ def delete_user(username)
63
+ @lock.synchronize do
64
+ @stats[:user_operations] += 1
65
+
66
+ return false unless @user_store.key?(username)
67
+ @user_store.delete(username)
68
+ @audit_log.log(:user_deleted, username: username)
69
+
70
+ true
71
+ end
72
+ end
73
+
74
+ def authenticate(username, password)
75
+ @lock.synchronize do
76
+ result = @authentication.authenticate(
77
+ username: username,
78
+ password: password
79
+ )
80
+
81
+ @audit_log.log(
82
+ result[:success] ? :login_success : :login_failure,
83
+ username: username,
84
+ result: result
85
+ )
86
+
87
+ result
88
+ end
89
+ end
90
+
91
+ def check_permission(user, action, object, object_type = Authorization::OBJECT_TABLE)
92
+ @lock.synchronize do
93
+ @stats[:access_checks] += 1
94
+
95
+ result = @authorization.authorize(user, action, object, object_type)
96
+
97
+ @audit_log.log(
98
+ result ? :access_granted : :access_denied,
99
+ username: user.username,
100
+ action: action,
101
+ object: object,
102
+ result: result
103
+ )
104
+
105
+ if result
106
+ @stats[:granted] += 1
107
+ else
108
+ @stats[:denied] += 1
109
+ end
110
+
111
+ result
112
+ end
113
+ end
114
+
115
+ def create_role(name, options = {})
116
+ @lock.synchronize do
117
+ @stats[:role_operations] += 1
118
+
119
+ if @role_store.key?(name)
120
+ raise SecurityError, "Role '#{name}' already exists"
121
+ end
122
+
123
+ role = Role.new(name, options)
124
+ @role_store[name] = role
125
+ @authorization.add_role(name, options[:parent_role])
126
+
127
+ @audit_log.log(:role_created, role: name)
128
+
129
+ role
130
+ end
131
+ end
132
+
133
+ def delete_role(name)
134
+ @lock.synchronize do
135
+ @stats[:role_operations] += 1
136
+
137
+ return false unless @role_store.key?(name)
138
+ @role_store.delete(name)
139
+ @authorization.remove_role(name)
140
+
141
+ @audit_log.log(:role_deleted, role: name)
142
+
143
+ true
144
+ end
145
+ end
146
+
147
+ def assign_role(username, role_name)
148
+ @lock.synchronize do
149
+ @stats[:role_operations] += 1
150
+
151
+ user = @user_store[username]
152
+ raise SecurityError, "User '#{username}' not found" unless user
153
+
154
+ unless @role_store.key?(role_name)
155
+ raise SecurityError, "Role '#{role_name}' not found"
156
+ end
157
+
158
+ @authorization.assign_role(user, role_name)
159
+ @role_store[role_name].add_member(username)
160
+
161
+ @audit_log.log(:role_assigned, username: username, role: role_name)
162
+
163
+ true
164
+ end
165
+ end
166
+
167
+ def revoke_role(username, role_name)
168
+ @lock.synchronize do
169
+ @stats[:role_operations] += 1
170
+
171
+ user = @user_store[username]
172
+ return false unless user
173
+
174
+ @authorization.revoke_role(user, role_name)
175
+ @role_store[role_name]&.remove_member(username)
176
+
177
+ @audit_log.log(:role_revoked, username: username, role: role_name)
178
+
179
+ true
180
+ end
181
+ end
182
+
183
+ def grant_permission(permission, object, object_type, options = {})
184
+ @lock.synchronize do
185
+ @authorization.grant_permission(
186
+ options[:grantor],
187
+ permission,
188
+ object,
189
+ object_type,
190
+ options
191
+ )
192
+
193
+ @audit_log.log(:permission_granted, permission: permission, object: object)
194
+
195
+ true
196
+ end
197
+ end
198
+
199
+ def revoke_permission(permission, object, object_type, options = {})
200
+ @lock.synchronize do
201
+ @authorization.revoke_permission(
202
+ options[:grantor],
203
+ permission,
204
+ object,
205
+ object_type,
206
+ options
207
+ )
208
+
209
+ @audit_log.log(:permission_revoked, permission: permission, object: object)
210
+
211
+ true
212
+ end
213
+ end
214
+
215
+ def list_users
216
+ @user_store.keys
217
+ end
218
+
219
+ def list_roles
220
+ @role_store.keys
221
+ end
222
+
223
+ def get_user(username)
224
+ @user_store[username]
225
+ end
226
+
227
+ def get_role(name)
228
+ @role_store[name]
229
+ end
230
+
231
+ def stats
232
+ @lock.synchronize do
233
+ @stats.merge({
234
+ users: @user_store.size,
235
+ roles: @role_store.size,
236
+ authentication: @authentication.stats,
237
+ authorization: @authorization.stats,
238
+ audit_log: @audit_log.stats
239
+ })
240
+ end
241
+ end
242
+
243
+ private
244
+
245
+ def create_default_users
246
+ # Create admin user if none exist
247
+ if @user_store.empty?
248
+ admin_password = @config[:admin_password] || "admin"
249
+ create_user("admin", admin_password, superuser: true)
250
+ end
251
+ end
252
+ end
253
+ end
254
+ end
@@ -0,0 +1,213 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "json"
4
+ require "fileutils"
5
+ require "time"
6
+
7
+ module RubyDB
8
+ module Security
9
+ # AuditLog - Logs security events
10
+ class AuditLog
11
+ attr_reader :stats
12
+
13
+ # Event types
14
+ EVENT_LOGIN = :login
15
+ EVENT_LOGIN_SUCCESS = :login_success
16
+ EVENT_LOGIN_FAILURE = :login_failure
17
+ EVENT_LOGOUT = :logout
18
+ EVENT_USER_CREATED = :user_created
19
+ EVENT_USER_DELETED = :user_deleted
20
+ EVENT_USER_UPDATED = :user_updated
21
+ EVENT_ROLE_CREATED = :role_created
22
+ EVENT_ROLE_DELETED = :role_deleted
23
+ EVENT_ROLE_ASSIGNED = :role_assigned
24
+ EVENT_ROLE_REVOKED = :role_revoked
25
+ EVENT_PERMISSION_GRANTED = :permission_granted
26
+ EVENT_PERMISSION_REVOKED = :permission_revoked
27
+ EVENT_ACCESS_GRANTED = :access_granted
28
+ EVENT_ACCESS_DENIED = :access_denied
29
+ EVENT_QUERY_EXECUTED = :query_executed
30
+ EVENT_SCHEMA_CHANGE = :schema_change
31
+ EVENT_CONFIG_CHANGE = :config_change
32
+ EVENT_SYSTEM_ERROR = :system_error
33
+ EVENT_SECURITY_ALERT = :security_alert
34
+
35
+ def initialize(config = {})
36
+ @config = config
37
+ @log_path = config[:log_path] || "audit.log"
38
+ @batch_size = config[:batch_size] || 100
39
+ @buffer = []
40
+ @buffer_lock = Mutex.new
41
+ @stats = {
42
+ events_logged: 0,
43
+ events_buffered: 0,
44
+ events_flushed: 0,
45
+ errors: 0,
46
+ buffer_size: 0
47
+ }
48
+ @lock = Mutex.new
49
+
50
+ # Create log directory
51
+ FileUtils.mkdir_p(File.dirname(@log_path))
52
+
53
+ # Start flush thread if async
54
+ if config[:async] != false
55
+ start_flush_thread
56
+ end
57
+ end
58
+
59
+ def log(event_type, data = {})
60
+ @lock.synchronize do
61
+ entry = {
62
+ timestamp: Time.now.iso8601,
63
+ event: event_type,
64
+ data: data,
65
+ pid: Process.pid,
66
+ thread: Thread.current.object_id,
67
+ host: Socket.gethostname
68
+ }
69
+
70
+ @buffer << entry
71
+ @stats[:events_logged] += 1
72
+ @stats[:events_buffered] += 1
73
+ @stats[:buffer_size] = @buffer.size
74
+
75
+ flush if @buffer.size >= @batch_size
76
+
77
+ entry
78
+ end
79
+ end
80
+
81
+ def log_event(event_type, **data)
82
+ log(event_type, data)
83
+ end
84
+
85
+ def flush
86
+ @lock.synchronize do
87
+ return if @buffer.empty?
88
+
89
+ begin
90
+ File.open(@log_path, "a") do |file|
91
+ @buffer.each do |entry|
92
+ file.puts(JSON.generate(entry))
93
+ end
94
+ file.flush
95
+ end
96
+
97
+ @stats[:events_flushed] += @buffer.size
98
+ @stats[:events_buffered] = 0
99
+ @buffer.clear
100
+ @stats[:buffer_size] = 0
101
+
102
+ rescue => e
103
+ @stats[:errors] += 1
104
+ end
105
+ end
106
+ end
107
+
108
+ def query(conditions = {})
109
+ @lock.synchronize do
110
+ flush if @buffer.any?
111
+
112
+ entries = []
113
+ return entries unless File.exist?(@log_path)
114
+
115
+ File.open(@log_path, "r") do |file|
116
+ file.each_line do |line|
117
+ begin
118
+ entry = JSON.parse(line, symbolize_names: true)
119
+
120
+ # Apply filters
121
+ matched = true
122
+ conditions.each do |key, value|
123
+ if entry[key] != value
124
+ matched = false
125
+ break
126
+ end
127
+ end
128
+
129
+ entries << entry if matched
130
+
131
+ rescue JSON::ParserError
132
+ # Skip malformed lines
133
+ end
134
+ end
135
+ end
136
+
137
+ entries
138
+ end
139
+ end
140
+
141
+ def query_by_user(username, limit = 100)
142
+ query({ user: username }).last(limit)
143
+ end
144
+
145
+ def query_by_event(event_type, limit = 100)
146
+ query({ event: event_type }).last(limit)
147
+ end
148
+
149
+ def query_by_time(start_time, end_time, limit = 100)
150
+ entries = query({})
151
+ entries.select! do |entry|
152
+ time = Time.parse(entry[:timestamp])
153
+ time >= start_time && time <= end_time
154
+ end
155
+ entries.last(limit)
156
+ end
157
+
158
+ def clear
159
+ @lock.synchronize do
160
+ flush
161
+ File.truncate(@log_path, 0) if File.exist?(@log_path)
162
+ @stats[:events_logged] = 0
163
+ end
164
+ end
165
+
166
+ def rotate(max_files = 10)
167
+ @lock.synchronize do
168
+ flush
169
+
170
+ if File.size(@log_path) > @config[:max_size] || 10 * 1024 * 1024
171
+ timestamp = Time.now.strftime("%Y%m%d_%H%M%S")
172
+ archive_path = "#{@log_path}.#{timestamp}"
173
+
174
+ # Move current log to archive
175
+ FileUtils.mv(@log_path, archive_path)
176
+ FileUtils.touch(@log_path)
177
+
178
+ # Remove old archives
179
+ archives = Dir.glob("#{@log_path}.*").sort
180
+ while archives.size > max_files
181
+ File.delete(archives.shift)
182
+ end
183
+ end
184
+ end
185
+ end
186
+
187
+ def stats
188
+ @lock.synchronize do
189
+ @stats.merge({
190
+ log_path: @log_path,
191
+ buffer_size: @buffer.size,
192
+ async: @flush_thread ? true : false
193
+ })
194
+ end
195
+ end
196
+
197
+ private
198
+
199
+ def start_flush_thread
200
+ @flush_thread = Thread.new do
201
+ loop do
202
+ sleep(5)
203
+ begin
204
+ flush
205
+ rescue => e
206
+ # Log error but continue
207
+ end
208
+ end
209
+ end
210
+ end
211
+ end
212
+ end
213
+ end